2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
20 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.appc.adapter.ansible.model;
26 * This module imples the APP-C/Ansible Server interface
27 * based on the REST API specifications
30 import java.lang.NumberFormatException ;
32 import com.google.common.base.Strings;
34 import org.json.JSONObject;
35 import org.json.JSONArray;
36 import org.json.JSONException;
37 import org.openecomp.appc.exceptions.APPCException;
38 import org.openecomp.appc.adapter.ansible.model.AnsibleResult;
42 * Class that validates and constructs requests sent/received from
46 public class AnsibleMessageParser {
51 // Accepts a map of strings and
52 // a) validates if all parameters are appropriate (else, throws an exception)
53 // and b) if correct returns a JSON object with appropriate key-value
54 // pairs to send to the server.
55 public JSONObject ReqMessage(Map <String, String> params) throws APPCException, NumberFormatException, JSONException{
57 // Mandatory parameters, that must be in the supplied information to the Ansible Adapter
58 // 1. URL to connect to
59 // 2. credentials for URL (assume username password for now)
61 String[] mandatoryTestParams = {"AgentUrl", "PlaybookName", "User", "Password"};
63 // Optional testService parameters that may be provided in the request
64 String[] optionalTestParams = {"EnvParameters", "NodeList", "LocalParameters", "Timeout", "Version", "FileParameters", "Action"};
66 JSONObject JsonPayload = new JSONObject();
68 JSONObject paramsJson;
71 // Verify all the mandatory parameters are there
72 for (String key: mandatoryTestParams){
73 if (! params.containsKey(key)){
74 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
76 payload = params.get(key);
77 if (Strings.isNullOrEmpty(payload)){
78 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key % value is Null or Emtpy", key));
81 JsonPayload.put(key, payload);
84 // Iterate through optional parameters
85 // If null or empty omit it
86 for (String key : optionalTestParams){
87 if (params.containsKey(key)){
88 payload = params.get(key);
89 if(!Strings.isNullOrEmpty(payload)){
91 // different cases require different treatment
94 int Timeout = Integer.parseInt(payload);
96 throw new NumberFormatException(" : specified negative integer for timeout = " + payload);
98 JsonPayload.put(key, payload);
102 JsonPayload.put(key, payload);
105 case "LocalParameters":
106 paramsJson = new JSONObject(payload);
107 JsonPayload.put(key, paramsJson);
110 case "EnvParameters":
111 paramsJson = new JSONObject(payload);
112 JsonPayload.put(key, paramsJson);
116 JSONArray paramsArray = new JSONArray(payload);
117 JsonPayload.put(key, paramsArray);
120 case "FileParameters":
121 // Files may have strings with newlines. Escape them as appropriate
122 String formattedPayload = payload.replace("\n", "\\n").replace("\r", "\\r");
123 JSONObject fileParams = new JSONObject(formattedPayload);
124 JsonPayload.put(key, fileParams);
133 // Generate a unique uuid for the test
134 String ReqId = UUID.randomUUID().toString();
135 JsonPayload.put("Id", ReqId);
143 // method that validates that the Map has enough information
144 // to query Ansible server for a result . If so, it
145 // returns the appropriate url, else an empty string
146 public String ReqUri_Result(Map <String, String> params) throws APPCException, NumberFormatException{
148 // Mandatory parameters, that must be in the request
149 String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
151 // Verify all the mandatory parameters are there
155 for (String key: mandatoryTestParams){
156 if (! params.containsKey(key)){
157 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
160 payload = params.get(key);
161 if (Strings.isNullOrEmpty(payload)){
162 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
167 Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetResult";
175 // method that validates that the Map has enough information
176 // to query Ansible server for logs. If so, it populates the appropriate
177 // returns the appropriate url, else an empty string
178 public String ReqUri_Output(Map <String, String> params) throws APPCException, NumberFormatException{
181 // Mandatory parameters, that must be in the request
182 String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
184 // Verify all the mandatory parameters are there
188 for (String key: mandatoryTestParams){
189 if (! params.containsKey(key)){
190 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
192 payload = params.get(key);
193 if (Strings.isNullOrEmpty(payload)){
194 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
199 Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetOutput";
204 // method that validates that the Map has enough information
205 // to query Ansible server for logs. If so, it populates the appropriate
206 // returns the appropriate url, else an empty string
207 public String ReqUri_Log(Map <String, String> params) throws APPCException, NumberFormatException{
210 // Mandatory parameters, that must be in the request
211 String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
213 // Verify all the mandatory parameters are there
217 for (String key: mandatoryTestParams){
218 if (! params.containsKey(key)){
219 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
221 payload = params.get(key);
222 if (Strings.isNullOrEmpty(payload)){
223 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
228 Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetLog";
235 This method parses response from the
236 Ansible Server when we do a post
237 and returns an AnsibleResult object
240 public AnsibleResult parsePostResponse(String Input) throws APPCException{
242 AnsibleResult ansibleResult = new AnsibleResult();
246 JSONObject postResponse = new JSONObject(Input);
248 // Mandatory keys required are StatusCode and StatusMessage
249 int Code = postResponse.getInt("StatusCode");
250 String Message = postResponse.getString("StatusMessage");
253 // Status code must must be either 100 (accepted) or 101 (rejected)
254 boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.INITRESPONSE.getValue(), Code);
256 throw new APPCException("Invalid InitResponse code = " + Code + " received. MUST be one of " + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.INITRESPONSE.getValue()) );
259 ansibleResult.setStatusCode(Code);
260 ansibleResult.setStatusMessage(Message);
263 catch(JSONException e){
264 ansibleResult = new AnsibleResult(600, "Error parsing response = " + Input + ". Error = " + e.getMessage(), "");
268 return ansibleResult;
272 /** This method parses response from an Ansible server when we do a GET for a result
273 and returns an AnsibleResult object
275 public AnsibleResult parseGetResponse(String Input) throws APPCException {
277 AnsibleResult ansibleResult = new AnsibleResult();
278 int FinalCode = AnsibleResultCodes.FINAL_SUCCESS.getValue();
284 JSONObject postResponse = new JSONObject(Input);
286 // Mandatory keys required are Status and Message
287 int Code = postResponse.getInt("StatusCode");
288 String Message = postResponse.getString("StatusMessage");
290 // Status code must be valid
291 // Status code must must be either 100 (accepted) or 101 (rejected)
292 boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.FINALRESPONSE.getValue(), Code);
295 throw new APPCException("Invalid FinalResponse code = " + Code + " received. MUST be one of " + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.FINALRESPONSE.getValue()));
299 ansibleResult.setStatusCode(Code);
300 ansibleResult.setStatusMessage(Message);
301 System.out.println("Received response with code = " + Integer.toString(Code) + " Message = " + Message);
303 if(! postResponse.isNull("Results")){
305 // Results are available. process them
306 // Results is a dictionary of the form
307 // {host :{status:s, group:g, message:m, hostname:h}, ...}
308 System.out.println("Processing results in response");
309 JSONObject results = postResponse.getJSONObject("Results");
310 System.out.println("Get JSON dictionary from Results ..");
311 Iterator<String> hosts = results.keys();
312 System.out.println("Iterating through hosts");
314 while(hosts.hasNext()){
315 String host = hosts.next();
316 System.out.println("Processing host = " + host);
319 JSONObject host_response = results.getJSONObject(host);
320 int subCode = host_response.getInt("StatusCode");
321 String message = host_response.getString("StatusMessage");
323 System.out.println("Code = " + Integer.toString(subCode) + " Message = " + message);
325 if(subCode != 200 || ! message.equals("SUCCESS")){
326 FinalCode = AnsibleResultCodes.REQ_FAILURE.getValue();
329 catch(JSONException e){
330 ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
331 ansibleResult.setStatusMessage(String.format("Error processing response message = %s from host %s", results.getString(host), host));
336 ansibleResult.setStatusCode(FinalCode);
338 // We return entire Results object as message
339 ansibleResult.setResults(results.toString());
343 ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
344 ansibleResult.setStatusMessage("Results not found in GET for response");
349 catch(JSONException e){
350 ansibleResult = new AnsibleResult(AnsibleResultCodes.INVALID_PAYLOAD.getValue(), "Error parsing response = " + Input + ". Error = " + e.getMessage(), "");
354 return ansibleResult;