First part of onap rename
[appc.git] / appc-adapters / appc-ansible-adapter / appc-ansible-adapter-bundle / src / main / java / org / openecomp / appc / adapter / ansible / model / AnsibleMessageParser.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
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
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
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.
20  * 
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.appc.adapter.ansible.model;
26
27 /**
28  * This module imples the APP-C/Ansible Server interface
29  * based on the REST API specifications
30  */
31
32 import java.lang.NumberFormatException ;
33 import java.util.*;
34 import com.google.common.base.Strings;
35
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;
41
42
43 /**
44  * Class that validates and constructs requests sent/received from 
45  * Ansible Server
46  *
47  */
48 public class AnsibleMessageParser {
49
50
51
52
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{
58
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)
62         // 3. Playbook name
63         String[] mandatoryTestParams = {"AgentUrl", "PlaybookName", "User", "Password"};
64
65         // Optional testService parameters that may be provided in the request
66         String[] optionalTestParams = {"EnvParameters", "NodeList", "LocalParameters", "Timeout", "Version", "FileParameters", "Action"};
67
68         JSONObject JsonPayload = new JSONObject();
69         String payload = "";
70         JSONObject paramsJson;
71
72   
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));
77             }
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));
81             }
82             
83             JsonPayload.put(key, payload);
84         }
85
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)){
92                     
93                     // different cases require different treatment
94                     switch (key){
95                     case "Timeout": 
96                         int Timeout = Integer.parseInt(payload);
97                         if (Timeout < 0){
98                             throw new NumberFormatException(" : specified negative integer for timeout = " +  payload);
99                         }
100                         JsonPayload.put(key, payload);
101                         break;
102
103                     case "Version": 
104                         JsonPayload.put(key, payload);
105                         break;
106
107                     case "LocalParameters":  
108                         paramsJson = new JSONObject(payload);
109                         JsonPayload.put(key, paramsJson);
110                         break;
111                         
112                     case "EnvParameters":  
113                         paramsJson = new JSONObject(payload);
114                         JsonPayload.put(key, paramsJson);
115                         break;
116                         
117                     case "NodeList":  
118                         JSONArray paramsArray = new JSONArray(payload);
119                         JsonPayload.put(key, paramsArray);
120                         break;
121                         
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);
127                         break;
128                         
129                     }
130                 }
131             }
132         }
133         
134
135         // Generate a unique uuid for the test
136         String ReqId = UUID.randomUUID().toString();
137         JsonPayload.put("Id", ReqId);
138
139         return JsonPayload;
140         
141     }
142
143
144
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{
149         
150         // Mandatory  parameters, that must be in the request
151         String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
152         
153         // Verify all the mandatory parameters are there
154         String payload = "";
155         String Uri = "";
156         
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));                
160             }
161
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));                
165             }
166
167         }
168
169         Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetResult";
170
171         return Uri;
172       
173     }
174
175
176
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{
181         
182         
183         // Mandatory  parameters, that must be in the request
184         String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
185         
186         // Verify all the mandatory parameters are there
187         String payload = "";
188         String Uri = "";
189         
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));                
193             }
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));                
197             }
198
199         }
200
201         Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetOutput";
202         return Uri;
203       
204     }
205
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{
210         
211         
212         // Mandatory  parameters, that must be in the request
213         String[] mandatoryTestParams = {"AgentUrl", "Id", "User", "Password" };
214         
215         // Verify all the mandatory parameters are there
216         String payload = "";
217         String Uri = "";
218         
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));                
222             }
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));                
226             }
227
228         }
229
230         Uri = params.get("AgentUrl") + "?Id=" + params.get("Id") + "&Type=GetLog";
231         return Uri;
232       
233     }
234
235    
236     /** 
237         This method parses response from the 
238         Ansible Server when we do a post 
239         and returns an AnsibleResult object
240     **/
241     
242     public AnsibleResult  parsePostResponse(String Input) throws APPCException{
243
244         AnsibleResult ansibleResult = new AnsibleResult();
245         
246         try{
247             //Jsonify it
248             JSONObject  postResponse = new JSONObject(Input);
249                 
250             // Mandatory keys required are StatusCode and StatusMessage
251             int Code = postResponse.getInt("StatusCode");
252             String Message = postResponse.getString("StatusMessage");
253
254             
255             // Status code must must be either 100 (accepted) or 101 (rejected)
256             boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.INITRESPONSE.getValue(), Code);
257             if(!valCode){
258                 throw new APPCException("Invalid InitResponse code  = " + Code + " received. MUST be one of " + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.INITRESPONSE.getValue()) );
259             }
260             
261             ansibleResult.setStatusCode(Code);
262             ansibleResult.setStatusMessage(Message);
263
264         }
265         catch(JSONException e){
266             ansibleResult = new AnsibleResult(600, "Error parsing response = " + Input + ". Error = " + e.getMessage(), "");
267         }
268
269         
270         return ansibleResult;
271     }
272
273
274     /** This method  parses response from an Ansible server when we do a GET for a result 
275         and returns an AnsibleResult object
276      **/
277     public AnsibleResult  parseGetResponse(String Input) throws APPCException {
278
279         AnsibleResult ansibleResult = new AnsibleResult();
280         int FinalCode = AnsibleResultCodes.FINAL_SUCCESS.getValue();
281
282
283         try{
284             
285             //Jsonify it
286             JSONObject  postResponse = new JSONObject(Input);
287             
288             // Mandatory keys required are Status and Message
289             int Code = postResponse.getInt("StatusCode");
290             String Message = postResponse.getString("StatusMessage");
291             
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);
295             
296             if(!valCode){
297                 throw new APPCException("Invalid FinalResponse code  = " + Code + " received. MUST be one of " + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.FINALRESPONSE.getValue()));
298             }
299
300             
301             ansibleResult.setStatusCode(Code);
302             ansibleResult.setStatusMessage(Message);
303             System.out.println("Received response with code = " + Integer.toString(Code) + " Message = " + Message);
304
305             if(! postResponse.isNull("Results")){
306
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");
315                 
316                 while(hosts.hasNext()){
317                     String host = hosts.next();
318                     System.out.println("Processing host = " + host);
319                     
320                     try{
321                         JSONObject host_response = results.getJSONObject(host);
322                         int subCode = host_response.getInt("StatusCode");
323                         String message = host_response.getString("StatusMessage");
324
325                         System.out.println("Code = " + Integer.toString(subCode) + " Message = " + message);
326                         
327                         if(subCode != 200 || ! message.equals("SUCCESS")){
328                             FinalCode = AnsibleResultCodes.REQ_FAILURE.getValue();
329                         }
330                     }
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));
334                         break;
335                     }
336                 }
337
338                 ansibleResult.setStatusCode(FinalCode);
339
340                 // We return entire Results object as message
341                 ansibleResult.setResults(results.toString());
342
343             }
344             else{
345                 ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
346                 ansibleResult.setStatusMessage("Results not found in GET for response");
347             }
348             
349             
350         }
351         catch(JSONException e){
352             ansibleResult = new AnsibleResult(AnsibleResultCodes.INVALID_PAYLOAD.getValue(), "Error parsing response = " + Input + ". Error = " + e.getMessage(), "");
353         }
354
355
356         return ansibleResult;
357     }
358
359
360
361 };    
362             
363             
364