8d754e7916d8804b8717334b210f44a9d1cb772b
[appc.git] / appc-adapters / appc-chef-adapter / appc-chef-adapter-bundle / src / main / java / org / onap / appc / adapter / chef / impl / ChefAdapterImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
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
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  * ============LICENSE_END=========================================================
21  */
22 package org.onap.appc.adapter.chef.impl;
23
24 import com.att.eelf.configuration.EELFLogger;
25 import com.att.eelf.configuration.EELFManager;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import org.apache.commons.lang.StringUtils;
31 import org.json.JSONException;
32 import org.json.JSONObject;
33 import org.onap.appc.adapter.chef.ChefAdapter;
34 import org.onap.appc.adapter.chef.chefclient.ChefApiClientFactory;
35 import org.onap.appc.adapter.chef.chefclient.api.ChefApiClient;
36 import org.onap.appc.adapter.chef.chefclient.api.ChefResponse;
37 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
38 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
39
40 /**
41  * This class implements the {@link ChefAdapter} interface. This interface
42  * defines the behaviors that our service provides.
43  */
44 public class ChefAdapterImpl implements ChefAdapter {
45
46     // chef server Initialize variable
47     private String username = StringUtils.EMPTY;
48     private String clientPrivatekey = StringUtils.EMPTY;
49     private String chefserver = StringUtils.EMPTY;
50     private String serverAddress = StringUtils.EMPTY;
51     private String organizations = StringUtils.EMPTY;
52
53     @SuppressWarnings("nls")
54     public static final String MDC_ADAPTER = "adapter";
55
56     @SuppressWarnings("nls")
57     public static final String MDC_SERVICE = "service";
58
59     @SuppressWarnings("nls")
60     public static final String OUTCOME_FAILURE = "failure";
61
62     @SuppressWarnings("nls")
63     public static final String OUTCOME_SUCCESS = "success";
64
65     @SuppressWarnings("nls")
66     public static final String PROPERTY_PROVIDER = "provider";
67
68     @SuppressWarnings("nls")
69     public static final String PROPERTY_PROVIDER_IDENTITY = "identity";
70
71     @SuppressWarnings("nls")
72     public static final String PROPERTY_PROVIDER_NAME = "name";
73
74     @SuppressWarnings("nls")
75     public static final String PROPERTY_PROVIDER_TENANT = "tenant";
76
77     @SuppressWarnings("nls")
78     public static final String PROPERTY_PROVIDER_TENANT_NAME = "name";
79
80     @SuppressWarnings("nls")
81     public static final String PROPERTY_PROVIDER_TENANT_PASSWORD = "password"; // NOSONAR
82
83     @SuppressWarnings("nls")
84     public static final String PROPERTY_PROVIDER_TENANT_USERID = "userid";
85
86     @SuppressWarnings("nls")
87     public static final String PROPERTY_PROVIDER_TYPE = "type";
88
89     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ChefAdapterImpl.class);
90
91     private static final String CANNOT_FIND_PRIVATE_KEY_STR = "Cannot find the private key in the APPC file system, please load the private key to ";
92
93     private static final String POSTING_REQUEST_JSON_ERROR_STR = "Error posting request due to invalid JSON block: ";
94     private static final String POSTING_REQUEST_ERROR_STR = "Error posting request: ";
95     private static final String CHEF_CLIENT_RESULT_CODE_STR = "chefClientResult.code";
96     private static final String CHEF_SERVER_RESULT_CODE_STR = "chefServerResult.code";
97     private static final String CHEF_CLIENT_RESULT_MSG_STR = "chefClientResult.message";
98     private static final String CHEF_SERVER_RESULT_MSG_STR = "chefServerResult.message";
99     private static final String CHEF_ACTION_STR = "chefAction";
100     private static final String NODE_LIST_STR = "NodeList";
101     private static final Integer STATUS_OK = 200;
102     private static final Integer STATUS_PUSHJOBCHECK = 201;
103     private static final Integer PUSHJOBSTATUS= 202;
104     private static final Integer KEY_NOTFOUND = 500;
105     private static final Integer NO_ENVIRONMENT = 404;
106     private static final Integer APPC_ERRORCODE = 401;
107
108     private final ChefApiClientFactory chefApiClientFactory;
109     private final PrivateKeyChecker privateKeyChecker;
110
111     ChefAdapterImpl(ChefApiClientFactory chefApiClientFactory, PrivateKeyChecker privateKeyChecker) {
112         this.chefApiClientFactory = chefApiClientFactory;
113         this.privateKeyChecker = privateKeyChecker;
114         logger.info("Initialize Chef Adapter");
115     }
116
117     @SuppressWarnings("nls")
118     @Override
119     public void vnfcEnvironment(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
120         int code;
121         logger.info("environment of VNF-C");
122         chefInfo(params, ctx);
123         String env = params.get("Environment");
124         logger.info("Environmnet" + env);
125         if (env.equals(StringUtils.EMPTY)) {
126             chefServerResult(ctx, STATUS_OK, "Skip Environment block ");
127         } else {
128             String message;
129             if (privateKeyChecker.doesExist(clientPrivatekey)) {
130                 try {
131                     JSONObject envJ = new JSONObject(env);
132                     String envName = envJ.getString("name");
133                     // update the details of an environment on the Chef server.
134                     ChefApiClient chefApiClient = chefApiClientFactory.create(chefserver, organizations, username,
135                             clientPrivatekey);
136                     ChefResponse chefResponse = chefApiClient.put("/environments/" + envName, env);
137                     code = chefResponse.getStatusCode();
138                     message = chefResponse.getBody();
139                     if (code == NO_ENVIRONMENT) {
140                         // need create a new environment
141                         chefResponse = chefApiClient.post("/environments", env);
142                         code = chefResponse.getStatusCode();
143                         message = chefResponse.getBody();
144                         logger.info("requestbody {}", chefResponse.getBody());
145                     }
146                     chefServerResult(ctx, code, message);
147                 } catch (JSONException e) {
148                     code = APPC_ERRORCODE;
149                     logger.error(POSTING_REQUEST_JSON_ERROR_STR, e);
150                     doFailure(ctx, code, POSTING_REQUEST_JSON_ERROR_STR + e.getMessage());
151                 } catch (Exception e) {
152                     code = APPC_ERRORCODE;
153                     logger.error(POSTING_REQUEST_ERROR_STR + "vnfcEnvironment", e);
154                     doFailure(ctx, code, POSTING_REQUEST_ERROR_STR + "vnfcEnvironment" + e.getMessage());
155                 }
156             } else {
157                 code = KEY_NOTFOUND;
158                 message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
159                 doFailure(ctx, code, message);
160             }
161         }
162     }
163
164     @SuppressWarnings("nls")
165     @Override
166     public void vnfcNodeobjects(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
167         logger.info("update the nodeObjects of VNF-C");
168         int code;
169         try {
170             chefInfo(params, ctx);
171             String nodeListS = params.get(NODE_LIST_STR);
172             String nodeS = params.get("Node");
173             if (StringUtils.isNotBlank(nodeListS) && StringUtils.isNotBlank(nodeS)) {
174                 nodeListS = nodeListS.replace("[", StringUtils.EMPTY);
175                 nodeListS = nodeListS.replace("]", StringUtils.EMPTY);
176                 nodeListS = nodeListS.replace("\"", StringUtils.EMPTY);
177                 nodeListS = nodeListS.replace(" ", StringUtils.EMPTY);
178                 List<String> nodes = Arrays.asList(nodeListS.split("\\s*,\\s*"));
179                 code = STATUS_OK;
180                 String message = null;
181                 if (privateKeyChecker.doesExist(clientPrivatekey)) {
182                     ChefApiClient cac = chefApiClientFactory.create(chefserver, organizations, username,
183                             clientPrivatekey);
184
185                     for (String nodeName : nodes) {
186                         JSONObject nodeJ = new JSONObject(nodeS);
187                         nodeJ.remove("name");
188                         nodeJ.put("name", nodeName);
189                         String nodeObject = nodeJ.toString();
190                         logger.info(nodeObject);
191                         ChefResponse chefResponse = cac.put("/nodes/" + nodeName, nodeObject);
192                         code = chefResponse.getStatusCode();
193                         message = chefResponse.getBody();
194                         if (code != STATUS_OK) {
195                             break;
196                         }
197                     }
198                 } else {
199                     code = KEY_NOTFOUND;
200                     message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
201                     doFailure(ctx, code, message);
202                 }
203                 chefServerResult(ctx, code, message);
204             } else {
205                 throw new SvcLogicException("Missing Mandatory param(s) Node , NodeList ");
206             }
207         } catch (JSONException e) {
208             code = APPC_ERRORCODE;
209             logger.error(POSTING_REQUEST_JSON_ERROR_STR + "vnfcNodeobjects", e);
210             doFailure(ctx, code, POSTING_REQUEST_JSON_ERROR_STR + "vnfcNodeobjects" + e.getMessage());
211         } catch (Exception e) {
212             code = APPC_ERRORCODE;
213             logger.error(POSTING_REQUEST_ERROR_STR + "vnfcNodeobjects", e);
214             doFailure(ctx, code, POSTING_REQUEST_ERROR_STR + "vnfcNodeobjects" + e.getMessage());
215         }
216     }
217
218     @Override
219     public void vnfcPushJob(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
220         int code;
221         try {
222             chefInfo(params, ctx);
223             String nodeList = params.get(NODE_LIST_STR);
224             if (StringUtils.isNotBlank(nodeList)) {
225                 String isCallback = params.get("CallbackCapable");
226                 String chefAction = "/pushy/jobs";
227                 // need work on this
228                 String pushRequest;
229                 if ("true".equals(isCallback)) {
230                     String requestId = params.get("RequestId");
231                     String callbackUrl = params.get("CallbackUrl");
232                     pushRequest = "{" + "\"command\": \"chef-client\"," + "\"run_timeout\": 300," + "\"nodes\":"
233                             + nodeList + "," + "\"env\": {\"RequestId\": \"" + requestId + "\", \"CallbackUrl\": \""
234                             + callbackUrl + "\"}," + "\"capture_output\": true" + "}";
235                 } else {
236                     pushRequest = "{" + "\"command\": \"chef-client\"," + "\"run_timeout\": 300," + "\"nodes\":"
237                             + nodeList + "," + "\"env\": {}," + "\"capture_output\": true" + "}";
238                 }
239                 ChefApiClient cac = chefApiClientFactory.create(chefserver, organizations, username, clientPrivatekey);
240                 ChefResponse chefResponse = cac.post(chefAction, pushRequest);
241                 code = chefResponse.getStatusCode();
242                 logger.info("pushRequest:" + pushRequest);
243                 logger.info("requestbody: {}", chefResponse.getBody());
244                 String message = chefResponse.getBody();
245                 if (code == STATUS_PUSHJOBCHECK) {
246                     int startIndex = message.indexOf("jobs") + 5;
247                     int endIndex = message.length() - 2;
248                     String jobID = message.substring(startIndex, endIndex);
249                     ctx.setAttribute("jobID", jobID);
250                     logger.info(jobID);
251                 }
252                 chefServerResult(ctx, code, message);
253             } else {
254                 throw new SvcLogicException("Missing Mandatory param(s)  NodeList ");
255             }
256         } catch (Exception e) {
257             code = APPC_ERRORCODE;
258             logger.error(POSTING_REQUEST_ERROR_STR + "vnfcPushJob", e);
259             doFailure(ctx, code, POSTING_REQUEST_ERROR_STR + "vnfcPushJob" + e.getMessage());
260         }
261     }
262
263     @SuppressWarnings("nls")
264     @Override
265     public void fetchResults(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
266         int code = STATUS_OK;
267         try {
268             chefInfo(params, ctx);
269             String nodeListS = params.get(NODE_LIST_STR);
270             if (StringUtils.isNotBlank(nodeListS)) {
271                 nodeListS = nodeListS.replace("[", StringUtils.EMPTY);
272                 nodeListS = nodeListS.replace("]", StringUtils.EMPTY);
273                 nodeListS = nodeListS.replace("\"", StringUtils.EMPTY);
274                 nodeListS = nodeListS.replace(" ", StringUtils.EMPTY);
275                 List<String> nodes = Arrays.asList(nodeListS.split("\\s*,\\s*"));
276                 JSONObject result = new JSONObject();
277                 String returnMessage = StringUtils.EMPTY;
278
279                 for (String node : nodes) {
280                     String chefAction = "/nodes/" + node;
281                     String message;
282                     if (privateKeyChecker.doesExist(clientPrivatekey)) {
283                         ChefResponse chefResponse = getApiMethod(chefAction);
284                         code = chefResponse.getStatusCode();
285                         message = chefResponse.getBody();
286                     } else {
287                         code = KEY_NOTFOUND;
288                         message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
289                         doFailure(ctx, code, message);
290                     }
291                     if (code == STATUS_OK) {
292                         JSONObject nodeResult = new JSONObject();
293                         JSONObject allNodeData = new JSONObject(message);
294                         allNodeData = allNodeData.getJSONObject("normal");
295                         String attribute = "PushJobOutput";
296
297                         String resultData = allNodeData.optString(attribute, null);
298                         if (resultData == null) {
299                             resultData = Optional.ofNullable(allNodeData.optJSONObject(attribute))
300                                     .map(p -> p.toString()).orElse(null);
301                             if (resultData == null) {
302                                 resultData = Optional.ofNullable(allNodeData.optJSONArray(attribute))
303                                         .map(p -> p.toString()).orElse(null);
304
305                                 if (resultData == null) {
306                                     code = KEY_NOTFOUND;
307                                     returnMessage = "Cannot find " + attribute;
308                                     break;
309                                 }
310                             }
311                         }
312                         nodeResult.put(attribute, resultData);
313                         result.put(node, nodeResult);
314                         returnMessage = result.toString();
315                     } else {
316                         code = KEY_NOTFOUND;
317                         returnMessage = message + " Cannot access: " + node;
318                         doFailure(ctx, code, message);
319                         break;
320                     }
321                 }
322
323                 chefServerResult(ctx, code, returnMessage);
324             } else {
325                 throw new SvcLogicException("Missing Mandatory param(s)  NodeList ");
326             }
327         } catch (JSONException e) {
328             code = APPC_ERRORCODE;
329             logger.error(POSTING_REQUEST_JSON_ERROR_STR + "fetchResults", e);
330             doFailure(ctx, code, POSTING_REQUEST_JSON_ERROR_STR + "fetchResults" + e.getMessage());
331         } catch (Exception e) {
332             code = APPC_ERRORCODE;
333             logger.error(POSTING_REQUEST_ERROR_STR + "fetchResults", e);
334             doFailure(ctx, code, POSTING_REQUEST_ERROR_STR + "fetchResults" + e.getMessage());
335         }
336     }
337
338     private ChefResponse getApiMethod(String chefAction) {
339         ChefApiClient cac = chefApiClientFactory.create(chefserver, organizations, username, clientPrivatekey);
340         return cac.get(chefAction);
341     }
342
343     /**
344      * build node object
345      */
346     @SuppressWarnings("nls")
347     @Override
348     public void nodeObejctBuilder(Map<String, String> params, SvcLogicContext ctx) {
349         logger.info("nodeObejctBuilder");
350         String name = params.get("nodeobject.name");
351         String normal = params.get("nodeobject.normal");
352         String overrides = params.get("nodeobject.overrides");
353         String defaults = params.get("nodeobject.defaults");
354         String runList = params.get("nodeobject.run_list");
355         String chefEnvironment = params.get("nodeobject.chef_environment");
356         String nodeObject = "{\"json_class\":\"Chef::Node\",\"default\":{" + defaults
357                 + "},\"chef_type\":\"node\",\"run_list\":[" + runList + "],\"override\":{" + overrides
358                 + "},\"normal\": {" + normal + "},\"automatic\":{},\"name\":\"" + name + "\",\"chef_environment\":\""
359                 + chefEnvironment + "\",}";
360         logger.info(nodeObject);
361         ctx.setAttribute("chef.nodeObject", nodeObject);
362     }
363
364     /**
365      * send get request to chef server
366      */
367     private void chefInfo(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
368
369         username = params.get("username");
370         serverAddress = params.get("serverAddress");
371         organizations = params.get("organizations");
372         if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(serverAddress)
373                 && StringUtils.isNotBlank(organizations)) {
374             chefserver = "https://" + serverAddress + "/organizations/" + organizations;
375             clientPrivatekey = "/opt/onap/appc/chef/" + serverAddress + "/" + organizations + "/" + username + ".pem";
376             logger.info(" clientPrivatekey  " + clientPrivatekey);
377         } else {
378             doFailure(ctx, APPC_ERRORCODE, "Missing mandatory param(s) such as username, serverAddress, organizations");
379         }
380     }
381
382     @SuppressWarnings("nls")
383     @Override
384     public void retrieveData(Map<String, String> params, SvcLogicContext ctx) {
385         String allConfigData = params.get("allConfig");
386         String key = params.get("key");
387         String dgContext = params.get("dgContext");
388         JSONObject jsonConfig = new JSONObject(allConfigData);
389         String contextData = fetchContextData(key, jsonConfig);
390         ctx.setAttribute(dgContext, contextData);
391     }
392
393     private String fetchContextData(String key, JSONObject jsonConfig) {
394         try {
395             return jsonConfig.getString(key);
396         } catch (Exception e) {
397             logger.error("Failed getting string value corresponding to " + key + ". Trying to fetch nested json object",
398                     e);
399             try {
400                 return jsonConfig.getJSONObject(key).toString();
401             } catch (Exception ex) {
402                 logger.error("Failed getting json object corresponding to " + key + ". Trying to fetch array", ex);
403                 return jsonConfig.getJSONArray(key).toString();
404             }
405         }
406     }
407
408     @SuppressWarnings("nls")
409     @Override
410     public void combineStrings(Map<String, String> params, SvcLogicContext ctx) {
411         String string1 = params.get("String1");
412         String string2 = params.get("String2");
413         String dgContext = params.get("dgContext");
414         String contextData = string1 + string2;
415         ctx.setAttribute(dgContext, contextData);
416     }
417
418     /**
419      * Send GET request to chef server
420      */
421     @SuppressWarnings("nls")
422
423     @Override
424     public void chefGet(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
425         logger.info("chef get method");
426         chefInfo(params, ctx);
427         String chefAction = params.get(CHEF_ACTION_STR);
428         int code;
429         String message;
430         if (privateKeyChecker.doesExist(clientPrivatekey)) {
431             ChefResponse chefResponse = getApiMethod(chefAction);
432             code = chefResponse.getStatusCode();
433             message = chefResponse.getBody();
434         } else {
435             code = KEY_NOTFOUND;
436             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
437         }
438         chefServerResult(ctx, code, message);
439     }
440
441     /**
442      * Send PUT request to chef server
443      */
444     @SuppressWarnings("nls")
445
446     @Override
447     public void chefPut(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
448         chefInfo(params, ctx);
449         String chefAction = params.get(CHEF_ACTION_STR);
450         String chefNodeStr = params.get("chefRequestBody");
451         int code;
452         String message;
453         if (privateKeyChecker.doesExist(clientPrivatekey)) {
454             ChefApiClient chefApiClient = chefApiClientFactory.create(chefserver, organizations, username,
455                     clientPrivatekey);
456             ChefResponse chefResponse = chefApiClient.put(chefAction, chefNodeStr);
457             code = chefResponse.getStatusCode();
458             message = chefResponse.getBody();
459         } else {
460             code = KEY_NOTFOUND;
461             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
462         }
463         logger.info(code + "   " + message);
464         chefServerResult(ctx, code, message);
465     }
466
467     /**
468      * send Post request to chef server
469      */
470     @Override
471     public void chefPost(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
472         chefInfo(params, ctx);
473         logger.info("chef Post method");
474         logger.info(username + " " + clientPrivatekey + " " + chefserver + " " + organizations);
475         String chefNodeStr = params.get("chefRequestBody");
476         String chefAction = params.get(CHEF_ACTION_STR);
477         int code;
478         String message;
479         // should load pem from somewhere else
480         if (privateKeyChecker.doesExist(clientPrivatekey)) {
481             ChefApiClient chefApiClient = chefApiClientFactory.create(chefserver, organizations, username,
482                     clientPrivatekey);
483             // need pass path into it
484             // "/nodes/testnode"
485             ChefResponse chefResponse = chefApiClient.post(chefAction, chefNodeStr);
486             code = chefResponse.getStatusCode();
487             message = chefResponse.getBody();
488         } else {
489             code = KEY_NOTFOUND;
490             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
491         }
492         logger.info(code + "   " + message);
493         chefServerResult(ctx, code, message);
494     }
495
496     /**
497      * send delete request to chef server
498      */
499     @Override
500     public void chefDelete(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
501         logger.info("chef delete method");
502         chefInfo(params, ctx);
503         String chefAction = params.get(CHEF_ACTION_STR);
504         int code;
505         String message;
506         if (privateKeyChecker.doesExist(clientPrivatekey)) {
507             ChefApiClient chefApiClient = chefApiClientFactory.create(chefserver, organizations, username,
508                     clientPrivatekey);
509             ChefResponse chefResponse = chefApiClient.delete(chefAction);
510             code = chefResponse.getStatusCode();
511             message = chefResponse.getBody();
512         } else {
513             code = KEY_NOTFOUND;
514             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
515         }
516         logger.info(code + "   " + message);
517         chefServerResult(ctx, code, message);
518     }
519
520     /**
521      * Trigger target vm run chef
522      */
523     @Override
524     public void trigger(Map<String, String> params, SvcLogicContext svcLogicContext) {
525         logger.info("Run trigger method");
526         String tVmIp = params.get("ip");
527         try {
528             ChefResponse chefResponse = chefApiClientFactory.create(tVmIp, organizations).get("");
529             chefClientResult(svcLogicContext, chefResponse.getStatusCode(), chefResponse.getBody());
530             svcLogicContext.setAttribute("chefAgent.code", STATUS_OK.toString());
531         } catch (Exception e) {
532             logger.error("An error occurred when executing trigger method", e);
533             svcLogicContext.setAttribute("chefAgent.code", KEY_NOTFOUND.toString());
534             svcLogicContext.setAttribute("chefAgent.message", e.toString());
535         }
536     }
537
538     @SuppressWarnings("nls")
539     @Override
540     public void checkPushJob(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
541         int code;
542         try {
543             chefInfo(params, ctx);
544             String jobID = params.get("jobid");
545             String retry = params.get("retryTimes");
546             String intrva = params.get("retryInterval");
547             if (StringUtils.isNotBlank(jobID) && StringUtils.isNotBlank(retry) && StringUtils.isNotBlank(intrva)) {
548
549                 int retryTimes = Integer.parseInt(params.get("retryTimes"));
550                 int retryInterval = Integer.parseInt(params.get("retryInterval"));
551                 String chefAction = "/pushy/jobs/" + jobID;
552                 String message = StringUtils.EMPTY;
553                 String status = StringUtils.EMPTY;
554                 for (int i = 0; i < retryTimes; i++) {
555                     sleepFor(retryInterval);
556                     ChefResponse chefResponse = getApiMethod(chefAction);
557                     code = chefResponse.getStatusCode();
558                     message = chefResponse.getBody();
559                     JSONObject obj = new JSONObject(message);
560                     status = obj.getString("status");
561                     if (!"running".equals(status)) {
562                         logger.info(i + " time " + code + "   " + status);
563                         break;
564                     }
565                 }
566                 resolveSvcLogicAttributes(ctx, message, status);
567             } else {
568                 throw new SvcLogicException("Missing Mandatory param(s) retryTimes , retryInterval ");
569             }
570         } catch (Exception e) {
571             code = APPC_ERRORCODE;
572             logger.error("An error occurred when executing checkPushJob method", e);
573             doFailure(ctx, code, e.getMessage());
574         }
575     }
576
577     private void resolveSvcLogicAttributes(SvcLogicContext svcLogic, String message, String status)   {
578         if ("complete".equals(status)) {
579             if (hasFailedNode(message)) {
580                 String finalMessage = "PushJob Status Complete but check failed nodes in the message :" + message;
581                 svcLogic.setAttribute("chefServerResult.code", APPC_ERRORCODE.toString());
582                 svcLogic.setAttribute("chefServerResult.message", finalMessage);
583             } else {
584                 svcLogic.setAttribute(CHEF_SERVER_RESULT_CODE_STR, STATUS_OK.toString());
585                 svcLogic.setAttribute(CHEF_SERVER_RESULT_MSG_STR, message);
586             }
587         } else if ("running".equals(status)) {
588             svcLogic.setAttribute(CHEF_SERVER_RESULT_CODE_STR, PUSHJOBSTATUS.toString());
589             svcLogic.setAttribute(CHEF_SERVER_RESULT_MSG_STR, "chef client runtime out");
590         } else {
591             svcLogic.setAttribute(CHEF_SERVER_RESULT_CODE_STR, KEY_NOTFOUND.toString());
592             svcLogic.setAttribute(CHEF_SERVER_RESULT_MSG_STR, message);
593         }
594     }
595
596     private Boolean hasFailedNode(String message) throws JSONException {
597         try {   
598             JSONObject messageJson = new JSONObject(message);
599             JSONObject node = messageJson.getJSONObject("nodes");
600             if (node == null) {
601                 logger.debug("Status Complete but node details in the message is null : " + message);
602                 return Boolean.TRUE;
603             }
604             if (node.has("failed") && !(node.isNull("failed")) && (node.getJSONArray("failed").length() != 0)) {
605                 logger.debug("Status Complete but one or more Failed nodes ....FAILURE " + message);
606                 return Boolean.TRUE;
607             }
608             logger.debug("Status Complete and no failed nodes ....SUCCESS " + message);
609             return Boolean.FALSE;
610         } catch (JSONException e) {
611             logger.error("Exception occured in hasFailedNode", e);
612             throw new JSONException("Exception occured in hasFailedNode" + e.getMessage());
613         }
614
615     }
616
617     private void sleepFor(int retryInterval) {
618         try {
619             Thread.sleep(retryInterval); // 1000 milliseconds is one second.
620         } catch (InterruptedException ex) {
621             Thread.currentThread().interrupt();
622         }
623     }
624
625     @SuppressWarnings("nls")
626     @Override
627     public void pushJob(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
628         int code;
629         try {
630             chefInfo(params, ctx);
631             String pushRequest = params.get("pushRequest");
632             String chefAction = "/pushy/jobs";
633             ChefApiClient chefApiClient = chefApiClientFactory.create(chefserver, organizations, username,
634                     clientPrivatekey);
635             ChefResponse chefResponse = chefApiClient.post(chefAction, pushRequest);
636             code = chefResponse.getStatusCode();
637             String message = chefResponse.getBody();
638             if (code == STATUS_PUSHJOBCHECK) {
639                 int startIndex = message.indexOf("jobs") + 6;
640                 int endIndex = message.length() - 2;
641                 String jobID = message.substring(startIndex, endIndex);
642                 ctx.setAttribute("jobID", jobID);
643                 logger.info(jobID);
644             }
645             chefServerResult(ctx, code, message);
646         } catch (Exception e) {
647             code = APPC_ERRORCODE;
648             logger.error("An error occurred when executing pushJob method", e);
649             doFailure(ctx, code, e.getMessage());
650         }
651     }
652
653     @SuppressWarnings("static-method")
654     private void chefServerResult(SvcLogicContext svcLogicContext, int code, String message) {
655         initSvcLogic(svcLogicContext, code, message, "server");
656     }
657
658     @SuppressWarnings("static-method")
659     private void chefClientResult(SvcLogicContext svcLogicContext, int code, String message) {
660         initSvcLogic(svcLogicContext, code, message, "client");
661     }
662
663     private void initSvcLogic(SvcLogicContext svcLogicContext, int code, String message, String target) {
664
665         String codeStr = "server".equals(target) ? CHEF_SERVER_RESULT_CODE_STR : CHEF_CLIENT_RESULT_CODE_STR;
666         String messageStr = "client".equals(target) ? CHEF_CLIENT_RESULT_MSG_STR : CHEF_SERVER_RESULT_MSG_STR;
667         svcLogicContext.setStatus(OUTCOME_SUCCESS);
668         svcLogicContext.setAttribute(codeStr, Integer.toString(code));
669         svcLogicContext.setAttribute(messageStr, message);
670         logger.info(codeStr + ": " + svcLogicContext.getAttribute(codeStr));
671         logger.info(messageStr + ": " + svcLogicContext.getAttribute(messageStr));
672     }
673
674     @SuppressWarnings("static-method")
675     private void doFailure(SvcLogicContext svcLogic, int code, String message) throws SvcLogicException {
676
677         String cutMessage = message.contains("\n") ? message.substring(message.indexOf('\n')) : message;
678         svcLogic.setStatus(OUTCOME_FAILURE);
679         svcLogic.setAttribute(CHEF_SERVER_RESULT_CODE_STR, Integer.toString(code));
680         svcLogic.setAttribute(CHEF_SERVER_RESULT_MSG_STR, cutMessage);
681         throw new SvcLogicException("Chef Adapter error:" + cutMessage);
682     }
683 }