2 * ============LICENSE_START=======================================================
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.onap.ccsdk.sli.adaptors.saltstack.model;
28 * This module implements the APP-C/Saltstack Server interface
29 * based on the REST API specifications
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;
40 import java.io.FileInputStream;
41 import java.io.FileNotFoundException;
42 import java.io.IOException;
43 import java.io.InputStream;
45 import java.util.Properties;
46 import java.util.UUID;
49 * Class that validates and constructs requests sent/received from
52 public class SaltstackMessageParser {
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";
66 private static final Logger LOGGER = LoggerFactory.getLogger(SaltstackMessageParser.class);
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.
73 public String reqPortResult(Map<String, String> params) throws SvcLogicException {
75 final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
78 for (String key : mandatoryTestParams) {
79 throwIfMissingMandatoryParam(params, key);
81 return params.get(SS_AGENT_PORT_KEY);
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.
89 public String reqHostNameResult(Map<String, String> params) throws SvcLogicException {
91 final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
94 for (String key : mandatoryTestParams) {
95 throwIfMissingMandatoryParam(params, key);
97 return params.get(SS_AGENT_HOSTNAME_KEY);
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.
105 public String reqId(Map<String, String> params) {
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();
112 return params.get(SaltstackMessageParser.SS_REQ_ID);
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.
120 public String reqCmd(Map<String, String> params) throws SvcLogicException {
122 final String[] mandatoryTestParams = {CMD_EXEC, IS_SLS_EXEC};
124 for (String key : mandatoryTestParams) {
125 throwIfMissingMandatoryParam(params, key);
128 return params.get(SaltstackMessageParser.CMD_EXEC);
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.
136 public String reqSlsFile(Map<String, String> params) throws SvcLogicException {
138 final String[] mandatoryTestParams = {SLS_FILE_LOCATION};
140 for (String key : mandatoryTestParams) {
141 throwIfMissingMandatoryParam(params, key);
144 return params.get(SaltstackMessageParser.SLS_FILE_LOCATION);
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.
152 public String reqSlsName(Map<String, String> params) throws SvcLogicException {
154 final String[] mandatoryTestParams = {SLS_NAME};
156 for (String key : mandatoryTestParams) {
157 throwIfMissingMandatoryParam(params, key);
159 String slsName = params.get(SaltstackMessageParser.SLS_NAME);
161 if (slsName.substring(slsName.lastIndexOf("."), slsName.length()).equalsIgnoreCase(".sls")) {
162 return stripExtension(slsName);
164 } catch (StringIndexOutOfBoundsException e) {
170 private String stripExtension(String str) {
174 int pos = str.lastIndexOf(".");
178 return str.substring(0, pos);
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.
186 public String reqApplyToDevices(Map<String, String> params) {
188 if (params.get(SaltstackMessageParser.MINION_TO_APPLY) == null) {
190 } else if (params.get(SaltstackMessageParser.MINION_TO_APPLY).equalsIgnoreCase("")) {
193 return params.get(SaltstackMessageParser.MINION_TO_APPLY);
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.
201 public long reqExecTimeout(Map<String, String> params) {
203 if (params.get(SaltstackMessageParser.EXEC_TIMEOUT_TO_APPLY) == null) {
205 } else if (params.get(SaltstackMessageParser.EXEC_TIMEOUT_TO_APPLY).equalsIgnoreCase("")) {
208 return Long.parseLong(params.get(SaltstackMessageParser.EXEC_TIMEOUT_TO_APPLY));
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.
216 public boolean reqIsSLSExec(Map<String, String> params) throws SvcLogicException {
218 final String[] mandatoryTestParams = {CMD_EXEC, IS_SLS_EXEC};
220 for (String key : mandatoryTestParams) {
221 throwIfMissingMandatoryParam(params, key);
224 return params.get(SaltstackMessageParser.IS_SLS_EXEC).equalsIgnoreCase("true");
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.
232 public String reqUserNameResult(Map<String, String> params) throws SvcLogicException {
234 final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
237 for (String key : mandatoryTestParams) {
238 throwIfMissingMandatoryParam(params, key);
240 return params.get(USER_KEY);
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.
248 public String reqPasswordResult(Map<String, String> params) throws SvcLogicException {
250 final String[] mandatoryTestParams = {SS_AGENT_HOSTNAME_KEY, SS_AGENT_PORT_KEY, USER_KEY,
253 for (String key : mandatoryTestParams) {
254 throwIfMissingMandatoryParam(params, key);
256 return params.get(PASS_KEY);
260 * This method parses response from the Saltstack Server when we do a post
261 * and returns an SaltstackResult object.
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;
272 File file = new File(saltstackResult.getOutputFileName());
273 in = new FileInputStream(file);
274 byte[] data = new byte[(int) file.length()];
276 String str = new String(data, "UTF-8");
278 Map<String, String> mm = JsonParser.convertToProperties(str);
280 for (Map.Entry<String, String> entry : mm.entrySet()) {
281 if (entry.getKey().contains("retcode")) {
283 if (!entry.getValue().equalsIgnoreCase("0")) {
284 executionStatus = false;
287 ctx.setAttribute(pfx + "." + entry.getKey(), entry.getValue());
288 LOGGER.info("+++ " + pfx + "." + entry.getKey() + ": [" + entry.getValue() + "]");
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());
307 return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(),
308 "error in executing configuration at the server");
310 if (!executionStatus) {
311 return new SaltstackResult(SaltstackResultCodes.COMMAND_EXEC_FAILED_STATUS.getValue(),
312 "error in executing configuration at the server");
315 saltstackResult.setStatusCode(SaltstackResultCodes.FINAL_SUCCESS.getValue());
316 return saltstackResult;
319 public SaltstackResult putToProperties(SvcLogicContext ctx, String pfx,
320 SaltstackResult saltstackResult) throws IOException {
321 InputStream in = null;
323 File file = new File(saltstackResult.getOutputFileName());
324 in = new FileInputStream(file);
325 Properties prop = new Properties();
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 + "]");
336 } catch (Exception e) {
337 saltstackResult = new SaltstackResult(SaltstackResultCodes.INVALID_RESPONSE_FILE.getValue(), "Error parsing response file = "
338 + saltstackResult.getOutputFileName() + ". Error = " + e.getMessage());
344 saltstackResult.setStatusCode(SaltstackResultCodes.FINAL_SUCCESS.getValue());
345 return saltstackResult;
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 !",
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 !",