* ================================================================================
* Copyright (C) 2017 Amdocs
* =============================================================================
+ * Modifications Copyright (C) 2019 IBM
+ * =============================================================================
+ * Modifications Copyright (C) 2019 Orange
+ * =============================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.apache.commons.lang.StringUtils;
/**
- * Class that validates and constructs requests sent/received from
- * Ansible Server
+ * Class that validates and constructs requests sent/received from Ansible
+ * Server
*/
public class AnsibleMessageParser {
private static final String STATUS_MESSAGE_KEY = "StatusMessage";
private static final String STATUS_CODE_KEY = "StatusCode";
-
+ private static final String SERVER_IP_KEY = "AnsibleServer";
private static final String PLAYBOOK_NAME_KEY = "PlaybookName";
private static final String AGENT_URL_KEY = "AgentUrl";
private static final String PASS_KEY = "Password";
private static final String USER_KEY = "User";
private static final String ID_KEY = "Id";
-
private static final String LOCAL_PARAMETERS_OPT_KEY = "LocalParameters";
private static final String FILE_PARAMETERS_OPT_KEY = "FileParameters";
private static final String ENV_PARAMETERS_OPT_KEY = "EnvParameters";
private static final String NODE_LIST_OPT_KEY = "NodeList";
+ private static final String AUTO_NODE_LIST_OPT_KEY = "AutoNodeList";
private static final String TIMEOUT_OPT_KEY = "Timeout";
private static final String VERSION_OPT_KEY = "Version";
+ private static final String INVENTORY_NAMES_OPT_KEY = "InventoryNames";
+ private static final String EXTRAVARS_OPT_KEY ="ExtraVars";
private static final String ACTION_OPT_KEY = "Action";
+ private static final String OUTPUT_OPT_KEY = "Output";
+ private static final String JSON_ERROR_MESSAGE = "JSONException: Error parsing response";
private static final Logger LOGGER = LoggerFactory.getLogger(AnsibleMessageParser.class);
/**
- * Accepts a map of strings and
- * a) validates if all parameters are appropriate (else, throws an exception) and
- * b) if correct returns a JSON object with appropriate key-value pairs to send to the server.
+ * Accepts a map of strings and a) validates if all parameters are appropriate
+ * (else, throws an exception) and b) if correct returns a JSON object with
+ * appropriate key-value pairs to send to the server.
*
- * Mandatory parameters, that must be in the supplied information to the Ansible Adapter
- * 1. URL to connect to
- * 2. credentials for URL (assume username password for now)
- * 3. Playbook name
+ * Mandatory parameters, that must be in the supplied information to the Ansible
+ * Adapter 1. URL to connect to 2. credentials for URL (assume username password
+ * for now) 3. Playbook name
*
*/
public JSONObject reqMessage(Map<String, String> params) throws APPCException {
- final String[] mandatoryTestParams = {AGENT_URL_KEY, PLAYBOOK_NAME_KEY, USER_KEY, PASS_KEY};
- final String[] optionalTestParams = {ENV_PARAMETERS_OPT_KEY, NODE_LIST_OPT_KEY, LOCAL_PARAMETERS_OPT_KEY,
- TIMEOUT_OPT_KEY, VERSION_OPT_KEY, FILE_PARAMETERS_OPT_KEY, ACTION_OPT_KEY};
+ final String[] mandatoryTestParams = { AGENT_URL_KEY, PLAYBOOK_NAME_KEY, USER_KEY, PASS_KEY };
+ final String[] optionalTestParams = { ENV_PARAMETERS_OPT_KEY, NODE_LIST_OPT_KEY, LOCAL_PARAMETERS_OPT_KEY,
+ TIMEOUT_OPT_KEY, VERSION_OPT_KEY, FILE_PARAMETERS_OPT_KEY, ACTION_OPT_KEY, INVENTORY_NAMES_OPT_KEY,
+ AUTO_NODE_LIST_OPT_KEY };
JSONObject jsonPayload = new JSONObject();
}
/**
- * Method that validates that the Map has enough information
- * to query Ansible server for a result. If so, it returns
- * the appropriate url, else an empty string.
+ * Method that validates that the Map has enough information to query Ansible
+ * server for a result. If so, it returns the appropriate url, else an empty
+ * string.
*/
public String reqUriResult(Map<String, String> params) throws APPCException {
- final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
+ final String[] mandatoryTestParams = { AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY };
for (String key : mandatoryTestParams) {
throwIfMissingMandatoryParam(params, key);
}
/**
- * Method that validates that the Map has enough information
- * to query Ansible server for logs. If so, it populates the appropriate
- * returns the appropriate url, else an empty string.
+ * Method that validates that the Map has enough information to query Ansible
+ * server for a result. If so, it returns the appropriate url, else an empty
+ * string.
+ */
+ public String reqUriResultWithIP(Map<String, String> params, String serverIP) throws APPCException {
+
+ final String[] mandatoryTestParams = { AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY };
+
+ for (String key : mandatoryTestParams) {
+ throwIfMissingMandatoryParam(params, key);
+ }
+ String[] arr1 = params.get(AGENT_URL_KEY).split("//", 2);
+ String[] arr2 = arr1[1].split(":", 2);
+ return arr1[0] + "//" + serverIP + ":" + arr2[1] + "?Id=" + params.get(ID_KEY) + "&Type=GetResult";
+ }
+
+ /**
+ * Method that validates that the Map has enough information to query Ansible
+ * server for logs. If so, it populates the appropriate returns the appropriate
+ * url, else an empty string.
*/
public String reqUriLog(Map<String, String> params) throws APPCException {
- final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
+ final String[] mandatoryTestParams = { AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY };
for (String mandatoryParam : mandatoryTestParams) {
throwIfMissingMandatoryParam(params, mandatoryParam);
}
/**
- * This method parses response from the Ansible Server when we do a post
- * and returns an AnsibleResult object.
+ * This method parses response from the Ansible Server when we do a post and
+ * returns an AnsibleResult object.
*/
public AnsibleResult parsePostResponse(String input) throws APPCException {
AnsibleResult ansibleResult;
int code = postResponse.getInt(STATUS_CODE_KEY);
String msg = postResponse.getString(STATUS_MESSAGE_KEY);
-
+ String serverIP = "";
+ if (postResponse.has(SERVER_IP_KEY))
+ serverIP = postResponse.getString(SERVER_IP_KEY);
+ else
+ serverIP = "";
int initResponseValue = AnsibleResultCodes.INITRESPONSE.getValue();
boolean validCode = AnsibleResultCodes.CODE.checkValidCode(initResponseValue, code);
if (!validCode) {
}
ansibleResult = new AnsibleResult(code, msg);
+ if (StringUtils.isNotBlank(serverIP))
+ ansibleResult.setServerIp(serverIP);
+
+ if (!postResponse.isNull(OUTPUT_OPT_KEY)) {
+ LOGGER.info("Processing results-output in post response");
+ JSONObject output = postResponse.getJSONObject(OUTPUT_OPT_KEY);
+ ansibleResult.setOutput(output.toString());
+ }
} catch (JSONException e) {
+ LOGGER.error(JSON_ERROR_MESSAGE, e);
ansibleResult = new AnsibleResult(600, "Error parsing response = " + input + ". Error = " + e.getMessage());
}
return ansibleResult;
}
/**
- * This method parses response from an Ansible server when we do a GET for a result
- * and returns an AnsibleResult object.
+ * This method parses response from an Ansible server when we do a GET for a
+ * result and returns an AnsibleResult object.
**/
public AnsibleResult parseGetResponse(String input) throws APPCException {
JSONObject postResponse = new JSONObject(input);
ansibleResult = parseGetResponseNested(ansibleResult, postResponse);
} catch (JSONException e) {
+ LOGGER.error(JSON_ERROR_MESSAGE, e);
ansibleResult = new AnsibleResult(AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
"Error parsing response = " + input + ". Error = " + e.getMessage(), "");
}
return ansibleResult;
}
- private AnsibleResult parseGetResponseNested(AnsibleResult ansibleResult, JSONObject postRsp) throws APPCException {
+ private AnsibleResult parseGetResponseNested(AnsibleResult ansibleResult, JSONObject postRsp) throws APPCException {
int codeStatus = postRsp.getInt(STATUS_CODE_KEY);
String messageStatus = postRsp.getString(STATUS_MESSAGE_KEY);
int finalCode = AnsibleResultCodes.FINAL_SUCCESS.getValue();
-
- boolean valCode =
- AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.FINALRESPONSE.getValue(), codeStatus);
+ JSONObject config = null;
+ boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.FINALRESPONSE.getValue(),
+ codeStatus);
if (!valCode) {
throw new APPCException("Invalid FinalResponse code = " + codeStatus + " received. MUST be one of "
ansibleResult.setStatusCode(codeStatus);
ansibleResult.setStatusMessage(messageStatus);
+ ansibleResult.setconfigData("UNKNOWN");
LOGGER.info("Received response with code = {}, Message = {}", codeStatus, messageStatus);
if (!postRsp.isNull("Results")) {
while (hosts.hasNext()) {
String host = hosts.next();
- LOGGER.info("Processing host = {}", host);
-
+ LOGGER.info("Processing host = {}",
+ (host.matches("^[\\w\\-.]+$")) ? host : "[unexpected value, logging suppressed]");
try {
JSONObject hostResponse = results.getJSONObject(host);
int subCode = hostResponse.getInt(STATUS_CODE_KEY);
LOGGER.info("Code = {}, Message = {}", subCode, message);
- if (subCode != 200 || !message.equals("SUCCESS")) {
+ if (subCode != 200 || !(("SUCCESS").equals(message))) {
finalCode = AnsibleResultCodes.REQ_FAILURE.getValue();
}
+ if ((hostResponse.optJSONObject(OUTPUT_OPT_KEY)) != null) {
+ JSONObject hostResponseObjectInfo = hostResponse.optJSONObject(OUTPUT_OPT_KEY).optJSONObject("info");
+ JSONObject hostResponseConfigData = hostResponseObjectInfo.optJSONObject("configData");
+ if ((hostResponseObjectInfo != null) && hostResponseConfigData != null) {
+ config = hostResponseConfigData;
+ ansibleResult.setconfigData(config.toString());
+ }
+ }
} catch (JSONException e) {
+ LOGGER.error(JSON_ERROR_MESSAGE, e);
ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
- ansibleResult.setStatusMessage(String.format(
- "Error processing response message = %s from host %s", results.getString(host), host));
+ ansibleResult.setStatusMessage(String.format("Error processing response message = %s from host %s",
+ results.getString(host), host));
break;
}
}
ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
ansibleResult.setStatusMessage("Results not found in GET for response");
}
- if(!postRsp.isNull("Output")) {
+ if (!postRsp.isNull(OUTPUT_OPT_KEY)) {
LOGGER.info("Processing results-output in response");
- JSONObject output = postRsp.getJSONObject("Output");
+ JSONObject output = postRsp.getJSONObject(OUTPUT_OPT_KEY);
ansibleResult.setOutput(output.toString());
}
Set<String> optionalParamsSet = new HashSet<>();
Collections.addAll(optionalParamsSet, optionalTestParams);
- //@formatter:off
- params.entrySet()
- .stream()
- .filter(entry -> optionalParamsSet.contains(entry.getKey()))
- .filter(entry -> !Strings.isNullOrEmpty(entry.getValue()))
- .forEach(entry -> parseOptionalParam(entry, jsonPayload));
- //@formatter:on
+ // @formatter:off
+ params.entrySet().stream().filter(entry -> optionalParamsSet.contains(entry.getKey()))
+ .filter(entry -> !Strings.isNullOrEmpty(entry.getValue()))
+ .forEach(entry -> parseOptionalParam(entry, jsonPayload));
+ // @formatter:on
}
private void parseOptionalParam(Map.Entry<String, String> params, JSONObject jsonPayload) {
String payload = params.getValue();
switch (key) {
- case TIMEOUT_OPT_KEY:
- int timeout = Integer.parseInt(payload);
- if (timeout < 0) {
- throw new NumberFormatException(" : specified negative integer for timeout = " + payload);
- }
- jsonPayload.put(key, payload);
+ case TIMEOUT_OPT_KEY:
+ if (dataIsVariable(payload))
break;
-
- case VERSION_OPT_KEY:
+ int timeout = Integer.parseInt(payload);
+ if (timeout < 0) {
+ throw new NumberFormatException(" : specified negative integer for timeout = " + payload);
+ }
+ jsonPayload.put(key, payload);
+ break;
+ case AUTO_NODE_LIST_OPT_KEY:
+ if (payload.equalsIgnoreCase("true") || payload.equalsIgnoreCase("false")) {
jsonPayload.put(key, payload);
- break;
+ } else {
+ throw new IllegalArgumentException(" : specified invalid boolean value of AutoNodeList = " + payload);
+ }
+ break;
+ case VERSION_OPT_KEY:
+ if (dataIsVariable(payload))
+ break;
+ case INVENTORY_NAMES_OPT_KEY:
+ jsonPayload.put(key, payload);
+ break;
- case LOCAL_PARAMETERS_OPT_KEY:
- case ENV_PARAMETERS_OPT_KEY:
+ case LOCAL_PARAMETERS_OPT_KEY:
+ case ENV_PARAMETERS_OPT_KEY:
+ case EXTRAVARS_OPT_KEY:
JSONObject paramsJson = new JSONObject(payload);
+ jsonDataIsVariable(paramsJson);
jsonPayload.put(key, paramsJson);
break;
+ case NODE_LIST_OPT_KEY:
+ if(payload.startsWith("$"))
+ break;
+ JSONArray paramsArray = new JSONArray(payload);
+ jsonPayload.put(key, paramsArray);
+ break;
+ case FILE_PARAMETERS_OPT_KEY:
+ if (dataIsVariable(payload))
+ break;
+ jsonPayload.put(key, getFilePayload(payload));
+ break;
- case NODE_LIST_OPT_KEY:
- JSONArray paramsArray = new JSONArray(payload);
- jsonPayload.put(key, paramsArray);
- break;
-
- case FILE_PARAMETERS_OPT_KEY:
- jsonPayload.put(key, getFilePayload(payload));
- break;
-
- default:
- break;
+ default:
+ break;
}
}
"Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !",
key));
}
+
+ if (StringUtils.startsWith(params.get(key), "$")) {
+ throw new APPCException(String.format(
+ "Ansible: Mandatory AnsibleAdapter key %s is a variable",
+ key));
+ }
+ }
+
+
+ /*private boolean varObjContainsNoData(Object obj) {
+ if (obj instanceof String) {
+ if (StringUtils.startsWith(obj.toString(), "$") || StringUtils.isEmpty(obj.toString()))
+ return true;
+ }
+ return false;
+
+ }*/
+
+ private boolean dataIsVariable(String payload) {
+ if (StringUtils.startsWith(payload, "$") || StringUtils.isEmpty(payload))
+ return true;
+ else
+ return false;
+
+ }
+
+ private JSONObject jsonDataIsVariable(JSONObject paramsJson) {
+ LOGGER.info("input json is " + paramsJson);
+ String[] keys = JSONObject.getNames(paramsJson);
+ for (String k : keys) {
+ Object a = paramsJson.get(k);
+ if (a instanceof String) {
+ if (StringUtils.startsWith(a.toString(), "$") || StringUtils.isEmpty(a.toString())) {
+ LOGGER.info("removing key " + k);
+ paramsJson.remove(k);
+ }
+ }
+ }
+ LOGGER.info("returning json as " + paramsJson);
+ return paramsJson;
}
}