2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2018-2019 AT&T Intellectual Property. All rights reserved.
 
   6  * ================================================================================
 
   7  * Copyright (C) 2017 Amdocs
 
   8  * =============================================================================
 
   9  * Modifications Copyright (C) 2019 IBM
 
  10  * =============================================================================
 
  11  * Modifications Copyright (C) 2019 Orange
 
  12  * =============================================================================
 
  13  * Licensed under the Apache License, Version 2.0 (the "License");
 
  14  * you may not use this file except in compliance with the License.
 
  15  * You may obtain a copy of the License at
 
  17  *      http://www.apache.org/licenses/LICENSE-2.0
 
  19  * Unless required by applicable law or agreed to in writing, software
 
  20  * distributed under the License is distributed on an "AS IS" BASIS,
 
  21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  22  * See the License for the specific language governing permissions and
 
  23  * limitations under the License.
 
  25  * ============LICENSE_END=========================================================
 
  28 package org.onap.appc.adapter.ansible.impl;
 
  32 import java.util.HashMap;
 
  33 import java.util.Properties;
 
  35 import org.apache.commons.lang.StringUtils;
 
  36 import org.json.JSONException;
 
  37 import org.json.JSONObject;
 
  38 import org.json.JSONArray;
 
  39 import org.onap.appc.adapter.ansible.AnsibleAdapter;
 
  40 import org.onap.appc.adapter.ansible.model.AnsibleMessageParser;
 
  41 import org.onap.appc.adapter.ansible.model.AnsibleResult;
 
  42 import org.onap.appc.adapter.ansible.model.AnsibleResultCodes;
 
  43 import org.onap.appc.adapter.ansible.model.AnsibleServerEmulator;
 
  44 import org.onap.appc.exceptions.APPCException;
 
  45 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 
  46 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
 
  48 import com.att.eelf.configuration.EELFLogger;
 
  49 import com.att.eelf.configuration.EELFManager;
 
  50 import org.onap.appc.encryption.EncryptionTool;
 
  53  * This class implements the {@link AnsibleAdapter} interface. This interface
 
  54  * defines the behaviors that our service provides.
 
  56 public class AnsibleAdapterImpl implements AnsibleAdapter {
 
  59      * The constant used to define the service name in the mapped diagnostic context
 
  61     @SuppressWarnings("nls")
 
  62     public static final String MDC_SERVICE = "service";
 
  65      * The constant for the status code for a failed outcome
 
  67     @SuppressWarnings("nls")
 
  68     public static final String OUTCOME_FAILURE = "failure";
 
  71      * The constant for the status code for a successful outcome
 
  73     @SuppressWarnings("nls")
 
  74     public static final String OUTCOME_SUCCESS = "success";
 
  79     private static final String ADAPTER_NAME = "Ansible Adapter";
 
  80     private static final String APPC_EXCEPTION_CAUGHT = "APPCException caught";
 
  82     private static final String RESULT_CODE_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.result.code";
 
  83     private static final String MESSAGE_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.message";
 
  84     private static final String RESULTS_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.results";
 
  85     private static final String OUTPUT_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.output";
 
  86     private static final String ID_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.Id";
 
  87     private static final String LOG_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.log";
 
  89     private static final String CLIENT_TYPE_PROPERTY_NAME = "org.onap.appc.adapter.ansible.clientType";
 
  90     private static final String TRUSTSTORE_PROPERTY_NAME = "org.onap.appc.adapter.ansible.trustStore";
 
  91     private static final String TRUSTPASSWD_PROPERTY_NAME = "org.onap.appc.adapter.ansible.trustStore.trustPasswd";
 
  92     private static final String TIMEOUT_PROPERTY_NAME = "org.onap.appc.adapter.ansible.timeout";
 
  93     private static final String POLL_INTERVAL_PROPERTY_NAME = "org.onap.appc.adapter.ansible.pollInterval";
 
  94     private static final String SOCKET_TIMEOUT_PROPERTY_NAME = "org.onap.appc.adapter.ansible.socketTimeout";
 
  95     private static final String PASSWORD = "Password";
 
  96     private static final String APPC_PROPS = "/appc.properties";
 
  97     private static final String SDNC_CONFIG_DIR = "SDNC_CONFIG_DIR";
 
  98     private static final String propDir = System.getenv(SDNC_CONFIG_DIR);
 
  99     private static final String SERVERIP = "ServerIP";
 
 100     private Properties props;
 
 101     private int defaultTimeout = 600 * 1000;
 
 102     private int defaultSocketTimeout = 60 * 1000;
 
 103     private int defaultPollInterval = 60 * 1000;
 
 106      * The logger to be used
 
 108     private static final EELFLogger logger = EELFManager.getInstance().getLogger(AnsibleAdapterImpl.class);
 
 112     private ConnectionBuilder httpClient;
 
 115      * Ansible API Message Handlers
 
 117     private AnsibleMessageParser messageProcessor;
 
 120      * indicator whether in test mode
 
 122     private boolean testMode = false;
 
 125      * server emulator object to be used if in test mode
 
 127     private AnsibleServerEmulator testServer;
 
 130      * This default constructor is used as a work around because the activator
 
 131      * wasn't getting called
 
 133     public AnsibleAdapterImpl() {
 
 138      * Used for jUnit test and testing interface
 
 140     public AnsibleAdapterImpl(boolean mode) {
 
 142         testServer = new AnsibleServerEmulator();
 
 143         messageProcessor = new AnsibleMessageParser();
 
 147      * Returns the symbolic name of the adapter
 
 149      * @return The adapter name
 
 150      * @see org.onap.appc.adapter.rest.AnsibleAdapter#getAdapterName()
 
 153     public String getAdapterName() {
 
 159      *            Method posts info to Context memory in case of an error and throws
 
 160      *            a SvcLogicException causing SLI to register this as a failure
 
 162     @SuppressWarnings("static-method")
 
 163     private void doFailure(SvcLogicContext svcLogic, int code, String message) throws SvcLogicException {
 
 165         svcLogic.setStatus(OUTCOME_FAILURE);
 
 166         svcLogic.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(code));
 
 167         svcLogic.setAttribute(MESSAGE_ATTRIBUTE_NAME, message);
 
 169         throw new SvcLogicException("Ansible Adapter Error = " + message);
 
 173      * initialize the Ansible adapter based on default and over-ride configuration
 
 176     private void initialize() {
 
 177         String path = propDir + APPC_PROPS;
 
 178         File propFile = new File(path);
 
 179         props = new Properties();
 
 181             InputStream input = new FileInputStream(propFile);
 
 183         } catch (Exception ex) {
 
 184             logger.error("Error while reading appc.properties file" + ex.getMessage());
 
 186         // Create the message processor instance 
 
 187         messageProcessor = new AnsibleMessageParser();
 
 188         //continuing for checking timeout
 
 190             String timeoutStr = props.getProperty(TIMEOUT_PROPERTY_NAME);
 
 191             defaultTimeout = Integer.parseInt(timeoutStr) * 1000;
 
 193         } catch (Exception e) {
 
 194             defaultTimeout = 600 * 1000;
 
 195             logger.error("Error while reading time out property" , e);
 
 197         //continuing for checking timeout
 
 199             String timeoutStr = props.getProperty(SOCKET_TIMEOUT_PROPERTY_NAME);
 
 200             defaultSocketTimeout = Integer.parseInt(timeoutStr) * 1000;
 
 202         } catch (Exception e) {
 
 203             defaultSocketTimeout = 60 * 1000;
 
 204             logger.error("Error while reading socket time out property" , e);
 
 206         //continuing for checking timeout
 
 208             String timeoutStr = props.getProperty(POLL_INTERVAL_PROPERTY_NAME);
 
 209             defaultPollInterval = Integer.parseInt(timeoutStr) * 1000;
 
 211         } catch (Exception e) {
 
 212             defaultPollInterval = 60 * 1000;
 
 213             logger.error("Error while reading poll interval property" , e);
 
 215         logger.info("Initialized Ansible Adapter");
 
 218     private ConnectionBuilder getHttpConn(int timeout, String serverIP) {
 
 220         String path = propDir + APPC_PROPS;
 
 221         File propFile = new File(path);
 
 222         props = new Properties();
 
 225             input = new FileInputStream(propFile);
 
 227         } catch (Exception ex) {
 
 228             // TODO Auto-generated catch block
 
 229             logger.error("Error while reading appc.properties file" + ex.getMessage());
 
 231         // Create the http client instance
 
 232         // type of client is extracted from the property file parameter
 
 233         // org.onap.appc.adapter.ansible.clientType
 
 235         // 1. TRUST_ALL (trust all SSL certs). To be used ONLY in dev
 
 236         // 2. TRUST_CERT (trust only those whose certificates have been stored in the
 
 238         // 3. DEFAULT (trust only well known certificates). This is standard behavior to
 
 240         // revert. To be used in PROD
 
 241         ConnectionBuilder httpClientLocal = null;
 
 243             String clientType = props.getProperty(CLIENT_TYPE_PROPERTY_NAME);
 
 244             logger.info("Ansible http client type set to " + clientType);
 
 246             if ("TRUST_ALL".equals(clientType)) {
 
 248                         "Creating http client to trust ALL ssl certificates. WARNING. This should be done only in dev environments");
 
 249                 httpClientLocal = new ConnectionBuilder(1, timeout);
 
 250             } else if ("TRUST_CERT".equals(clientType)) {
 
 251                 // set path to keystore file
 
 252                 String trustStoreFile = props.getProperty(TRUSTSTORE_PROPERTY_NAME);
 
 253                 String key = props.getProperty(TRUSTPASSWD_PROPERTY_NAME);
 
 254                 char[] trustStorePasswd = EncryptionTool.getInstance().decrypt(key).toCharArray();
 
 255                 logger.info("Creating http client with trustmanager from " + trustStoreFile);
 
 256                 httpClientLocal = new ConnectionBuilder(trustStoreFile, trustStorePasswd, timeout, serverIP);
 
 258                 logger.info("Creating http client with default behaviour");
 
 259                 httpClientLocal = new ConnectionBuilder(0, timeout);
 
 261         } catch (Exception e) {
 
 262             logger.error("Error Getting HTTP Connection Builder due to Unknown Exception", e);
 
 265         logger.info("Got HTTP Connection Builder");
 
 266         return httpClientLocal;
 
 269     // Public Method to post request to execute playbook. Posts the following back
 
 270     // to Svc context memory
 
 271     // org.onap.appc.adapter.ansible.req.code : 100 if successful
 
 272     // org.onap.appc.adapter.ansible.req.messge : any message
 
 273     // org.onap.appc.adapter.ansible.req.Id : a unique uuid to reference the request
 
 275     public void reqExec(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
 
 277         String playbookName = StringUtils.EMPTY;
 
 278         String payload = StringUtils.EMPTY;
 
 279         String agentUrl = StringUtils.EMPTY;
 
 280         String user = StringUtils.EMPTY;
 
 281         String password = StringUtils.EMPTY;
 
 282         String id = StringUtils.EMPTY;
 
 283         String timeout = StringUtils.EMPTY;
 
 284         JSONObject jsonPayload;
 
 287             // create json object to send request
 
 288             jsonPayload = messageProcessor.reqMessage(params);
 
 290             logger.info("Initial Payload  = " + jsonPayload.toString());
 
 291             agentUrl = (String) jsonPayload.remove("AgentUrl");
 
 292             user = (String) jsonPayload.remove("User");
 
 293             password = (String)jsonPayload.remove(PASSWORD);
 
 294             if(StringUtils.isNotBlank(password))
 
 295             password = EncryptionTool.getInstance().decrypt(password);
 
 296             id = jsonPayload.getString("Id");
 
 297             timeout = jsonPayload.getString("Timeout");
 
 298             if (StringUtils.isBlank(timeout))
 
 301             String autoNodeList = (String) jsonPayload.remove("AutoNodeList");
 
 302             if (autoNodeList != null && Boolean.parseBoolean(autoNodeList)) {
 
 303                 JSONArray generatedNodeList = generateNodeList(params, ctx);
 
 304                 if (generatedNodeList.length() > 0) {
 
 305                     jsonPayload.put("NodeList", generatedNodeList);
 
 306                     jsonPayload.put("InventoryNames", "VM");
 
 308                     doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
 
 309                             "Auto generation of Node List Failed - no elements on the list");
 
 312                 logger.debug("Auto Node List is DISABLED");
 
 314             payload = jsonPayload.toString();
 
 315             ctx.setAttribute("AnsibleTimeout", timeout);
 
 316             logger.info("Updated Payload  = " + payload + " timeout = " + timeout);
 
 317         } catch (APPCException e) {
 
 318             logger.error(APPC_EXCEPTION_CAUGHT, e);
 
 319             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
 
 320                     "Error constructing request for execution of playbook due to missing mandatory parameters. Reason = "
 
 322         } catch (JSONException e) {
 
 323             logger.error("JSONException caught", e);
 
 324             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
 
 325                     "Error constructing request for execution of playbook due to invalid JSON block. Reason = "
 
 327         } catch (NumberFormatException e) {
 
 328             logger.error("NumberFormatException caught", e);
 
 329             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
 
 330                     "Error constructing request for execution of playbook due to invalid parameter values. Reason = "
 
 335         String message = StringUtils.EMPTY;
 
 338             // post the test request
 
 339             logger.info("Posting ansible request = " + payload + " to url = " + agentUrl);
 
 340             AnsibleResult testResult = postExecRequest(agentUrl, payload, user, password,ctx);
 
 341           if (testResult != null) {
 
 342             logger.info("Received response on ansible post request " + testResult.getStatusMessage());
 
 343             // Process if HTTP was successful
 
 344             if (testResult.getStatusCode() == 200) {
 
 345               testResult = messageProcessor.parsePostResponse(testResult.getStatusMessage());
 
 347               doFailure(ctx, testResult.getStatusCode(),
 
 348                         "Error posting request. Reason = " + testResult.getStatusMessage());
 
 350             String output = StringUtils.EMPTY;
 
 351             code = testResult.getStatusCode();
 
 352             message = testResult.getStatusMessage();
 
 353             output = testResult.getOutput();
 
 354             ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, output);
 
 355             String serverIp = testResult.getServerIp();
 
 356             if (StringUtils.isBlank(serverIp))
 
 357             ctx.setAttribute(SERVERIP, serverIp);
 
 359               ctx.setAttribute(SERVERIP, "");
 
 360             // Check status of test request returned by Agent
 
 361             if (code == AnsibleResultCodes.PENDING.getValue()) {
 
 362               logger.info(String.format("Submission of Test %s successful.", playbookName));
 
 363               // test request accepted. We are in asynchronous case
 
 365               doFailure(ctx, code, "Request for execution of playbook rejected. Reason = " + message);
 
 368             doFailure(ctx, code, "Ansible Test result is null");
 
 370         } catch (APPCException e) {
 
 371             logger.error(APPC_EXCEPTION_CAUGHT, e);
 
 372             doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
 
 373                     "Exception encountered when posting request for execution of playbook. Reason = " + e.getMessage());
 
 376         ctx.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(code));
 
 377         ctx.setAttribute(MESSAGE_ATTRIBUTE_NAME, message);
 
 378         ctx.setAttribute(ID_ATTRIBUTE_NAME, id);
 
 382      * Method is used to automatically generate NodeList section base on the svc context
 
 384      * @see org.onap.appc.adapter.ansible.AnsibleAdapter#reqExecResult(java.util.Map,
 
 385      *      org.onap.ccsdk.sli.core.sli.SvcLogicContext)
 
 387     private JSONArray generateNodeList(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
 
 388         String vfModuleId = params.get("vf-module-id");
 
 389         String vnfcName = params.get("vnfc-name");
 
 390         String vServerId = params.get("vserver-id");
 
 391         String vnfcType = params.get("vnfc-type");
 
 392         logger.info("GENERATING NODE LIST");
 
 393         JSONArray result = new JSONArray();
 
 395         if (vServerId != null && !vServerId.equals(""))
 
 396             logger.debug("Auto Node List filtering parameter vserver-id " + vServerId);
 
 399         if (vnfcName != null && !vnfcName.equals(""))
 
 400             logger.debug("Auto Node List filtering parameter vnfc-name " + vnfcName);
 
 403         if (vnfcType != null && !vnfcType.equals(""))
 
 404             logger.debug("Auto Node List filtering parameter vnfc-type " + vnfcType);
 
 407         if (vfModuleId != null && !vfModuleId.equals(""))
 
 408             logger.debug("Auto Node List filtering parameter vf-module-id " + vfModuleId);
 
 412         Map<String, JSONObject> candidates = new HashMap<String, JSONObject>();
 
 413         for (int i = 0; ; i++) {
 
 414             String vmKey = "tmp.vnfInfo.vm[" + Integer.toString(i) + "]";
 
 415             logger.info("Looking for attributes of: " + vmKey);
 
 416             if (ctx.getAttribute(vmKey + ".vnfc-name") != null) {
 
 417                 String vmVnfcName = ctx.getAttribute(vmKey + ".vnfc-name");
 
 418                 String vmVnfcIpv4Address = ctx.getAttribute(vmKey + ".vnfc-ipaddress-v4-oam-vip");
 
 419                 String vmVnfcType = ctx.getAttribute(vmKey + ".vnfc-type");
 
 421                 if (vmVnfcName != null && vmVnfcIpv4Address != null && vmVnfcType != null
 
 422                     && !vmVnfcName.equals("") && !vmVnfcIpv4Address.equals("") && !vmVnfcType.equals("")) {
 
 423                     if (vServerId != null) {
 
 424                         String vmVserverId = ctx.getAttribute(vmKey + ".vserver-id");
 
 425                         if (vmVserverId == null || !vmVserverId.equals(vServerId)) {
 
 426                             logger.debug("Auto Node List candidate " + vmVnfcName + " dropped. vserver-id mismatch");
 
 430                     if (vfModuleId != null) {
 
 431                         String vmVfModuleId = ctx.getAttribute(vmKey + ".vf-module-id");
 
 432                         if (vmVfModuleId == null || !vmVfModuleId.equals(vfModuleId)) {
 
 433                             logger.debug("Auto Node List candidate " + vmVnfcName + " dropped. vf-module-id mismatch");
 
 437                     if (vnfcName != null) {
 
 438                         if (!vmVnfcName.equals(vnfcName)) {
 
 439                             logger.debug("Auto Node List candidate " + vmVnfcName + " dropped. vnfc-name mismatch");
 
 443                     if (vnfcType != null) {
 
 444                         if (!vmVnfcType.equals(vnfcType)) {
 
 445                             logger.debug("Auto Node List candidate " + vmVnfcType + " dropped. vnfc-type mismatch");
 
 450                     logger.info("Auto Node List candidate " + vmVnfcName + " [" + vmVnfcIpv4Address + "," + vmVnfcType + "]");
 
 452                     JSONObject vnfTypeCandidates = null;
 
 453                     JSONArray vmList = null;
 
 454                     if (!candidates.containsKey(vmVnfcType)) {
 
 455                         vnfTypeCandidates = new JSONObject();
 
 456                         vmList = new JSONArray();
 
 457                         vnfTypeCandidates.put("site", "site");
 
 458                         vnfTypeCandidates.put("vnfc-type", vmVnfcType);
 
 459                         vnfTypeCandidates.put("vm-info", vmList);
 
 460                         candidates.put(vmVnfcType, vnfTypeCandidates);
 
 462                         vnfTypeCandidates = candidates.get(vmVnfcType);
 
 463                         vmList = (JSONArray) vnfTypeCandidates.get("vm-info");
 
 466                     JSONObject candidate = new JSONObject();
 
 467                     candidate.put("ne_id", vmVnfcName);
 
 468                     candidate.put("fixed_ip_address", vmVnfcIpv4Address);
 
 469                     vmList.put(candidate);
 
 471                     logger.warn("Incomplete information for Auto Node List candidate " + vmKey);
 
 477         for(JSONObject vnfcCandidates : candidates.values()) {
 
 478             result.put(vnfcCandidates);
 
 481         logger.info("GENERATING NODE LIST COMPLETED");
 
 486      * Public method to query status of a specific request It blocks till the
 
 487      * Ansible Server responds or the session times out (non-Javadoc)
 
 489      * @see org.onap.appc.adapter.ansible.AnsibleAdapter#reqExecResult(java.util.Map,
 
 490      *      org.onap.ccsdk.sli.core.sli.SvcLogicContext)
 
 493     public void reqExecResult(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
 
 496         String reqUri = StringUtils.EMPTY;
 
 499             String serverIp = ctx.getAttribute(SERVERIP);
 
 500             if (StringUtils.isNotBlank(serverIp))
 
 501                 reqUri = messageProcessor.reqUriResultWithIP(params, serverIp);
 
 503                 reqUri = messageProcessor.reqUriResult(params);
 
 504             logger.info("Got uri " + reqUri);
 
 505         } catch (APPCException e) {
 
 506             logger.error(APPC_EXCEPTION_CAUGHT, e);
 
 507             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
 
 508                     "Error constructing request to retrieve result due to missing parameters. Reason = "
 
 511         } catch (NumberFormatException e) {
 
 512             logger.error("NumberFormatException caught", e);
 
 513             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
 
 514                     "Error constructing request to retrieve result due to invalid parameters value. Reason = "
 
 520         String message = StringUtils.EMPTY;
 
 521         String results = StringUtils.EMPTY;
 
 522         String output = StringUtils.EMPTY;
 
 524             // Try to retrieve the test results (modify the URL for that)
 
 525             AnsibleResult testResult = queryServer(reqUri, params.get("User"),
 
 526                     EncryptionTool.getInstance().decrypt(params.get(PASSWORD)), ctx);
 
 527             code = testResult.getStatusCode();
 
 528             message = testResult.getStatusMessage();
 
 530             if (code == 200 || code == 400 || "FINISHED".equalsIgnoreCase(message)) {
 
 531                 logger.info("Parsing response from ansible Server = " + message);
 
 532                 // Valid HTTP. process the Ansible message
 
 533                 testResult = messageProcessor.parseGetResponse(message);
 
 534                 code = testResult.getStatusCode();
 
 535                 message = testResult.getStatusMessage();
 
 536                 results = testResult.getResults();
 
 537                 output = testResult.getOutput();
 
 538                 ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, output);
 
 540             logger.info("Request response = " + message);
 
 541         } catch (APPCException e) {
 
 542             doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
 
 543                     "Exception encountered retrieving result : " + e.getMessage());
 
 547         // We were able to get and process the results. Determine if playbook succeeded
 
 549         if (code == AnsibleResultCodes.FINAL_SUCCESS.getValue()) {
 
 550             message = String.format("Ansible Request  %s finished with Result = %s, Message = %s", params.get("Id"),
 
 551                     OUTCOME_SUCCESS, message);
 
 552             logger.info(message);
 
 554             logger.info(String.format("Ansible Request  %s finished with Result %s, Message = %s", params.get("Id"),
 
 555                     OUTCOME_FAILURE, message));
 
 556             ctx.setAttribute(RESULTS_ATTRIBUTE_NAME, results);
 
 557             ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, output);
 
 558             doFailure(ctx, code, message);
 
 562         // In case of 200,400,FINISHED return 400
 
 563         ctx.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, "400");
 
 564         ctx.setAttribute(MESSAGE_ATTRIBUTE_NAME, message);
 
 565         ctx.setAttribute(RESULTS_ATTRIBUTE_NAME, results);
 
 566         ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, output);
 
 567         ctx.setStatus(OUTCOME_SUCCESS);
 
 571      * Public method to get logs from playbook execution for a specific request
 
 573      * It blocks till the Ansible Server responds or the session times out very
 
 574      * similar to reqExecResult logs are returned in the DG context variable
 
 575      * org.onap.appc.adapter.ansible.log
 
 578     public void reqExecLog(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
 
 580         String reqUri = StringUtils.EMPTY;
 
 582             reqUri = messageProcessor.reqUriLog(params);
 
 583             logger.info("Retrieving results from " + reqUri);
 
 584         } catch (Exception e) {
 
 585             logger.error("Exception caught", e);
 
 586             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(), e.getMessage());
 
 589         String message = StringUtils.EMPTY;
 
 591             // Try to retrieve the test results (modify the url for that)
 
 592             AnsibleResult testResult = queryServer(reqUri, params.get("User"),
 
 593                     EncryptionTool.getInstance().decrypt(params.get(PASSWORD)), ctx);
 
 594             message = testResult.getStatusMessage();
 
 595             logger.info("Request output = " + message);
 
 596             ctx.setAttribute(LOG_ATTRIBUTE_NAME, message);
 
 597             ctx.setStatus(OUTCOME_SUCCESS);
 
 598         } catch (Exception e) {
 
 599             logger.error("Exception caught", e);
 
 600             doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
 
 601                     "Exception encountered retreiving output : " + e.getMessage());
 
 606      * Method that posts the request
 
 608     private AnsibleResult postExecRequest(String agentUrl, String payload, String user, String password,
 
 609             SvcLogicContext ctx) {
 
 611         AnsibleResult testResult = null;
 
 612         ConnectionBuilder httpClientLocal = getHttpConn(defaultSocketTimeout, "");
 
 614           if(httpClientLocal!=null) {
 
 615             httpClientLocal.setHttpContext(user, password);
 
 616             testResult = httpClientLocal.post(agentUrl, payload);
 
 617             httpClientLocal.close();
 
 620             testResult = testServer.post(agentUrl, payload);
 
 626      * Method to query Ansible server
 
 628     private AnsibleResult queryServer(String agentUrl, String user, String password, SvcLogicContext ctx) {
 
 630         AnsibleResult testResult = new AnsibleResult();
 
 631         int timeout = 600 * 1000;
 
 633             timeout = Integer.parseInt(ctx.getAttribute("AnsibleTimeout")) * 1000;
 
 635         } catch (Exception e) {
 
 636             timeout = defaultTimeout;
 
 638         long endTime = System.currentTimeMillis() + timeout;
 
 640         while (System.currentTimeMillis() < endTime) {
 
 641             String serverIP = ctx.getAttribute(SERVERIP);
 
 642             ConnectionBuilder httpClientLocal = getHttpConn(defaultSocketTimeout, serverIP);
 
 643             logger.info("Querying ansible GetResult URL = " + agentUrl);
 
 646               if(httpClientLocal!=null) {
 
 647                 httpClientLocal.setHttpContext(user, password);
 
 648                 testResult = httpClientLocal.get(agentUrl);
 
 649                 httpClientLocal.close();
 
 652                 testResult = testServer.get(agentUrl);
 
 654             if (testResult.getStatusCode() != AnsibleResultCodes.IO_EXCEPTION.getValue()
 
 655                     && testResult.getStatusCode() != AnsibleResultCodes.PENDING.getValue()) {
 
 660                 Thread.sleep(defaultPollInterval);
 
 661             } catch (InterruptedException ex) {
 
 662               logger.error("Thread Interrupted Exception", ex);
 
 663               Thread.currentThread().interrupt();
 
 667         if (testResult.getStatusCode() == AnsibleResultCodes.PENDING.getValue()) {
 
 668             testResult.setStatusCode(AnsibleResultCodes.IO_EXCEPTION.getValue());
 
 669             testResult.setStatusMessage("Request timed out");