saltstack adaptor reqExecLog API cleanup
[ccsdk/sli/adaptors.git] / saltstack-adapter / saltstack-adapter-provider / src / main / java / org / onap / ccsdk / sli / adaptors / saltstack / model / SaltstackMessageParser.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * =============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.ccsdk.sli.adaptors.saltstack.model;
26
27 /**
28  * This module implements the APP-C/Saltstack Server interface
29  * based on the REST API specifications
30  */
31
32 import com.google.common.base.Strings;
33 import org.codehaus.jettison.json.JSONException;
34 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
35 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import java.io.File;
40 import java.io.FileInputStream;
41 import java.io.FileNotFoundException;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.util.Map;
45 import java.util.Properties;
46 import java.util.UUID;
47
48 /**
49  * Class that validates and constructs requests sent/received from
50  * Saltstack Server
51  */
52 public class SaltstackMessageParser {
53
54     private static final String SS_AGENT_HOSTNAME_KEY = "HostName";
55     private static final String SS_AGENT_PORT_KEY = "Port";
56     private static final String PASS_KEY = "Password";
57     private static final String USER_KEY = "User";
58     private static final String CMD_EXEC = "cmd";
59     private static final String IS_SLS_EXEC = "slsExec";
60     private static final String SS_REQ_ID = "Id";
61     private static final String SLS_FILE_LOCATION = "slsFile";
62     private static final String SLS_NAME = "slsName";
63     private static final String MINION_TO_APPLY = "applyTo";
64     private static final String EXEC_TIMEOUT_TO_APPLY = "execTimeout";
65
66     private static final Logger LOGGER = LoggerFactory.getLogger(SaltstackMessageParser.class);
67
68     /**
69      * Method that validates that the Map has enough information
70      * to query Saltstack server for a result. If so, it returns
71      * the appropriate PORT number.
72      */
73     public String reqPortResult(Map<String, String> params) throws SvcLogicException {
74
75         final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
76                 PASS_KEY};
77
78         for (String key : mandatoryTestParams) {
79             throwIfMissingMandatoryParam(params, key);
80         }
81         return params.get(SS_AGENT_PORT_KEY);
82     }
83
84     /**
85      * Method that validates that the Map has enough information
86      * to query Saltstack server for a result. If so, it returns
87      * the appropriate HOST name.
88      */
89     public String reqHostNameResult(Map<String, String> params) throws SvcLogicException {
90
91         final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
92                 PASS_KEY};
93
94         for (String key : mandatoryTestParams) {
95             throwIfMissingMandatoryParam(params, key);
96         }
97         return params.get(SS_AGENT_HOSTNAME_KEY);
98     }
99
100     /**
101      * Method that validates that the Map has enough information
102      * to query Saltstack server for a result. If so, it returns
103      * the appropriate request ID.
104      */
105     public String reqId(Map<String, String> params) {
106
107         if (params.get(SaltstackMessageParser.SS_REQ_ID) == null) {
108             return UUID.randomUUID().toString();
109         } else if (params.get(SaltstackMessageParser.SS_REQ_ID).equalsIgnoreCase("")) {
110             return UUID.randomUUID().toString();
111         }
112         return params.get(SaltstackMessageParser.SS_REQ_ID);
113     }
114
115     /**
116      * Method that validates that the Map has enough information
117      * to query Saltstack server for a result. If so, it returns
118      * the appropriate command to execute.
119      */
120     public String reqCmd(Map<String, String> params) throws SvcLogicException {
121
122         final String[] mandatoryTestParams = {CMD_EXEC, IS_SLS_EXEC};
123
124         for (String key : mandatoryTestParams) {
125             throwIfMissingMandatoryParam(params, key);
126         }
127
128         return params.get(SaltstackMessageParser.CMD_EXEC);
129     }
130
131     /**
132      * Method that validates that the Map has enough information
133      * to query Saltstack server for a result. If so, it returns
134      * the appropriate SLS file location to execute.
135      */
136     public String reqSlsFile(Map<String, String> params) throws SvcLogicException {
137
138         final String[] mandatoryTestParams = {SLS_FILE_LOCATION};
139
140         for (String key : mandatoryTestParams) {
141             throwIfMissingMandatoryParam(params, key);
142         }
143
144         return params.get(SaltstackMessageParser.SLS_FILE_LOCATION);
145     }
146
147     /**
148      * Method that validates that the Map has enough information
149      * to query Saltstack server for a result. If so, it returns
150      * the appropriate SLS file location to execute.
151      */
152     public String reqSlsName(Map<String, String> params) throws SvcLogicException {
153
154         final String[] mandatoryTestParams = {SLS_NAME};
155
156         for (String key : mandatoryTestParams) {
157             throwIfMissingMandatoryParam(params, key);
158         }
159         String slsName = params.get(SaltstackMessageParser.SLS_NAME);
160         try {
161             if (slsName.substring(slsName.lastIndexOf("."), slsName.length()).equalsIgnoreCase(".sls")) {
162                 return stripExtension(slsName);
163             }
164         } catch (StringIndexOutOfBoundsException e) {
165             return slsName;
166         }
167         return slsName;
168     }
169
170     private String stripExtension(String str) {
171         if (str == null) {
172             return null;
173         }
174         int pos = str.lastIndexOf(".");
175         if (pos == -1) {
176             return str;
177         }
178         return str.substring(0, pos);
179     }
180
181     /**
182      * Method that validates that the Map has enough information
183      * to query Saltstack server for a result. If so, it returns
184      * the appropriate minions/vnfc to execute the SLS file to.
185      */
186     public String reqApplyToDevices(Map<String, String> params) {
187
188         if (params.get(SaltstackMessageParser.MINION_TO_APPLY) == null) {
189             return "*";
190         } else if (params.get(SaltstackMessageParser.MINION_TO_APPLY).equalsIgnoreCase("")) {
191             return "*";
192         }
193         return params.get(SaltstackMessageParser.MINION_TO_APPLY);
194     }
195
196     /**
197      * Method that validates that the Map has enough information
198      * to query Saltstack server for a result. If so, it returns
199      * the appropriate minions/vnfc to execute the SLS file to.
200      */
201     public long reqExecTimeout(Map<String, String> params) {
202
203         if (params.get(SaltstackMessageParser.EXEC_TIMEOUT_TO_APPLY) == null) {
204             return -1;
205         } else if (params.get(SaltstackMessageParser.EXEC_TIMEOUT_TO_APPLY).equalsIgnoreCase("")) {
206             return -1;
207         }
208         return Long.parseLong(params.get(SaltstackMessageParser.EXEC_TIMEOUT_TO_APPLY));
209     }
210
211     /**
212      * Method that validates that the Map has enough information
213      * to query Saltstack server for a result. If so, it returns
214      * the appropriate IsSLSExec true or false.
215      */
216     public boolean reqIsSLSExec(Map<String, String> params) throws SvcLogicException {
217
218         final String[] mandatoryTestParams = {CMD_EXEC, IS_SLS_EXEC};
219
220         for (String key : mandatoryTestParams) {
221             throwIfMissingMandatoryParam(params, key);
222         }
223
224         return params.get(SaltstackMessageParser.IS_SLS_EXEC).equalsIgnoreCase("true");
225     }
226
227     /**
228      * Method that validates that the Map has enough information
229      * to query Saltstack server for a result. If so, it returns
230      * the appropriate Saltstack server login user name.
231      */
232     public String reqUserNameResult(Map<String, String> params) throws SvcLogicException {
233
234         final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
235                 PASS_KEY};
236
237         for (String key : mandatoryTestParams) {
238             throwIfMissingMandatoryParam(params, key);
239         }
240         return params.get(USER_KEY);
241     }
242
243     /**
244      * Method that validates that the Map has enough information
245      * to query Saltstack server for a result. If so, it returns
246      * the appropriate Saltstack server login password.
247      */
248     public String reqPasswordResult(Map<String, String> params) throws SvcLogicException {
249
250         final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
251                 PASS_KEY};
252
253         for (String key : mandatoryTestParams) {
254             throwIfMissingMandatoryParam(params, key);
255         }
256         return params.get(PASS_KEY);
257     }
258
259     /**
260      * This method parses response from the Saltstack Server when we do a post
261      * and returns an SaltstackResult object.
262      */
263     public SaltstackResult parseResponse(SvcLogicContext ctx, String pfx,
264                                          SaltstackResult saltstackResult, boolean slsExec) throws IOException {
265         int code = saltstackResult.getStatusCode();
266         InputStream in = null;
267         boolean executionStatus = true, retCodeFound = false;
268         if (code != SaltstackResultCodes.SUCCESS.getValue()) {
269             return saltstackResult;
270         }
271         try {
272             File file = new File(saltstackResult.getOutputFileName());
273             in = new FileInputStream(file);
274             byte[] data = new byte[(int) file.length()];
275             in.read(data);
276             String str = new String(data, "UTF-8");
277             in.close();
278             Map<String, String> mm = JsonParser.convertToProperties(str);
279             if (mm != null) {
280                 for (Map.Entry<String, String> entry : mm.entrySet()) {
281                     if (entry.getKey().contains("retcode")) {
282                         retCodeFound = true;
283                         if (!entry.getValue().equalsIgnoreCase("0")) {
284                             executionStatus = false;
285                         }
286                     }
287                     ctx.setAttribute(pfx + "." + entry.getKey(), entry.getValue());
288                     LOGGER.info("+++ " + pfx + "." + entry.getKey() + ": [" + entry.getValue() + "]");
289                 }
290             }
291         } catch (FileNotFoundException e) {
292             return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "error parsing response file "
293                     + saltstackResult.getOutputFileName() + " : " + e.getMessage());
294         } catch (JSONException e) {
295             LOGGER.info("Output not in JSON format");
296             return putToProperties(ctx, pfx, saltstackResult);
297         } catch (Exception e) {
298             return new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "error parsing response file "
299                     + saltstackResult.getOutputFileName() + " : " + e.getMessage());
300         } finally {
301             if (in != null) {
302                 in.close();
303             }
304         }
305         if (slsExec) {
306             if (!retCodeFound) {
307                 return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(),
308                                            "error in executing configuration at the server");
309             }
310             if (!executionStatus) {
311                 return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(),
312                                            "error in executing configuration at the server");
313             }
314         }
315         saltstackResult.setStatusCode(SaltstackResultCodes.FINAL_SUCCESS.getValue());
316         return saltstackResult;
317     }
318
319     public SaltstackResult putToProperties(SvcLogicContext ctx, String pfx,
320                                            SaltstackResult saltstackResult) throws IOException {
321         InputStream in = null;
322         try {
323             File file = new File(saltstackResult.getOutputFileName());
324             in = new FileInputStream(file);
325             Properties prop = new Properties();
326             prop.load(in);
327             ctx.setAttribute(pfx + "completeResult", prop.toString());
328             for (Object key : prop.keySet()) {
329                 String name = (String) key;
330                 String value = prop.getProperty(name);
331                 if (value != null && value.trim().length() > 0) {
332                     ctx.setAttribute(pfx + "." + name, value.trim());
333                     LOGGER.info("+++ " + pfx + "." + name + ": [" + value + "]");
334                 }
335             }
336         } catch (Exception e) {
337             saltstackResult = new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "Error parsing response file = "
338                     + saltstackResult.getOutputFileName() + ". Error = " + e.getMessage());
339         } finally {
340             if (in != null) {
341                 in.close();
342             }
343         }
344         saltstackResult.setStatusCode(SaltstackResultCodes.FINAL_SUCCESS.getValue());
345         return saltstackResult;
346     }
347
348     private void throwIfMissingMandatoryParam(Map<String, String> params, String key) throws SvcLogicException {
349         if (!params.containsKey(key)) {
350             throw new SvcLogicException(String.format(
351                     "Saltstack: Mandatory SaltstackAdapter key %s not found in parameters provided by calling agent !",
352                     key));
353         }
354         if (Strings.isNullOrEmpty(params.get(key))) {
355             throw new SvcLogicException(String.format(
356                     "Saltstack: Mandatory SaltstackAdapter key %s not found in parameters provided by calling agent !",
357                     key));
358         }
359     }
360 }