2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 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.appc.adapter.ansible.model;
28 * This module imples the APP-C/Ansible Server interface
29 * based on the REST API specifications
32 import java.lang.NumberFormatException ;
34 import com.google.common.base.Strings;
36 import org.json.JSONObject;
37 import org.json.JSONArray;
38 import org.json.JSONException;
39 import org.onap.appc.exceptions.APPCException;
40 import org.onap.appc.adapter.ansible.model.AnsibleResult;
44 * Class that validates and constructs requests sent/received from
48 public class AnsibleMessageParser {
53 // Accepts a map of strings and
54 // a) validates if all parameters are appropriate (else, throws an exception)
55 // and b) if correct returns a JSON object with appropriate key-value
56 // pairs to send to the server.
57 public JSONObject ReqMessage(Map <String, String> params) throws APPCException, NumberFormatException, JSONException{
59 // Mandatory parameters, that must be in the supplied information to the Ansible Adapter
60 // 1. URL to connect to
61 // 2. credentials for URL (assume username password for now)
63 String[] mandatoryTestParams = {"AgentUrl", "PlaybookName", "User", "Password"};
65 // Optional testService parameters that may be provided in the request
66 String[] optionalTestParams = {"EnvParameters", "NodeList", "LocalParameters", "Timeout", "Version", "FileParameters", "Action"};
68 JSONObject JsonPayload = new JSONObject();
70 JSONObject paramsJson;
73 // Verify all the mandatory parameters are there
74 for (String key: mandatoryTestParams){
75 if (! params.containsKey(key)){
76 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
78 payload = params.get(key);
79 if (Strings.isNullOrEmpty(payload)){
80 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key % value is Null or Emtpy", key));
83 JsonPayload.put(key, payload);
86 // Iterate through optional parameters
87 // If null or empty omit it
88 for (String key : optionalTestParams){
89 if (params.containsKey(key)){
90 payload = params.get(key);
91 if(!Strings.isNullOrEmpty(payload)){
93 // different cases require different treatment
96 int Timeout = Integer.parseInt(payload);
98 throw new NumberFormatException(" : specified negative integer for timeout = " + payload);
100 JsonPayload.put(key, payload);
104 JsonPayload.put(key, payload);
107 case "LocalParameters":
108 paramsJson = new JSONObject(payload);
109 JsonPayload.put(key, paramsJson);
112 case "EnvParameters":
113 paramsJson = new JSONObject(payload);
114 JsonPayload.put(key, paramsJson);
118 JSONArray paramsArray = new JSONArray(payload);
119 JsonPayload.put(key, paramsArray);
122 case "FileParameters":
123 // Files may have strings with newlines. Escape them as appropriate
124 String formattedPayload = payload.replace("\n", "\\n").replace("\r", "\\r");
125 JSONObject fileParams = new JSONObject(formattedPayload);
126 JsonPayload.put(key, fileParams);
135 // Generate a unique uuid for the test
136 String ReqId = UUID.randomUUID().toString();
137 JsonPayload.put("Id", ReqId);
145 // method that validates that the Map has enough information
146 // to query Ansible server for a result . If so, it
147 // returns the appropriate url, else an empty string
148 public String ReqUri_Result(Map <String, String> params) throws APPCException, NumberFormatException{
150 // Mandatory parameters, that must be in the request
151 String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
153 // Verify all the mandatory parameters are there
157 for (String key: mandatoryTestParams){
158 if (! params.containsKey(key)){
159 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
162 payload = params.get(key);
163 if (Strings.isNullOrEmpty(payload)){
164 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
169 Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetResult";
177 // method that validates that the Map has enough information
178 // to query Ansible server for logs. If so, it populates the appropriate
179 // returns the appropriate url, else an empty string
180 public String ReqUri_Output(Map <String, String> params) throws APPCException, NumberFormatException{
183 // Mandatory parameters, that must be in the request
184 String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
186 // Verify all the mandatory parameters are there
190 for (String key: mandatoryTestParams){
191 if (! params.containsKey(key)){
192 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
194 payload = params.get(key);
195 if (Strings.isNullOrEmpty(payload)){
196 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
201 Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetOutput";
206 // method that validates that the Map has enough information
207 // to query Ansible server for logs. If so, it populates the appropriate
208 // returns the appropriate url, else an empty string
209 public String ReqUri_Log(Map <String, String> params) throws APPCException, NumberFormatException{
212 // Mandatory parameters, that must be in the request
213 String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
215 // Verify all the mandatory parameters are there
219 for (String key: mandatoryTestParams){
220 if (! params.containsKey(key)){
221 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
223 payload = params.get(key);
224 if (Strings.isNullOrEmpty(payload)){
225 throw new APPCException(String.format("Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
230 Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetLog";
237 This method parses response from the
238 Ansible Server when we do a post
239 and returns an AnsibleResult object
242 public AnsibleResult parsePostResponse(String Input) throws APPCException{
244 AnsibleResult ansibleResult = new AnsibleResult();
248 JSONObject postResponse = new JSONObject(Input);
250 // Mandatory keys required are StatusCode and StatusMessage
251 int Code = postResponse.getInt("StatusCode");
252 String Message = postResponse.getString("StatusMessage");
255 // Status code must must be either 100 (accepted) or 101 (rejected)
256 boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.INITRESPONSE.getValue(), Code);
258 throw new APPCException("Invalid InitResponse code = " + Code + " received. MUST be one of " + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.INITRESPONSE.getValue()) );
261 ansibleResult.setStatusCode(Code);
262 ansibleResult.setStatusMessage(Message);
265 catch(JSONException e){
266 ansibleResult = new AnsibleResult(600, "Error parsing response = " + Input + ". Error = " + e.getMessage(), "");
270 return ansibleResult;
274 /** This method parses response from an Ansible server when we do a GET for a result
275 and returns an AnsibleResult object
277 public AnsibleResult parseGetResponse(String Input) throws APPCException {
279 AnsibleResult ansibleResult = new AnsibleResult();
280 int FinalCode = AnsibleResultCodes.FINAL_SUCCESS.getValue();
286 JSONObject postResponse = new JSONObject(Input);
288 // Mandatory keys required are Status and Message
289 int Code = postResponse.getInt("StatusCode");
290 String Message = postResponse.getString("StatusMessage");
292 // Status code must be valid
293 // Status code must must be either 100 (accepted) or 101 (rejected)
294 boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.FINALRESPONSE.getValue(), Code);
297 throw new APPCException("Invalid FinalResponse code = " + Code + " received. MUST be one of " + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.FINALRESPONSE.getValue()));
301 ansibleResult.setStatusCode(Code);
302 ansibleResult.setStatusMessage(Message);
303 System.out.println("Received response with code = " + Integer.toString(Code) + " Message = " + Message);
305 if(! postResponse.isNull("Results")){
307 // Results are available. process them
308 // Results is a dictionary of the form
309 // {host :{status:s, group:g, message:m, hostname:h}, ...}
310 System.out.println("Processing results in response");
311 JSONObject results = postResponse.getJSONObject("Results");
312 System.out.println("Get JSON dictionary from Results ..");
313 Iterator<String> hosts = results.keys();
314 System.out.println("Iterating through hosts");
316 while(hosts.hasNext()){
317 String host = hosts.next();
318 System.out.println("Processing host = " + host);
321 JSONObject host_response = results.getJSONObject(host);
322 int subCode = host_response.getInt("StatusCode");
323 String message = host_response.getString("StatusMessage");
325 System.out.println("Code = " + Integer.toString(subCode) + " Message = " + message);
327 if(subCode != 200 || ! message.equals("SUCCESS")){
328 FinalCode = AnsibleResultCodes.REQ_FAILURE.getValue();
331 catch(JSONException e){
332 ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
333 ansibleResult.setStatusMessage(String.format("Error processing response message = %s from host %s", results.getString(host), host));
338 ansibleResult.setStatusCode(FinalCode);
340 // We return entire Results object as message
341 ansibleResult.setResults(results.toString());
345 ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
346 ansibleResult.setStatusMessage("Results not found in GET for response");
351 catch(JSONException e){
352 ansibleResult = new AnsibleResult(AnsibleResultCodes.INVALID_PAYLOAD.getValue(), "Error parsing response = " + Input + ". Error = " + e.getMessage(), "");
356 return ansibleResult;