b81c10bc8d8f9b6b654a771ab2e09f8ed22743ac
[appc.git] / appc-adapters / appc-chef-adapter / appc-chef-adapter-bundle / src / main / java / org / openecomp / appc / adapter / chef / impl / ChefAdapterImpl.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.openecomp.appc.adapter.chef.impl;
26
27 import java.io.File;
28 import java.util.Map;
29
30 import org.apache.http.HttpEntity;
31 import org.apache.http.HttpResponse;
32 import org.apache.http.client.methods.HttpGet;
33 import org.apache.http.impl.client.CloseableHttpClient;
34 import org.apache.http.impl.client.HttpClients;
35 import org.apache.http.util.EntityUtils;
36 import org.json.JSONObject;
37 import org.openecomp.appc.Constants;
38 import org.openecomp.appc.adapter.chef.ChefAdapter;
39 import org.openecomp.appc.adapter.chef.chefapi.ApiMethod;
40 import org.openecomp.appc.adapter.chef.chefclient.ChefApiClient;
41 import org.openecomp.appc.configuration.Configuration;
42 import org.openecomp.appc.configuration.ConfigurationFactory;
43 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
44
45 import com.att.eelf.configuration.EELFLogger;
46 import com.att.eelf.configuration.EELFManager;
47
48 /**
49  * This class implements the {@link ChefAdapter} interface. This interface
50  * defines the behaviors that our service provides.
51  */
52 public class ChefAdapterImpl implements ChefAdapter {
53     // chef server Initialize variable
54     private String clientName = "";
55     private String clientPrivatekey = "";
56     private String chefserver = "";
57     private String serverAddress = "";
58     private String organizations = "";
59
60
61     /**
62      * The constant for the status code for a successful outcome
63      */
64     private static final String OUTCOME_SUCCESS = "success";
65
66     /**
67      * The logger to be used
68      */
69     private final EELFLogger logger = EELFManager.getInstance().getLogger(ChefAdapterImpl.class);
70
71     private final String CANNOT_FIND_PRIVATE_KEY_STR = "Cannot find the private key in the APPC file system, please load the private key to ";
72     private final String CHEF_ACTION_STR = "org.openecomp.appc.instance.chefAction";
73     private final String ORGANIZATIONS_STR = "/organizations/";
74     /**
75      * A reference to the adapter configuration object.
76      */
77     private Configuration configuration;
78
79     /**
80      * This default constructor is used as a work around because the activator wasnt
81      * getting called
82      */
83     public ChefAdapterImpl() {
84         initialize();
85     }
86
87     /**
88      * This constructor is used primarily in the test cases to bypass initialization
89      * of the adapter for isolated, disconnected testing
90      *
91      * @param initialize
92      *            True if the adapter is to be initialized, can false if not
93      */
94     public ChefAdapterImpl(boolean initialize) {
95         configuration = ConfigurationFactory.getConfiguration();
96         if (initialize) {
97             initialize();
98         }
99     }
100
101     public ChefAdapterImpl(String key) {
102         initialize(key);
103     }
104
105     /**
106      * Returns the symbolic name of the adapter
107      *
108      * @return The adapter name
109      * @see org.openecomp.appc.adapter.chef.ChefAdapter#getAdapterName()
110      */
111     @Override
112     public String getAdapterName() {
113         return configuration.getProperty(Constants.PROPERTY_ADAPTER_NAME);
114     }
115
116     /**
117      * build node object
118      */
119     @Override
120     public void nodeObejctBuilder(Map<String, String> params, SvcLogicContext ctx) {
121         logger.info("nodeObejctBuilder");
122         String name = params.get("org.openecomp.appc.instance.nodeobject.name");
123         String normal = params.get("org.openecomp.appc.instance.nodeobject.normal");
124         String overrides = params.get("org.openecomp.appc.instance.nodeobject.overrides");
125         String defaults = params.get("org.openecomp.appc.instance.nodeobject.defaults");
126         String runList = params.get("org.openecomp.appc.instance.nodeobject.run_list");
127         String chefEnvironment = params.get("org.openecomp.appc.instance.nodeobject.chef_environment");
128         String nodeObject = "{\"json_class\":\"Chef::Node\",\"default\":{" + defaults
129                 + "},\"chef_type\":\"node\",\"run_list\":[" + runList + "],\"override\":{" + overrides
130                 + "},\"normal\": {" + normal + "},\"automatic\":{},\"name\":\"" + name + "\",\"chef_environment\":\""
131                 + chefEnvironment + "\"}";
132         logger.info(nodeObject);
133
134         RequestContext rc = new RequestContext(ctx);
135         rc.isAlive();
136         SvcLogicContext svcLogic = rc.getSvcLogicContext();
137         svcLogic.setAttribute("org.openecomp.appc.chef.nodeObject", nodeObject);
138     }
139
140     /**
141      * send get request to chef server
142      */
143     public void chefInfo(Map<String, String> params) {
144         clientName = params.get("org.openecomp.appc.instance.username");
145         serverAddress = params.get("org.openecomp.appc.instance.serverAddress");
146         organizations = params.get("org.openecomp.appc.instance.organizations");
147         chefserver = "https://" + serverAddress + ORGANIZATIONS_STR + organizations;
148         clientPrivatekey = "/opt/app/bvc/chef/" + serverAddress + "/" + organizations + "/" + clientName + ".pem";
149     }
150
151     public Boolean privateKeyCheck() {
152         File f = new File(clientPrivatekey);
153         return f.exists();
154     }
155
156     @Override
157     public void retrieveData(Map<String, String> params, SvcLogicContext ctx) {
158         String allConfigData = params.get("org.openecomp.appc.instance.allConfig");
159         String key = params.get("org.openecomp.appc.instance.key");
160         String dgContext = params.get("org.openecomp.appc.instance.dgContext");
161         JSONObject josnConfig = new JSONObject(allConfigData);
162
163         String contextData;
164         try {
165             contextData = josnConfig.getString(key);
166         } catch (Exception ex) {
167             try {
168                 contextData = josnConfig.getJSONObject(key).toString();
169             } catch (Exception exc) {
170                 contextData = josnConfig.getJSONArray(key).toString();
171             }
172         }
173
174         RequestContext rc = new RequestContext(ctx);
175         rc.isAlive();
176         SvcLogicContext svcLogic = rc.getSvcLogicContext();
177         svcLogic.setAttribute(dgContext, contextData);
178     }
179
180     @Override
181     public void combineStrings(Map<String, String> params, SvcLogicContext ctx) {
182
183         String string1 = params.get("org.openecomp.appc.instance.String1");
184         String string2 = params.get("org.openecomp.appc.instance.String2");
185         String dgContext = params.get("org.openecomp.appc.instance.dgContext");
186         String contextData = string1 + string2;
187         RequestContext rc = new RequestContext(ctx);
188         rc.isAlive();
189         SvcLogicContext svcLogic = rc.getSvcLogicContext();
190         svcLogic.setAttribute(dgContext, contextData);
191     }
192
193     /**
194      * Send GET request to chef server
195      */
196     @Override
197     public void chefGet(Map<String, String> params, SvcLogicContext ctx) {
198         logger.info("chef get method");
199         chefInfo(params);
200         String chefAction = params.get(CHEF_ACTION_STR);
201         RequestContext rc = new RequestContext(ctx);
202         rc.isAlive();
203         int code;
204         String message;
205         if (privateKeyCheck()) {
206             ChefApiClient cac = new ChefApiClient(clientName, clientPrivatekey, chefserver, organizations);
207             ApiMethod am = cac.get(chefAction);
208             am.execute();
209             code = am.getReturnCode();
210             message = am.getResponseBodyAsString();
211         } else {
212             code = 500;
213             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
214         }
215         chefServerResult(rc, Integer.toString(code), message);
216     }
217
218     /**
219      * Send PUT request to chef server
220      */
221     @Override
222     public void chefPut(Map<String, String> params, SvcLogicContext ctx) {
223         chefInfo(params);
224         String chefAction = params.get(CHEF_ACTION_STR);
225         String chefNodeStr = params.get("org.openecomp.appc.instance.chefRequestBody");
226         RequestContext rc = new RequestContext(ctx);
227         rc.isAlive();
228         int code;
229         String message;
230         if (privateKeyCheck()) {
231             ChefApiClient cac = new ChefApiClient(clientName, clientPrivatekey, chefserver, organizations);
232
233             ApiMethod am = cac.put(chefAction).body(chefNodeStr);
234             am.execute();
235             code = am.getReturnCode();
236             message = am.getResponseBodyAsString();
237         } else {
238             code = 500;
239             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
240         }
241         logger.info(code + "   " + message);
242         chefServerResult(rc, Integer.toString(code), message);
243     }
244
245     /**
246      *  send Post request to chef server
247      */
248     @Override
249     public void chefPost(Map<String, String> params, SvcLogicContext ctx) {
250         chefInfo(params);
251         logger.info("chef Post method");
252         logger.info(clientName + " " + clientPrivatekey + " " + chefserver + " " + organizations);
253         String chefNodeStr = params.get("org.openecomp.appc.instance.chefRequestBody");
254         String chefAction = params.get(CHEF_ACTION_STR);
255
256         RequestContext rc = new RequestContext(ctx);
257         rc.isAlive();
258         int code;
259         String message;
260         // should load pem from somewhere else
261         if (privateKeyCheck()) {
262             ChefApiClient cac = new ChefApiClient(clientName, clientPrivatekey, chefserver, organizations);
263
264             // need pass path into it
265             // "/nodes/testnode"
266             ApiMethod am = cac.post(chefAction).body(chefNodeStr);
267             am.execute();
268             code = am.getReturnCode();
269             message = am.getResponseBodyAsString();
270         } else {
271             code = 500;
272             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
273         }
274         logger.info(code + "   " + message);
275         chefServerResult(rc, Integer.toString(code), message);
276     }
277
278     /**
279      * send delete request to chef server
280      */
281     @Override
282     public void chefDelete(Map<String, String> params, SvcLogicContext ctx) {
283         logger.info("chef delete method");
284         chefInfo(params);
285         String chefAction = params.get(CHEF_ACTION_STR);
286         RequestContext rc = new RequestContext(ctx);
287         rc.isAlive();
288         int code;
289         String message;
290         if (privateKeyCheck()) {
291             ChefApiClient cac = new ChefApiClient(clientName, clientPrivatekey, chefserver, organizations);
292             ApiMethod am = cac.delete(chefAction);
293             am.execute();
294             code = am.getReturnCode();
295             message = am.getResponseBodyAsString();
296         } else {
297             code = 500;
298             message = CANNOT_FIND_PRIVATE_KEY_STR + clientPrivatekey;
299         }
300         logger.info(code + "   " + message);
301         chefServerResult(rc, Integer.toString(code), message);
302     }
303
304     /**
305      * Trigger target vm run chef
306      */
307     @Override
308     public void trigger(Map<String, String> params, SvcLogicContext ctx) {
309         logger.info("Run trigger method");
310         String tVmIp = params.get("org.openecomp.appc.instance.ip");
311         RequestContext rc = new RequestContext(ctx);
312         rc.isAlive();
313
314         try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
315             HttpGet httpGet = new HttpGet(tVmIp);
316             HttpResponse response;
317             response = httpClient.execute(httpGet);
318             int responseCode = response.getStatusLine().getStatusCode();
319             HttpEntity entity = response.getEntity();
320             String responseOutput = EntityUtils.toString(entity);
321             chefClientResult(rc, Integer.toString(responseCode), responseOutput);
322             doSuccess(rc);
323         } catch (Exception ex) {
324             doFailure(rc, 500, ex.toString());
325         }
326     }
327
328     @Override
329     public void checkPushJob(Map<String, String> params, SvcLogicContext ctx) {
330         chefInfo(params);
331         String jobID = params.get("org.openecomp.appc.instance.jobid");
332         int retryTimes = Integer.parseInt(params.get("org.openecomp.appc.instance.retryTimes"));
333         int retryInterval = Integer.parseInt(params.get("org.openecomp.appc.instance.retryInterval"));
334         String chefAction = "/pushy/jobs/" + jobID;
335
336         RequestContext rc = new RequestContext(ctx);
337         rc.isAlive();
338         SvcLogicContext svcLogic = rc.getSvcLogicContext();
339         String message = "";
340         String status = "";
341         for (int i = 0; i < retryTimes; i++) {
342             try {
343                 Thread.sleep(retryInterval); // 1000 milliseconds is one second.
344             } catch (InterruptedException ex) {
345                 Thread.currentThread().interrupt();
346             }
347             ChefApiClient cac = new ChefApiClient(clientName, clientPrivatekey, chefserver, organizations);
348             ApiMethod am = cac.get(chefAction);
349             am.execute();
350             int code = am.getReturnCode();
351             message = am.getResponseBodyAsString();
352             JSONObject obj = new JSONObject(message);
353             status = obj.getString("status");
354             if (!"running".equals(status)) {
355                 logger.info(i + " time " + code + "   " + status);
356                 break;
357             }
358
359         }
360         if ("complete".equals(status)) {
361             svcLogic.setAttribute("org.openecomp.appc.chefServerResult.code", "200");
362             svcLogic.setAttribute("org.openecomp.appc.chefServerResult.message", message);
363         } else {
364             if ("running".equals(status)) {
365                 svcLogic.setAttribute("org.openecomp.appc.chefServerResult.code", "202");
366                 svcLogic.setAttribute("org.openecomp.appc.chefServerResult.message", "chef client runtime out");
367             } else {
368                 svcLogic.setAttribute("org.openecomp.appc.chefServerResult.code", "500");
369                 svcLogic.setAttribute("org.openecomp.appc.chefServerResult.message", message);
370             }
371         }
372     }
373
374     @Override
375     public void pushJob(Map<String, String> params, SvcLogicContext ctx) {
376         chefInfo(params);
377         String pushRequest = params.get("org.openecomp.appc.instance.pushRequest");
378         String chefAction = "/pushy/jobs";
379         RequestContext rc = new RequestContext(ctx);
380         rc.isAlive();
381         SvcLogicContext svcLogic = rc.getSvcLogicContext();
382         ChefApiClient cac = new ChefApiClient(clientName, clientPrivatekey, chefserver, organizations);
383         ApiMethod am = cac.post(chefAction).body(pushRequest);
384
385         am.execute();
386         int code = am.getReturnCode();
387         String message = am.getResponseBodyAsString();
388         if (code == 201) {
389             int startIndex = message.indexOf("jobs") + 6;
390             int endIndex = message.length() - 2;
391             String jobID = message.substring(startIndex, endIndex);
392             svcLogic.setAttribute("org.openecomp.appc.jobID", jobID);
393             logger.info(jobID);
394         }
395         chefServerResult(rc, Integer.toString(code), message);
396     }
397
398     private void doFailure(RequestContext rc, int code, String message) {
399         SvcLogicContext svcLogic = rc.getSvcLogicContext();
400         String msg = (message == null) ? Integer.toString(code) : message;
401         if (msg.contains("\n")) {
402             msg = msg.substring(msg.indexOf("\n"));
403         }
404
405         String status;
406         try {
407             status = Integer.toString(code);
408         } catch (Exception e) {
409             logger.info("Couldn't covert " + code + " to an Integer, defaulting status to 500", e);
410             status = "500";
411         }
412         svcLogic.setAttribute("org.openecomp.appc.chefAgent.code", status);
413         svcLogic.setAttribute("org.openecomp.appc.chefAgent.message", msg);
414     }
415
416     /**
417      * @param rc
418      *            The request context that manages the state and recovery of the
419      *            request for the life of its processing.
420      */
421     private void doSuccess(RequestContext rc) {
422         SvcLogicContext svcLogic = rc.getSvcLogicContext();
423         svcLogic.setAttribute("org.openecomp.appc.chefAgent.code", "200");
424     }
425
426     private void chefServerResult(RequestContext rc, String code, String message) {
427         SvcLogicContext svcLogic = rc.getSvcLogicContext();
428         svcLogic.setStatus(OUTCOME_SUCCESS);
429         svcLogic.setAttribute("org.openecomp.appc.chefServerResult.code", code);
430         svcLogic.setAttribute("org.openecomp.appc.chefServerResult.message", message);
431     }
432
433     private void chefClientResult(RequestContext rc, String code, String message) {
434         SvcLogicContext svcLogic = rc.getSvcLogicContext();
435         svcLogic.setStatus(OUTCOME_SUCCESS);
436         svcLogic.setAttribute("org.openecomp.appc.chefClientResult.code", code);
437         svcLogic.setAttribute("org.openecomp.appc.chefClientResult.message", message);
438     }
439
440     /**
441      * initialize the provider adapter by building the context cache
442      */
443     private void initialize() {
444         configuration = ConfigurationFactory.getConfiguration();
445         // need to fetch data from appc configurator or form some file in the appc vms
446         clientName = "testnode";
447         clientPrivatekey = "/etc/chef/client.pem";
448         serverAddress = "http://example.com";
449         organizations = "test";
450         chefserver = serverAddress + ORGANIZATIONS_STR + organizations;
451         logger.info("Initialize Chef Adapter");
452     }
453
454     private void initialize(String key) {
455         configuration = ConfigurationFactory.getConfiguration();
456         // need to fetch data from appc configurator or form some file in the appc vms
457         clientName = "testnode";
458         clientPrivatekey = key;
459         serverAddress = "http://example.com";
460         organizations = "test";
461         chefserver = serverAddress + ORGANIZATIONS_STR + organizations;
462         logger.info("Initialize Chef Adapter");
463     }
464
465 }