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
31 import java.util.Collections;
32 import java.util.HashSet;
33 import java.util.Iterator;
36 import java.util.UUID;
37 import org.json.JSONArray;
38 import org.json.JSONException;
39 import org.json.JSONObject;
40 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
41 import com.google.common.base.Strings;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * Class that validates and constructs requests sent/received from
49 //TODO: This class is to be altered completely based on the SALTSTACK server communicaiton.
50 public class SaltstackMessageParser {
52 private static final String STATUS_MESSAGE_KEY = "StatusMessage";
53 private static final String STATUS_CODE_KEY = "StatusCode";
55 private static final String SALTSTATE_NAME_KEY = "SaltStateName";
56 private static final String AGENT_URL_KEY = "AgentUrl";
57 private static final String PASS_KEY = "Password";
58 private static final String USER_KEY = "User";
59 private static final String ID_KEY = "Id";
61 private static final String LOCAL_PARAMETERS_OPT_KEY = "LocalParameters";
62 private static final String FILE_PARAMETERS_OPT_KEY = "FileParameters";
63 private static final String ENV_PARAMETERS_OPT_KEY = "EnvParameters";
64 private static final String NODE_LIST_OPT_KEY = "NodeList";
65 private static final String TIMEOUT_OPT_KEY = "Timeout";
66 private static final String VERSION_OPT_KEY = "Version";
67 private static final String ACTION_OPT_KEY = "Action";
69 private static final Logger LOGGER = LoggerFactory.getLogger(SaltstackMessageParser.class);
72 * Accepts a map of strings and
73 * a) validates if all parameters are appropriate (else, throws an exception) and
74 * b) if correct returns a JSON object with appropriate key-value pairs to send to the server.
76 * Mandatory parameters, that must be in the supplied information to the Saltstack Adapter
77 * 1. URL to connect to
78 * 2. credentials for URL (assume username password for now)
82 public JSONObject reqMessage(Map<String, String> params) throws SvcLogicException {
83 final String[] mandatoryTestParams = {AGENT_URL_KEY, SALTSTATE_NAME_KEY, USER_KEY, PASS_KEY};
84 final String[] optionalTestParams = {ENV_PARAMETERS_OPT_KEY, NODE_LIST_OPT_KEY, LOCAL_PARAMETERS_OPT_KEY,
85 TIMEOUT_OPT_KEY, VERSION_OPT_KEY, FILE_PARAMETERS_OPT_KEY, ACTION_OPT_KEY};
87 JSONObject jsonPayload = new JSONObject();
89 for (String key : mandatoryTestParams) {
90 throwIfMissingMandatoryParam(params, key);
91 jsonPayload.put(key, params.get(key));
94 parseOptionalParams(params, optionalTestParams, jsonPayload);
96 // Generate a unique uuid for the test
97 String reqId = UUID.randomUUID().toString();
98 jsonPayload.put(ID_KEY, reqId);
104 * Method that validates that the Map has enough information
105 * to query Saltstack server for a result. If so, it returns
106 * the appropriate url, else an empty string.
108 public String reqUriResult(Map<String, String> params) throws SvcLogicException {
110 final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
112 for (String key : mandatoryTestParams) {
113 throwIfMissingMandatoryParam(params, key);
115 return params.get(AGENT_URL_KEY) + "?Id=" + params.get(ID_KEY) + "&Type=GetResult";
119 * Method that validates that the Map has enough information
120 * to query Saltstack server for logs. If so, it populates the appropriate
121 * returns the appropriate url, else an empty string.
123 public String reqUriLog(Map<String, String> params) throws SvcLogicException {
125 final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
127 for (String mandatoryParam : mandatoryTestParams) {
128 throwIfMissingMandatoryParam(params, mandatoryParam);
130 return params.get(AGENT_URL_KEY) + "?Id=" + params.get(ID_KEY) + "&Type=GetLog";
134 * This method parses response from the Saltstack Server when we do a post
135 * and returns an SaltstackResult object.
137 public SaltstackResult parsePostResponse(String input) throws SvcLogicException {
138 SaltstackResult saltstackResult;
140 JSONObject postResponse = new JSONObject(input);
142 int code = postResponse.getInt(STATUS_CODE_KEY);
143 String msg = postResponse.getString(STATUS_MESSAGE_KEY);
145 int initResponseValue = SaltstackResultCodes.INITRESPONSE.getValue();
146 boolean validCode = SaltstackResultCodes.CODE.checkValidCode(initResponseValue, code);
148 throw new SvcLogicException("Invalid InitResponse code = " + code + " received. MUST be one of "
149 + SaltstackResultCodes.CODE.getValidCodes(initResponseValue));
152 saltstackResult = new SaltstackResult(code, msg);
154 } catch (JSONException e) {
155 saltstackResult = new SaltstackResult(600, "Error parsing response = " + input + ". Error = " + e.getMessage());
157 return saltstackResult;
161 * This method parses response from an Saltstack server when we do a GET for a result
162 * and returns an SaltstackResult object.
164 public SaltstackResult parseGetResponse(String input) throws SvcLogicException {
166 SaltstackResult saltstackResult = new SaltstackResult();
169 JSONObject postResponse = new JSONObject(input);
170 saltstackResult = parseGetResponseNested(saltstackResult, postResponse);
171 } catch (JSONException e) {
172 saltstackResult = new SaltstackResult(SaltstackResultCodes.INVALID_PAYLOAD.getValue(),
173 "Error parsing response = " + input + ". Error = " + e.getMessage(), "");
175 return saltstackResult;
178 private SaltstackResult parseGetResponseNested(SaltstackResult saltstackResult, JSONObject postRsp) throws SvcLogicException {
180 int codeStatus = postRsp.getInt(STATUS_CODE_KEY);
181 String messageStatus = postRsp.getString(STATUS_MESSAGE_KEY);
182 int finalCode = SaltstackResultCodes.FINAL_SUCCESS.getValue();
185 SaltstackResultCodes.CODE.checkValidCode(SaltstackResultCodes.FINALRESPONSE.getValue(), codeStatus);
188 throw new SvcLogicException("Invalid FinalResponse code = " + codeStatus + " received. MUST be one of "
189 + SaltstackResultCodes.CODE.getValidCodes(SaltstackResultCodes.FINALRESPONSE.getValue()));
192 saltstackResult.setStatusCode(codeStatus);
193 saltstackResult.setStatusMessage(messageStatus);
194 LOGGER.info("Received response with code = {}, Message = {}", codeStatus, messageStatus);
196 if (!postRsp.isNull("Results")) {
198 // Results are available. process them
199 // Results is a dictionary of the form
200 // {host :{status:s, group:g, message:m, hostname:h}, ...}
201 LOGGER.info("Processing results in response");
202 JSONObject results = postRsp.getJSONObject("Results");
203 LOGGER.info("Get JSON dictionary from Results ..");
204 Iterator<String> hosts = results.keys();
205 LOGGER.info("Iterating through hosts");
207 while (hosts.hasNext()) {
208 String host = hosts.next();
209 LOGGER.info("Processing host = {}", host);
212 JSONObject hostResponse = results.getJSONObject(host);
213 int subCode = hostResponse.getInt(STATUS_CODE_KEY);
214 String message = hostResponse.getString(STATUS_MESSAGE_KEY);
216 LOGGER.info("Code = {}, Message = {}", subCode, message);
218 if (subCode != 200 || !message.equals("SUCCESS")) {
219 finalCode = SaltstackResultCodes.REQ_FAILURE.getValue();
221 } catch (JSONException e) {
222 saltstackResult.setStatusCode(SaltstackResultCodes.INVALID_RESPONSE.getValue());
223 saltstackResult.setStatusMessage(String.format(
224 "Error processing response message = %s from host %s", results.getString(host), host));
229 saltstackResult.setStatusCode(finalCode);
231 // We return entire Results object as message
232 saltstackResult.setResults(results.toString());
235 saltstackResult.setStatusCode(SaltstackResultCodes.INVALID_RESPONSE.getValue());
236 saltstackResult.setStatusMessage("Results not found in GET for response");
238 return saltstackResult;
241 private void parseOptionalParams(Map<String, String> params, String[] optionalTestParams, JSONObject jsonPayload) {
243 Set<String> optionalParamsSet = new HashSet<>();
244 Collections.addAll(optionalParamsSet, optionalTestParams);
249 .filter(entry -> optionalParamsSet.contains(entry.getKey()))
250 .filter(entry -> !Strings.isNullOrEmpty(entry.getValue()))
251 .forEach(entry -> parseOptionalParam(entry, jsonPayload));
255 private void parseOptionalParam(Map.Entry<String, String> params, JSONObject jsonPayload) {
256 String key = params.getKey();
257 String payload = params.getValue();
260 case TIMEOUT_OPT_KEY:
261 int timeout = Integer.parseInt(payload);
263 throw new NumberFormatException(" : specified negative integer for timeout = " + payload);
265 jsonPayload.put(key, payload);
268 case VERSION_OPT_KEY:
269 jsonPayload.put(key, payload);
272 case LOCAL_PARAMETERS_OPT_KEY:
273 case ENV_PARAMETERS_OPT_KEY:
274 JSONObject paramsJson = new JSONObject(payload);
275 jsonPayload.put(key, paramsJson);
278 case NODE_LIST_OPT_KEY:
279 JSONArray paramsArray = new JSONArray(payload);
280 jsonPayload.put(key, paramsArray);
283 case FILE_PARAMETERS_OPT_KEY:
284 jsonPayload.put(key, getFilePayload(payload));
293 * Return payload with escaped newlines
295 private JSONObject getFilePayload(String payload) {
296 String formattedPayload = payload.replace("\n", "\\n").replace("\r", "\\r");
297 return new JSONObject(formattedPayload);
300 private void throwIfMissingMandatoryParam(Map<String, String> params, String key) throws SvcLogicException {
301 if (!params.containsKey(key)) {
302 throw new SvcLogicException(String.format(
303 "Saltstack: Mandatory SaltstackAdapter key %s not found in parameters provided by calling agent !",
306 if (Strings.isNullOrEmpty(params.get(key))) {
307 throw new SvcLogicException(String.format(
308 "Saltstack: Mandatory SaltstackAdapter key %s not found in parameters provided by calling agent !",