Moving and merging Ansible adaptor from appc to ccsdk/sli 72/119272/6
authorSingal, Kapil (ks220y) <ks220y@att.com>
Fri, 12 Mar 2021 21:32:54 +0000 (16:32 -0500)
committerSingal, Kapil (ks220y) <ks220y@att.com>
Mon, 15 Mar 2021 04:38:17 +0000 (00:38 -0400)
Issue-ID: CCSDK-3198
Signed-off-by: Singal, Kapil (ks220y) <ks220y@att.com>
Change-Id: I5b2c8a3aff7b0e874a659122264be06f412945be

30 files changed:
adaptors/ansible-adapter/ansible-adapter-bundle/pom.xml
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapter.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterConstants.java [new file with mode: 0644]
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterPropertiesProvider.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterImpl.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImpl.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/ConnectionBuilder.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleMessageParser.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResult.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResultCodes.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleServerEmulator.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/OSGI-INF/blueprint/ansible-adapter-blueprint.xml
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/ansible-adapter.properties
adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/org/opendaylight/blueprint/ansible-adapter-blueprint.xml
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterImpl.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterPropertiesProviderImpl.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestConnectionBuilder.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleAdapter.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleMessageParser.java [new file with mode: 0644]
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleResult.java [new file with mode: 0644]
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/ExecutorHarness.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/InterceptLogger.java
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client-cert.crt [new file with mode: 0644]
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client.jks [new file with mode: 0644]
adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/properties/ansible-adapter-test.properties [moved from adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/ccsdk/default.properties with 76% similarity]
adaptors/ansible-adapter/pom.xml
core/utils/provider/pom.xml
core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/common/EnvProperties.java
core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionTool.java [new file with mode: 0644]
core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionToolTest.java [new file with mode: 0644]

index 9052215..192bcec 100644 (file)
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
         </dependency>
-
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
         </dependency>
-
-        <!-- Needed to run test cases -->
-        <dependency>
-            <groupId>org.glassfish.jersey.core</groupId>
-            <artifactId>jersey-common</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>org.codehaus.jackson</groupId>
-            <artifactId>jackson-jaxrs</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mockito</groupId>
-            <artifactId>mockito-core</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.onap.ccsdk.sli.core</groupId>
             <artifactId>sli-common</artifactId>
-            <scope>provided</scope>
         </dependency>
-
         <dependency>
             <groupId>org.onap.ccsdk.sli.core</groupId>
             <artifactId>sli-provider</artifactId>
-            <scope>provided</scope>
         </dependency>
-
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
-            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
-
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl-over-slf4j</artifactId>
         </dependency>
-
         <dependency>
             <groupId>org.json</groupId>
             <artifactId>json</artifactId>
         </dependency>
-
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
-
+        <!-- Needed to run test cases -->
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-common</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-jaxrs</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- Specifically using mockito version 1.10.19 to make sure junit works -->
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>1.10.19</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-reflect</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito2</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
index e43d3e3..65f80a1 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -31,7 +29,6 @@ import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
 
 /**
  * This interface defines the operations that the Ansible adapter exposes.
- *
  */
 public interface AnsibleAdapter extends SvcLogicJavaPlugin {
     /**
@@ -52,4 +49,5 @@ public interface AnsibleAdapter extends SvcLogicJavaPlugin {
 
     /* Method to get output of a playbook execution request */
     void reqExecOutput(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException;
+
 }
diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterConstants.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterConstants.java
new file mode 100644 (file)
index 0000000..20a8400
--- /dev/null
@@ -0,0 +1,50 @@
+package org.onap.ccsdk.sli.adaptors.ansible;
+
+public class AnsibleAdapterConstants {
+
+    public static final String ID = "Id";
+    public static final String USER = "User";
+    public static final String PSWD = "Password";
+    public static final String SERVERIP = "ServerIP";
+    public static final String AGENT_URL = "AgentUrl";
+    public static final String NODE_LIST = "NodeList";
+    public static final String ANSIBLE_SERVER = "AnsibleServer";
+
+    public static final String APPC_PROPS = "/appc.properties";
+    public static final String SDNC_CONFIG_DIR = "SDNC_CONFIG_DIR";
+    public static final String PROPDIR = System.getenv(SDNC_CONFIG_DIR);
+
+    public static final String ACTION = "Action";
+    public static final String OUTPUT = "Output";
+    public static final String TIMEOUT = "Timeout";
+    public static final String VERSION = "Version";
+
+    public static final String FAILURE = "failure";
+    public static final String SUCCESS = "success";
+    public static final String STATUS_CODE = "StatusCode";
+    public static final String STATUS_MESSAGE = "StatusMessage";
+
+    public static final String EXTRA_VARS = "ExtraVars";
+    public static final String PLAYBOOK_NAME = "PlaybookName";
+    public static final String AUTO_NODE_LIST = "AutoNodeList";
+    public static final String ENV_PARAMETERS = "EnvParameters";
+    public static final String FILE_PARAMETERS = "FileParameters";
+    public static final String INVENTORY_NAMES = "InventoryNames";
+    public static final String LOCAL_PARAMETERS = "LocalParameters";
+
+    public static final String ID_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.Id";
+    public static final String LOG_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.log";
+    public static final String OUTPUT_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.output";
+    public static final String TIMEOUT_PROPERTY_NAME = "org.onap.appc.adapter.ansible.timeout";
+    public static final String MESSAGE_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.message";
+    public static final String RESULTS_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.results";
+    public static final String RESULT_CODE_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.result.code";
+
+    public static final String TRUSTSTORE_PROPERTY_NAME = "org.onap.appc.adapter.ansible.trustStore";
+    public static final String CLIENT_TYPE_PROPERTY_NAME = "org.onap.appc.adapter.ansible.clientType";
+    public static final String POLL_INTERVAL_PROPERTY_NAME = "org.onap.appc.adapter.ansible.pollInterval";
+    public static final String SOCKET_TIMEOUT_PROPERTY_NAME = "org.onap.appc.adapter.ansible.socketTimeout";
+    public static final String TRUSTSTORE_PASS_PROPERTY_NAME = "org.onap.appc.adapter.ansible.trustStore.trustPasswd";
+
+
+}
index 6d9f4f1..671b1e4 100755 (executable)
@@ -1,8 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * onap
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2016 - 2017 ONAP
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
 
@@ -24,5 +26,6 @@ import java.util.Properties;
 
 public interface AnsibleAdapterPropertiesProvider {
 
-    public Properties getProperties();
+    Properties getProperties();
+
 }
index 2361fee..bc0af27 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
 
 package org.onap.ccsdk.sli.adaptors.ansible.impl;
 
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 import org.apache.commons.lang.StringUtils;
+import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapter;
@@ -37,8 +42,9 @@ import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResultCodes;
 import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleServerEmulator;
 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
+import org.onap.ccsdk.sli.core.utils.encryption.EncryptionTool;
+
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.*;
 
 /**
  * This class implements the {@link AnsibleAdapter} interface. This interface defines the behaviors
@@ -46,55 +52,19 @@ import com.att.eelf.configuration.EELFManager;
  */
 public class AnsibleAdapterImpl implements AnsibleAdapter {
 
-
-    /**
-     * The constant used to define the service name in the mapped diagnostic context
-     */
-    @SuppressWarnings("nls")
-    public static final String MDC_SERVICE = "service";
-
-    /**
-     * The constant for the status code for a failed outcome
-     */
-    @SuppressWarnings("nls")
-    public static final String OUTCOME_FAILURE = "failure";
-
-    /**
-     * The constant for the status code for a successful outcome
-     */
-    @SuppressWarnings("nls")
-    public static final String OUTCOME_SUCCESS = "success";
-
     /**
      * Adapter Name
      */
     private static final String ADAPTER_NAME = "Ansible Adapter";
     private static final String APPC_EXCEPTION_CAUGHT = "APPCException caught";
 
-    private static final String RESULT_CODE_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.result.code";
-    private static final String MESSAGE_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.message";
-    private static final String RESULTS_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.results";
-    private static final String ID_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.Id";
-    private static final String LOG_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.log";
-    private static final String OUTPUT_ATTRIBUTE_NAME = "org.onap.appc.adapter.ansible.output";
-
-    private static final String CLIENT_TYPE_PROPERTY_NAME = "org.onap.appc.adapter.ansible.clientType";
-    private static final String TRUSTSTORE_PROPERTY_NAME = "org.onap.appc.adapter.ansible.trustStore";
-    private static final String TRUSTPASSD_PROPERTY_NAME = "org.onap.appc.adapter.ansible.trustStore.trustPasswd";
-
-    private static final String PASSD = "Password";
-
     /**
      * The logger to be used
      */
     private static final EELFLogger logger = EELFManager.getInstance().getLogger(AnsibleAdapterImpl.class);
-
-
-    /**
-     * Connection object
-     **/
-    private ConnectionBuilder httpClient;
-
+    private int defaultTimeout = 600 * 1000;
+    private int defaultSocketTimeout = 60 * 1000;
+    private int defaultPollInterval = 60 * 1000;
     /**
      * Ansible API Message Handlers
      **/
@@ -116,12 +86,20 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
     public AnsibleAdapterImpl() {
         initialize(new AnsibleAdapterPropertiesProviderImpl());
     }
+
+    /**
+     * Instantiates a new Ansible adapter.
+     *
+     * @param propProvider the prop provider
+     */
     public AnsibleAdapterImpl(AnsibleAdapterPropertiesProvider propProvider) {
         initialize(propProvider);
     }
 
     /**
      * Used for jUnit test and testing interface
+     *
+     * @param mode the mode
      */
     public AnsibleAdapterImpl(boolean mode) {
         testMode = mode;
@@ -133,24 +111,17 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
      * Returns the symbolic name of the adapter
      *
      * @return The adapter name
-     * @see org.onap.appc.adapter.rest.AnsibleAdapter#getAdapterName()
      */
     @Override
     public String getAdapterName() {
         return ADAPTER_NAME;
     }
 
-    /**
-     * @param rc Method posts info to Context memory in case of an error and throws a
-     *        SvcLogicException causing SLI to register this as a failure
-     */
     @SuppressWarnings("static-method")
     private void doFailure(SvcLogicContext svcLogic, int code, String message) throws SvcLogicException {
-
-        svcLogic.setStatus(OUTCOME_FAILURE);
+        svcLogic.markFailed();
         svcLogic.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(code));
         svcLogic.setAttribute(MESSAGE_ATTRIBUTE_NAME, message);
-
         throw new SvcLogicException("Ansible Adapter Error = " + message);
     }
 
@@ -158,13 +129,48 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
      * initialize the Ansible adapter based on default and over-ride configuration data
      */
     private void initialize(AnsibleAdapterPropertiesProvider propProvider) {
-
-
         Properties props = propProvider.getProperties();
-
         // Create the message processor instance
         messageProcessor = new AnsibleMessageParser();
 
+        //continuing for checking defaultTimeout
+        try {
+            String timeoutStr = props.getProperty(TIMEOUT_PROPERTY_NAME);
+            defaultTimeout = Integer.parseInt(timeoutStr) * 1000;
+        } catch (Exception e) {
+            defaultTimeout = 600 * 1000;
+            logger.error("Error while reading time out property", e);
+        }
+        //continuing for checking defaultSocketTimeout
+        try {
+            String timeoutStr = props.getProperty(SOCKET_TIMEOUT_PROPERTY_NAME);
+            defaultSocketTimeout = Integer.parseInt(timeoutStr) * 1000;
+        } catch (Exception e) {
+            defaultSocketTimeout = 60 * 1000;
+            logger.error("Error while reading socket time out property", e);
+        }
+        //continuing for checking defaultPollInterval
+        try {
+            String timeoutStr = props.getProperty(POLL_INTERVAL_PROPERTY_NAME);
+            defaultPollInterval = Integer.parseInt(timeoutStr) * 1000;
+        } catch (Exception e) {
+            defaultPollInterval = 60 * 1000;
+            logger.error("Error while reading poll interval property", e);
+        }
+        logger.info("Initialized Ansible Adapter");
+    }
+
+    private ConnectionBuilder getHttpConn(int timeout, String serverIP) {
+        String path = PROPDIR + APPC_PROPS;
+        File propFile = new File(path);
+        Properties props = new Properties();
+        InputStream input;
+        try {
+            input = new FileInputStream(propFile);
+            props.load(input);
+        } catch (Exception ex) {
+            logger.error("Error while reading appc.properties file {}", ex.getMessage());
+        }
         // Create the http client instance
         // type of client is extracted from the property file parameter
         // org.onap.appc.adapter.ansible.clientType
@@ -173,31 +179,30 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
         // 2. TRUST_CERT (trust only those whose certificates have been stored in the trustStore file)
         // 3. DEFAULT (trust only well known certificates). This is standard behavior to which it will
         // revert. To be used in PROD
-
+        ConnectionBuilder httpClientLocal = null;
         try {
             String clientType = props.getProperty(CLIENT_TYPE_PROPERTY_NAME);
-            logger.info("Ansible http client type set to " + clientType);
-
+            logger.info("Ansible http client type set to {}", clientType);
             if ("TRUST_ALL".equals(clientType)) {
-                logger.info(
-                        "Creating http client to trust ALL ssl certificates. WARNING. This should be done only in dev environments");
-                httpClient = new ConnectionBuilder(1);
+                logger.info("Creating http client to trust ALL ssl certificates. WARNING. This should be done only in dev environments");
+                httpClientLocal = new ConnectionBuilder(1, timeout);
             } else if ("TRUST_CERT".equals(clientType)) {
                 // set path to keystore file
                 String trustStoreFile = props.getProperty(TRUSTSTORE_PROPERTY_NAME);
-                String key = props.getProperty(TRUSTPASSD_PROPERTY_NAME);
-                char[] trustStorePasswd = key.toCharArray();
-                logger.info("Creating http client with trustmanager from " + trustStoreFile);
-                httpClient = new ConnectionBuilder(trustStoreFile, trustStorePasswd);
+                String key = props.getProperty(TRUSTSTORE_PASS_PROPERTY_NAME);
+                char[] trustStorePasswd = EncryptionTool.getInstance().decrypt(key).toCharArray();
+                logger.info("Creating http client with trust manager from {}", trustStoreFile);
+                httpClientLocal = new ConnectionBuilder(trustStoreFile, trustStorePasswd, timeout, serverIP);
             } else {
                 logger.info("Creating http client with default behaviour");
-                httpClient = new ConnectionBuilder(0);
+                httpClientLocal = new ConnectionBuilder(0, timeout);
             }
         } catch (Exception e) {
-            logger.error("Error Initializing Ansible Adapter due to Unknown Exception", e);
+            logger.error("Error Getting HTTP Connection Builder due to Unknown Exception", e);
         }
 
-        logger.info("Initialized Ansible Adapter");
+        logger.info("Got HTTP Connection Builder");
+        return httpClientLocal;
     }
 
     // Public Method to post request to execute playbook. Posts the following back
@@ -207,41 +212,62 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
     //  org.onap.appc.adapter.ansible.req.Id : a unique uuid to reference the request
     @Override
     public void reqExec(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
-
         String playbookName = StringUtils.EMPTY;
         String payload = StringUtils.EMPTY;
         String agentUrl = StringUtils.EMPTY;
         String user = StringUtils.EMPTY;
-        String password = StringUtils.EMPTY;
+        String pswd = StringUtils.EMPTY;
         String id = StringUtils.EMPTY;
 
-        JSONObject jsonPayload;
-
         try {
             // create json object to send request
-            jsonPayload = messageProcessor.reqMessage(params);
+            JSONObject jsonPayload = messageProcessor.reqMessage(params);
+            logger.info("Initial Payload = {}", jsonPayload.toString());
 
             agentUrl = (String) jsonPayload.remove("AgentUrl");
-            user = (String) jsonPayload.remove("User");
-            password = (String) jsonPayload.remove(PASSD);
             id = jsonPayload.getString("Id");
+            user = (String) jsonPayload.remove(USER);
+            pswd = (String) jsonPayload.remove(PSWD);
+            if (StringUtils.isNotBlank(pswd)) {
+                pswd = EncryptionTool.getInstance().decrypt(pswd);
+            }
+            String timeout = jsonPayload.getString("Timeout");
+            if (StringUtils.isBlank(timeout)) {
+                timeout = "600";
+            }
+
+            String autoNodeList = (String) jsonPayload.remove("AutoNodeList");
+            if (Boolean.parseBoolean(autoNodeList)) {
+                JSONArray generatedNodeList = generateNodeList(params, ctx);
+                if (generatedNodeList.length() > 0) {
+                    jsonPayload.put("NodeList", generatedNodeList);
+                    jsonPayload.put("InventoryNames", "VM");
+                } else {
+                    doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
+                            "Auto generation of Node List Failed - no elements on the list");
+                }
+            } else {
+                logger.debug("Auto Node List is DISABLED");
+            }
+
             payload = jsonPayload.toString();
-            logger.info("Updated Payload  = " + payload);
+            ctx.setAttribute("AnsibleTimeout", timeout);
+            logger.info("Updated Payload = {} timeout = {}", payload, timeout);
         } catch (SvcLogicException e) {
             logger.error(APPC_EXCEPTION_CAUGHT, e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
                     "Error constructing request for execution of playbook due to missing mandatory parameters. Reason = "
-                            + e.getMessage());
+                    + e.getMessage());
         } catch (JSONException e) {
             logger.error("JSONException caught", e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
                     "Error constructing request for execution of playbook due to invalid JSON block. Reason = "
-                            + e.getMessage());
+                    + e.getMessage());
         } catch (NumberFormatException e) {
             logger.error("NumberFormatException caught", e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
                     "Error constructing request for execution of playbook due to invalid parameter values. Reason = "
-                            + e.getMessage());
+                    + e.getMessage());
         }
 
         int code = -1;
@@ -249,26 +275,31 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
 
         try {
             // post the test request
-            logger.info("Posting request = " + payload + " to url = " + agentUrl);
-            AnsibleResult testResult = postExecRequest(agentUrl, payload, user, password);
-
-            // Process if HTTP was successful
-            if (testResult.getStatusCode() == 200) {
-                testResult = messageProcessor.parsePostResponse(testResult.getStatusMessage());
-            } else {
-                doFailure(ctx, testResult.getStatusCode(),
-                        "Error posting request. Reason = " + testResult.getStatusMessage());
-            }
+            logger.info("Posting ansible request = {} to url = {}", payload, agentUrl);
+            AnsibleResult testResult = postExecRequest(agentUrl, payload, user, pswd);
+            if (testResult != null) {
+                logger.info("Received response on ansible post request {}", testResult.getStatusMessage());
+                // Process if HTTP was successful
+                if (testResult.getStatusCode() == 200) {
+                    testResult = messageProcessor.parsePostResponse(testResult.getStatusMessage());
+                } else {
+                    doFailure(ctx, testResult.getStatusCode(),
+                            "Error posting request. Reason = " + testResult.getStatusMessage());
+                }
 
-            code = testResult.getStatusCode();
-            message = testResult.getStatusMessage();
-
-            // Check status of test request returned by Agent
-            if (code == AnsibleResultCodes.PENDING.getValue()) {
-                logger.info(String.format("Submission of Test %s successful.", playbookName));
-                // test request accepted. We are in asynchronous case
+                code = testResult.getStatusCode();
+                message = testResult.getStatusMessage();
+                ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, testResult.getOutput());
+                ctx.setAttribute(SERVERIP, StringUtils.defaultIfBlank(testResult.getServerIp(), ""));
+                // Check status of test request returned by Agent
+                if (code == AnsibleResultCodes.PENDING.getValue()) {
+                    logger.info("Submission of Test {} successful.", playbookName);
+                    // test request accepted. We are in asynchronous case
+                } else {
+                    doFailure(ctx, code, "Request for execution of playbook rejected. Reason = " + message);
+                }
             } else {
-                doFailure(ctx, code, "Request for execution of playbook rejected. Reason = " + message);
+                doFailure(ctx, code, "Ansible Test result is null");
             }
         } catch (SvcLogicException e) {
             logger.error(APPC_EXCEPTION_CAUGHT, e);
@@ -281,58 +312,160 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
         ctx.setAttribute(ID_ATTRIBUTE_NAME, id);
     }
 
+    /**
+     * Method is used to automatically generate NodeList section base on the svc context
+     */
+    private JSONArray generateNodeList(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
+        String vfModuleId = StringUtils.trimToNull(params.get("vf-module-id"));
+        String vnfcName = StringUtils.trimToNull(params.get("vnfc-name"));
+        String vServerId = StringUtils.trimToNull(params.get("vserver-id"));
+        String vnfcType = StringUtils.trimToNull(params.get("vnfc-type"));
+
+        JSONArray result = new JSONArray();
+        logger.info("GENERATING NODE LIST");
+        logger.debug("Auto Node List filtering parameter vserver-id {} | vnfc-name {} | vnfc-type {} | vf-module-id {}",
+                vServerId, vnfcName, vnfcType, vfModuleId);
+
+        Map<String, JSONObject> candidates = new HashMap<>();
+        for (int i = 0; ; i++) {
+            String vmKey = "tmp.vnfInfo.vm[" + i + "]";
+            logger.info("Looking for attributes of: {}", vmKey);
+            if (ctx.getAttribute(vmKey + ".vnfc-name") != null) {
+                String debugText = "Auto Node List candidate ";
+                String vmVnfcName = ctx.getAttribute(vmKey + ".vnfc-name");
+                String vmVnfcIpv4Address = ctx.getAttribute(vmKey + ".vnfc-ipaddress-v4-oam-vip");
+                String vmVnfcType = ctx.getAttribute(vmKey + ".vnfc-type");
+
+                if (vmVnfcName != null && vmVnfcIpv4Address != null && vmVnfcType != null
+                    && !vmVnfcName.equals("") && !vmVnfcIpv4Address.equals("") && !vmVnfcType.equals("")) {
+                    if (vServerId != null) {
+                        String vmVserverId = ctx.getAttribute(vmKey + ".vserver-id");
+                        if (!vServerId.equals(vmVserverId)) {
+                            logger.debug("{}{} dropped. vserver-id mismatch", debugText, vmVnfcName);
+                            continue;
+                        }
+                    }
+                    if (vfModuleId != null) {
+                        String vmVfModuleId = ctx.getAttribute(vmKey + ".vf-module-id");
+                        if (!vfModuleId.equals(vmVfModuleId)) {
+                            logger.debug("{}{} dropped. vf-module-id mismatch", debugText, vmVnfcName);
+                            continue;
+                        }
+                    }
+                    if (vnfcName != null && !vmVnfcName.equals(vnfcName)) {
+                        logger.debug("{}{} dropped. vnfc-name mismatch", debugText, vmVnfcName);
+                        continue;
+                    }
+                    if (vnfcType != null && !vmVnfcType.equals(vnfcType)) {
+                        logger.debug("{}{} dropped. vnfc-type mismatch", debugText, vmVnfcType);
+                        continue;
+                    }
+
+                    logger.info("{}{} [{},{}]", debugText, vmVnfcName, vmVnfcIpv4Address, vmVnfcType);
+
+                    JSONObject vnfTypeCandidates;
+                    JSONArray vmList;
+                    if (!candidates.containsKey(vmVnfcType)) {
+                        vnfTypeCandidates = new JSONObject();
+                        vmList = new JSONArray();
+                        vnfTypeCandidates.put("site", "site");
+                        vnfTypeCandidates.put("vnfc-type", vmVnfcType);
+                        vnfTypeCandidates.put("vm-info", vmList);
+                        candidates.put(vmVnfcType, vnfTypeCandidates);
+                    } else {
+                        vnfTypeCandidates = candidates.get(vmVnfcType);
+                        vmList = (JSONArray) vnfTypeCandidates.get("vm-info");
+                    }
+
+                    JSONObject candidate = new JSONObject();
+                    candidate.put("ne_id", vmVnfcName);
+                    candidate.put("fixed_ip_address", vmVnfcIpv4Address);
+                    vmList.put(candidate);
+                } else {
+                    logger.warn("Incomplete information for Auto Node List candidate {}", vmKey);
+                }
+            } else {
+                break;
+            }
+        }
+
+        for (JSONObject vnfcCandidates : candidates.values()) {
+            result.put(vnfcCandidates);
+        }
+
+        logger.info("GENERATING NODE LIST COMPLETED");
+        return result;
+    }
+
     /**
      * Public method to query status of a specific request It blocks till the Ansible Server
      * responds or the session times out (non-Javadoc)
      *
      * @see org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapter#reqExecResult(java.util.Map,
-     *      org.onap.ccsdk.sli.core.sli.SvcLogicContext)
+     * org.onap.ccsdk.sli.core.sli.SvcLogicContext)
      */
     @Override
     public void reqExecResult(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
-
         // Get URI
-        String reqUri = StringUtils.EMPTY;
+        String reqUri;
 
         try {
-            reqUri = messageProcessor.reqUriResult(params);
-            logger.info("Got uri ", reqUri );
+            String serverIp = ctx.getAttribute(SERVERIP);
+            if (StringUtils.isNotBlank(serverIp)) {
+                reqUri = messageProcessor.reqUriResultWithIP(params, serverIp);
+            } else {
+                reqUri = messageProcessor.reqUriResult(params);
+            }
+            logger.info("Got uri {}", reqUri);
         } catch (SvcLogicException e) {
             logger.error(APPC_EXCEPTION_CAUGHT, e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
                     "Error constructing request to retrieve result due to missing parameters. Reason = "
-                            + e.getMessage());
+                    + e.getMessage());
             return;
         } catch (NumberFormatException e) {
             logger.error("NumberFormatException caught", e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
                     "Error constructing request to retrieve result due to invalid parameters value. Reason = "
-                            + e.getMessage());
+                    + e.getMessage());
             return;
         }
 
-        int code = -1;
-        String message = StringUtils.EMPTY;
+        int code;
+        String message;
+        String output;
+        String configData;
         String results = StringUtils.EMPTY;
-
+        String finalResponse = StringUtils.EMPTY;
         try {
             // Try to retrieve the test results (modify the URL for that)
-            AnsibleResult testResult = queryServer(reqUri, params.get("User"), params.get(PASSD));
+            AnsibleResult testResult = queryServer(reqUri, params.get(USER),
+                    EncryptionTool.getInstance().decrypt(params.get(PSWD)), ctx);
             code = testResult.getStatusCode();
             message = testResult.getStatusMessage();
 
-            if (code == 200) {
-                logger.info("Parsing response from Server = " + message);
+            if (code == 200 || code == 400 || "FINISHED".equalsIgnoreCase(message)) {
+                logger.info("Parsing response from ansible Server = {}", message);
                 // Valid HTTP. process the Ansible message
                 testResult = messageProcessor.parseGetResponse(message);
                 code = testResult.getStatusCode();
                 message = testResult.getStatusMessage();
                 results = testResult.getResults();
+                output = testResult.getOutput();
+                configData = testResult.getConfigData();
+                if ((StringUtils.isBlank(output)) || (output.trim().equalsIgnoreCase("{}"))) {
+                    finalResponse = results;
+                } else {
+                    finalResponse = output;
+                }
+                logger.info("configData from ansible's response = {}", configData);
+                ctx.setAttribute("device-running-config", configData);
             }
-
             logger.info("Request response = " + message);
         } catch (SvcLogicException e) {
             logger.error(APPC_EXCEPTION_CAUGHT, e);
+            ctx.setAttribute(RESULTS_ATTRIBUTE_NAME, results);
+            ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, finalResponse);
             doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
                     "Exception encountered retrieving result : " + e.getMessage());
             return;
@@ -342,119 +475,146 @@ public class AnsibleAdapterImpl implements AnsibleAdapter {
 
         if (code == AnsibleResultCodes.FINAL_SUCCESS.getValue()) {
             message = String.format("Ansible Request  %s finished with Result = %s, Message = %s", params.get("Id"),
-                    OUTCOME_SUCCESS, message);
+                    SUCCESS, message);
             logger.info(message);
         } else {
             logger.info(String.format("Ansible Request  %s finished with Result %s, Message = %s", params.get("Id"),
-                    OUTCOME_FAILURE, message));
+                    FAILURE, message));
             ctx.setAttribute(RESULTS_ATTRIBUTE_NAME, results);
+            ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, finalResponse);
             doFailure(ctx, code, message);
             return;
         }
 
+        // In case of 200, 400, FINISHED return 400
         ctx.setAttribute(RESULT_CODE_ATTRIBUTE_NAME, Integer.toString(400));
         ctx.setAttribute(MESSAGE_ATTRIBUTE_NAME, message);
         ctx.setAttribute(RESULTS_ATTRIBUTE_NAME, results);
-        ctx.setStatus(OUTCOME_SUCCESS);
+        ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, finalResponse);
+        ctx.markSuccess();
     }
 
     /**
      * Public method to get logs from playbook execution for a specific request
-     *
+     * <p>
      * It blocks till the Ansible Server responds or the session times out very similar to
      * reqExecResult logs are returned in the DG context variable org.onap.appc.adapter.ansible.log
      */
     @Override
     public void reqExecLog(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
-
         String reqUri = StringUtils.EMPTY;
         try {
             reqUri = messageProcessor.reqUriLog(params);
-            logger.info("Retrieving results from " + reqUri);
+            logger.info("Retrieving results from {}", reqUri);
         } catch (Exception e) {
             logger.error("Exception caught", e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(), e.getMessage());
         }
 
-        String message = StringUtils.EMPTY;
-        try {
-            // Try to retrieve the test results (modify the url for that)
-            AnsibleResult testResult = queryServer(reqUri, params.get("User"), params.get(PASSD));
-            message = testResult.getStatusMessage();
-            logger.info("Request output = " + message);
-            ctx.setAttribute(LOG_ATTRIBUTE_NAME, message);
-            ctx.setStatus(OUTCOME_SUCCESS);
-        } catch (Exception e) {
-            logger.error("Exception caught", e);
-            doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
-                    "Exception encountered retreiving output : " + e.getMessage());
-        }
+        queryServerAndProcessResult(params, ctx, reqUri, LOG_ATTRIBUTE_NAME);
     }
 
     /**
      * Public method to get output from playbook execution for a specific request
-     *
+     * <p>
      * It blocks till the Ansible Server responds or the session times out very similar to
      * reqExecResult and output is returned in the DG context variable org.onap.appc.adapter.ansible.output
      */
     @Override
     public void reqExecOutput(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
-
         String reqUri = StringUtils.EMPTY;
         try {
             reqUri = messageProcessor.reqUriOutput(params);
-            logger.info("Retrieving results from " + reqUri);
+            logger.info("Retrieving results from {}", reqUri);
         } catch (Exception e) {
             logger.error("Exception caught", e);
             doFailure(ctx, AnsibleResultCodes.INVALID_PAYLOAD.getValue(), e.getMessage());
         }
 
-        String message = StringUtils.EMPTY;
-        try {
-            // Try to retrieve the test results (modify the url for that)
-            AnsibleResult testResult = queryServer(reqUri, params.get("User"), params.get(PASSD));
-            message = testResult.getStatusMessage();
-            logger.info("Request output = " + message);
-            ctx.setAttribute(OUTPUT_ATTRIBUTE_NAME, message);
-            ctx.setStatus(OUTCOME_SUCCESS);
-        } catch (Exception e) {
-            logger.error("Exception caught", e);
-            doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
-                    "Exception encountered retreiving output : " + e.getMessage());
-        }
+        queryServerAndProcessResult(params, ctx, reqUri, OUTPUT_ATTRIBUTE_NAME);
     }
 
     /**
      * Method that posts the request
      */
-    private AnsibleResult postExecRequest(String agentUrl, String payload, String user, String password) {
-
-        AnsibleResult testResult;
-
+    private AnsibleResult postExecRequest(String agentUrl, String payload, String user, String pswd) {
+        AnsibleResult testResult = null;
+        ConnectionBuilder httpClientLocal = getHttpConn(defaultSocketTimeout, "");
         if (!testMode) {
-            httpClient.setHttpContext(user, password);
-            testResult = httpClient.post(agentUrl, payload);
+            if (httpClientLocal != null) {
+                httpClientLocal.setHttpContext(user, pswd);
+                testResult = httpClientLocal.post(agentUrl, payload);
+                httpClientLocal.close();
+            }
         } else {
-            testResult = testServer.Post(agentUrl, payload);
+            testResult = testServer.post(payload);
         }
         return testResult;
     }
 
+    private void queryServerAndProcessResult(Map<String, String> params, SvcLogicContext ctx, String reqUri, String attributeName)
+            throws SvcLogicException {
+        try {
+            // Try to retrieve the test results (modify the url for that)
+            AnsibleResult testResult = queryServer(reqUri, params.get(USER),
+                    EncryptionTool.getInstance().decrypt(params.get(PSWD)), ctx);
+            String message = testResult.getStatusMessage();
+            logger.info("Request output = {}", message);
+            ctx.setAttribute(attributeName, message);
+            ctx.markSuccess();
+        } catch (Exception e) {
+            logger.error("Exception caught: {}", e.getMessage(), e);
+            doFailure(ctx, AnsibleResultCodes.UNKNOWN_EXCEPTION.getValue(),
+                    String.format("Exception encountered retrieving output: %s", e.getMessage()));
+        }
+    }
+
     /**
      * Method to query Ansible server
      */
-    private AnsibleResult queryServer(String agentUrl, String user, String password) {
-
-        AnsibleResult testResult;
+    private AnsibleResult queryServer(String agentUrl, String user, String pswd, SvcLogicContext ctx) {
+        AnsibleResult testResult = new AnsibleResult();
+        int timeout;
+        try {
+            timeout = Integer.parseInt(ctx.getAttribute("AnsibleTimeout")) * 1000;
+        } catch (Exception e) {
+            timeout = defaultTimeout;
+        }
+        long endTime = System.currentTimeMillis() + timeout;
+
+        while (System.currentTimeMillis() < endTime) {
+            String serverIP = ctx.getAttribute(SERVERIP);
+            ConnectionBuilder httpClientLocal = getHttpConn(defaultSocketTimeout, serverIP);
+            logger.info("Querying ansible GetResult URL = {}", agentUrl);
+
+            if (!testMode) {
+                if (httpClientLocal != null) {
+                    httpClientLocal.setHttpContext(user, pswd);
+                    testResult = httpClientLocal.get(agentUrl);
+                    httpClientLocal.close();
+                }
+            } else {
+                testResult = testServer.get(agentUrl);
+            }
+            if (testResult.getStatusCode() != AnsibleResultCodes.IO_EXCEPTION.getValue()
+                && testResult.getStatusCode() != AnsibleResultCodes.PENDING.getValue()) {
+                break;
+            }
 
-        logger.info("Querying url = " + agentUrl);
+            try {
+                Thread.sleep(defaultPollInterval);
+            } catch (InterruptedException ex) {
+                logger.error("Thread Interrupted Exception", ex);
+                Thread.currentThread().interrupt();
+            }
 
-        if (!testMode) {
-            testResult = httpClient.get(agentUrl);
-        } else {
-            testResult = testServer.Get(agentUrl);
+        }
+        if (testResult.getStatusCode() == AnsibleResultCodes.PENDING.getValue()) {
+            testResult.setStatusCode(AnsibleResultCodes.IO_EXCEPTION.getValue());
+            testResult.setStatusMessage("Request timed out");
         }
 
         return testResult;
     }
+
 }
index 36eec6a..e465e13 100755 (executable)
@@ -1,8 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * onap
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2016 - 2017 ONAP
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
 
@@ -24,9 +26,10 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
-import java.util.Vector;
 import org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterPropertiesProvider;
 import org.onap.ccsdk.sli.core.sli.ConfigurationException;
 import org.onap.ccsdk.sli.core.utils.JREFileResolver;
@@ -60,12 +63,12 @@ public class AnsibleAdapterPropertiesProviderImpl implements AnsibleAdapterPrope
     /**
      * The name of the properties file for database configuration
      */
-    private static final String ANSIBLEADAPTER_PROP_FILE_NAME = "ansible-adapter.properties";
+    private static final String ANSIBLE_ADAPTER_PROPERTIES = "ansible-adapter.properties";
 
     /**
      * A prioritized list of strategies for resolving sql-resource properties files.
      */
-    private Vector<PropertiesFileResolver> ansibleAdapterPropertiesFileResolvers = new Vector<>();
+    private final List<PropertiesFileResolver> ansibleAdapterPropertiesFileResolvers = new ArrayList<>();
 
     /**
      * The configuration properties for the db connection.
@@ -79,28 +82,27 @@ public class AnsibleAdapterPropertiesProviderImpl implements AnsibleAdapterPrope
     public AnsibleAdapterPropertiesProviderImpl() {
         ansibleAdapterPropertiesFileResolvers
                 .add(new SdncConfigEnvVarFileResolver("Using property file (1) from environment variable"));
-        ansibleAdapterPropertiesFileResolvers.add(new CoreDefaultFileResolver("Using property file (2) from default directory"));
-
-        ansibleAdapterPropertiesFileResolvers.add(
-                new JREFileResolver("Using property file (3) from JRE argument", AnsibleAdapterPropertiesProviderImpl.class));
-        ansibleAdapterPropertiesFileResolvers.add(new KarafRootFileResolver("Using property file (4) from karaf root", this));
+        ansibleAdapterPropertiesFileResolvers
+                .add(new CoreDefaultFileResolver("Using property file (2) from default directory"));
+        ansibleAdapterPropertiesFileResolvers
+                .add(new JREFileResolver("Using property file (3) from JRE argument", AnsibleAdapterPropertiesProviderImpl.class));
+        ansibleAdapterPropertiesFileResolvers
+                .add(new KarafRootFileResolver("Using property file (4) from karaf root", this));
 
         // determines properties file as according to the priority described in the
         // class header comment
-        final File propertiesFile = determinePropertiesFile(this);
+        final File propertiesFile = determinePropertiesFile();
         if (propertiesFile != null) {
             try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) {
                 properties = new EnvProperties();
                 properties.load(fileInputStream);
             } catch (final IOException e) {
-                LOG.error("Failed to load properties for file: {}", propertiesFile.toString(),
-                        new ConfigurationException("Failed to load properties for file: " + propertiesFile.toString(),
-                                e));
+                LOG.error("Failed to load properties for file: {}", propertiesFile,
+                        new ConfigurationException("Failed to load properties for file: " + propertiesFile, e));
             }
         } else {
             // Try to read properties as resource
-
-            InputStream propStr = getClass().getResourceAsStream("/" + ANSIBLEADAPTER_PROP_FILE_NAME);
+            InputStream propStr = getClass().getResourceAsStream("/" + ANSIBLE_ADAPTER_PROPERTIES);
             if (propStr != null) {
                 properties = new EnvProperties();
                 try {
@@ -110,37 +112,46 @@ public class AnsibleAdapterPropertiesProviderImpl implements AnsibleAdapterPrope
                     properties = null;
                 }
             }
-
         }
-
         if (properties == null) {
-            reportFailure("Missing configuration properties resource(3)", new ConfigurationException(
-                    "Missing configuration properties resource(3): " + ANSIBLEADAPTER_PROP_FILE_NAME));
-
+            reportFailure(new ConfigurationException(
+                    "Missing configuration properties resource(3): " + ANSIBLE_ADAPTER_PROPERTIES));
             LOG.info("Defaulting org.onap.appc.adapter.ansible.clientType to TRUST_ALL");
-
             properties = new Properties();
             properties.setProperty("org.onap.appc.adapter.ansible.clientType", "TRUST_ALL");
         }
+
     }
 
     /**
-     * Extract svclogic config properties.
+     * Instantiates a new Ansible adapter properties provider.
      *
-     * @return the svclogic config properties
+     * @param configFilePath the config file path
      */
-    public Properties getProperties() {
-        return properties;
+    public AnsibleAdapterPropertiesProviderImpl(String configFilePath) {
+        properties = new EnvProperties();
+        try {
+            properties.load(new FileInputStream(configFilePath));
+        } catch (IOException e) {
+            properties = null;
+        }
+        if (properties == null) {
+            reportFailure(new ConfigurationException(
+                    "Missing configuration properties resource(3): " + ANSIBLE_ADAPTER_PROPERTIES));
+            LOG.info("Defaulting org.onap.appc.adapter.ansible.clientType to TRUST_ALL");
+            properties = new Properties();
+            properties.setProperty("org.onap.appc.adapter.ansible.clientType", "TRUST_ALL");
+        }
+
     }
 
     /**
      * Reports the method chosen for properties resolution to the
      * <code>Logger</code>.
      *
-     * @param message
-     *            Some user friendly message
-     * @param fileOptional
-     *            The file location of the chosen properties file
+     * @param message      Some user friendly message
+     * @param fileOptional The file location of the chosen properties file
+     *
      * @return the file location of the chosen properties file
      */
     private static File reportSuccess(final String message, final Optional<File> fileOptional) {
@@ -156,14 +167,19 @@ public class AnsibleAdapterPropertiesProviderImpl implements AnsibleAdapterPrope
      * Reports fatal errors. This is the case in which no properties file could be
      * found.
      *
-     * @param message
-     *            An appropriate fatal error message
-     * @param configurationException
-     *            An exception describing what went wrong during resolution
+     * @param configurationException An exception describing what went wrong during resolution
      */
-    private static void reportFailure(final String message, final ConfigurationException configurationException) {
+    private static void reportFailure(final ConfigurationException configurationException) {
+        LOG.error("{}", "Missing configuration properties resource(3)", configurationException);
+    }
 
-        LOG.error("{}", message, configurationException);
+    /**
+     * Extract svclogic config properties.
+     *
+     * @return the svclogic config properties
+     */
+    public Properties getProperties() {
+        return properties;
     }
 
     /**
@@ -178,15 +194,15 @@ public class AnsibleAdapterPropertiesProviderImpl implements AnsibleAdapterPrope
      * directory</li>
      * </ol>
      */
-    File determinePropertiesFile(final AnsibleAdapterPropertiesProviderImpl resourceProvider) {
-
-        for (final PropertiesFileResolver sliPropertiesFileResolver : ansibleAdapterPropertiesFileResolvers) {
-            final Optional<File> fileOptional = sliPropertiesFileResolver.resolveFile(ANSIBLEADAPTER_PROP_FILE_NAME);
+    File determinePropertiesFile() {
+        for (final PropertiesFileResolver propertiesFileResolver : ansibleAdapterPropertiesFileResolvers) {
+            final Optional<File> fileOptional = propertiesFileResolver.resolveFile(ANSIBLE_ADAPTER_PROPERTIES);
             if (fileOptional.isPresent()) {
-                return reportSuccess(sliPropertiesFileResolver.getSuccessfulResolutionMessage(), fileOptional);
+                return reportSuccess(propertiesFileResolver.getSuccessfulResolutionMessage(), fileOptional);
             }
         }
 
         return null;
     }
+
 }
index 672e0df..1fbf206 100644 (file)
@@ -1,13 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * ================================================================================
- * Modifications Copyright Â© 2018 IBM.
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -26,6 +22,9 @@
 
 package org.onap.ccsdk.sli.adaptors.ansible.impl;
 
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.io.Closeable;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.security.KeyManagementException;
@@ -36,13 +35,16 @@ import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import javax.net.ssl.SSLContext;
+import org.apache.commons.lang.StringUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.auth.AuthScope;
 import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.conn.ssl.SSLContexts;
 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
@@ -51,13 +53,11 @@ import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
+import org.json.JSONObject;
 import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResult;
 import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResultCodes;
 import org.onap.ccsdk.sli.core.utils.PathValidator;
 
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
-
 /**
  * Returns a custom http client
  * - based on options
@@ -67,35 +67,36 @@ import com.att.eelf.configuration.EELFManager;
  * option
  **/
 
-public class ConnectionBuilder {
-
+public class ConnectionBuilder implements Closeable {
+    private static final String STATUS_CODE_KEY = "StatusCode";
     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ConnectionBuilder.class);
 
-    private CloseableHttpClient httpClient = null;
-    private HttpClientContext httpContext = new HttpClientContext();
+    private final CloseableHttpClient httpClient;
+    private final HttpClientContext httpContext = new HttpClientContext();
 
     /**
      * Constructor that initializes an http client based on certificate
      **/
-    public ConnectionBuilder(String certFile) throws KeyStoreException, CertificateException, IOException,
+    public ConnectionBuilder(String certFile, int timeout) throws KeyStoreException, CertificateException, IOException,
             KeyManagementException, NoSuchAlgorithmException {
 
         /* Point to the certificate */
-        try(FileInputStream fs = new FileInputStream(certFile)){
-               /* Generate a certificate from the X509 */
-               CertificateFactory cf = CertificateFactory.getInstance("X.509");
-               X509Certificate cert = (X509Certificate) cf.generateCertificate(fs);
+        try (FileInputStream fs = new FileInputStream(certFile)) {
+            /* Generate a certificate from the X509 */
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            X509Certificate cert = (X509Certificate) cf.generateCertificate(fs);
 
-               /* Create a keystore object and load the certificate there */
-               KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
-               keystore.load(null, null);
-               keystore.setCertificateEntry("cacert", cert);
+            /* Create a keystore object and load the certificate there */
+            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+            keystore.load(null, null);
+            keystore.setCertificateEntry("cacert", cert);
 
-               SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore).build();
-               SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
-                       SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore).build();
+            SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
+                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
 
-               httpClient = HttpClients.custom().setSSLSocketFactory(factory).build();
+            RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
+            httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
         }
     }
 
@@ -103,9 +104,9 @@ public class ConnectionBuilder {
      * Constructor which trusts all certificates in a specific java keystore file (assumes a JKS
      * file)
      **/
-    public ConnectionBuilder(String trustStoreFile, char[] trustStorePasswd) throws KeyStoreException, IOException,
-            KeyManagementException, NoSuchAlgorithmException, CertificateException {
-
+    public ConnectionBuilder(String trustStoreFile, char[] trustStorePasswd, int timeout, String serverIP)
+            throws KeyStoreException, IOException, KeyManagementException, NoSuchAlgorithmException,
+            CertificateException {
         if (!PathValidator.isValidFilePath(trustStoreFile)) {
             throw new IOException("Invalid trust store file path");
         }
@@ -114,37 +115,45 @@ public class ConnectionBuilder {
         KeyStore keystore = KeyStore.getInstance("JKS");
         FileInputStream readStream = new FileInputStream(trustStoreFile);
         keystore.load(readStream, trustStorePasswd);
+        if (StringUtils.isNotBlank(serverIP)) {
+            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
+            SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier());
 
-        SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore).build();
-        SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
-                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
-
-        httpClient = HttpClients.custom().setSSLSocketFactory(factory).build();
+            RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
+            httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
+        } else {
+            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore).build();
+            SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
+                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+            RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
+            httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
+        }
     }
 
     /**
      * Constructor that trusts ALL SSl certificates (NOTE : ONLY FOR DEV TESTING) if Mode == 1 or
      * Default if Mode == 0
      */
-    public ConnectionBuilder(int mode)
+    public ConnectionBuilder(int mode, int timeout)
             throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+        RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
         if (mode == 1) {
             SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
             SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
                     SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
 
-            httpClient = HttpClients.custom().setSSLSocketFactory(factory).build();
+            httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
         } else {
-            httpClient = HttpClients.createDefault();
+            httpClient = HttpClients.custom().setDefaultRequestConfig(config).build();
         }
     }
 
     // Use to create an http context with auth headers
-    public void setHttpContext(String user, String myPassword) {
+    public void setHttpContext(String user, String pswd) {
 
         // Are credential provided ? If so, set the context to be used
-        if (user != null && !user.isEmpty() && myPassword != null && !myPassword.isEmpty()) {
-            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, myPassword);
+        if (user != null && !user.isEmpty() && pswd != null && !pswd.isEmpty()) {
+            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, pswd);
             AuthScope authscope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT);
             BasicCredentialsProvider credsprovider = new BasicCredentialsProvider();
             credsprovider.setCredentials(authscope, credentials);
@@ -165,7 +174,6 @@ public class ConnectionBuilder {
             postObj.addHeader("Content-type", "application/json");
 
             HttpResponse response = httpClient.execute(postObj, httpContext);
-
             HttpEntity entity = response.getEntity();
             String responseOutput = entity != null ? EntityUtils.toString(entity) : null;
             int responseCode = response.getStatusLine().getStatusCode();
@@ -189,11 +197,21 @@ public class ConnectionBuilder {
         try {
             HttpGet getObj = new HttpGet(agentUrl);
             HttpResponse response = httpClient.execute(getObj, httpContext);
-
             HttpEntity entity = response.getEntity();
             String responseOutput = entity != null ? EntityUtils.toString(entity) : null;
             int responseCode = response.getStatusLine().getStatusCode();
-            result.setStatusCode(responseCode);
+            logger.info("GetResult response for ansible GET URL" + agentUrl + " returned " + responseOutput);
+            JSONObject postResponse = new JSONObject(responseOutput);
+            if (postResponse.has(STATUS_CODE_KEY)) {
+                int codeStatus = postResponse.getInt(STATUS_CODE_KEY);
+                if (codeStatus == AnsibleResultCodes.PENDING.getValue()) {
+                    result.setStatusCode(codeStatus);
+                } else {
+                    result.setStatusCode(responseCode);
+                }
+            } else {
+                result.setStatusCode(responseCode);
+            }
             result.setStatusMessage(responseOutput);
         } catch (IOException io) {
             result.setStatusCode(AnsibleResultCodes.IO_EXCEPTION.getValue());
@@ -202,4 +220,16 @@ public class ConnectionBuilder {
         }
         return result;
     }
+
+    @Override
+    public void close() {
+        try {
+            if (httpClient != null) {
+                httpClient.close();
+            }
+        } catch (IOException e) {
+            logger.error("Caught IOException during httpClient close", e);
+        }
+    }
+
 }
index 5f6342d..e448f1c 100644 (file)
@@ -1,12 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
- * Modifications Copyright (C) 2018 IBM.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.ccsdk.sli.adaptors.ansible.model;
 
-/**
- * This module implements the APP-C/Ansible Server interface
- * based on the REST API specifications
- */
+import com.google.common.base.Strings;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
+import org.apache.commons.lang.StringUtils;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants;
 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-import com.google.common.base.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.*;
+
 /**
  * Class that validates and constructs requests sent/received from
  * Ansible Server
  */
 public class AnsibleMessageParser {
 
-    private static final String STATUS_MESSAGE_KEY = "StatusMessage";
-    private static final String STATUS_CODE_KEY = "StatusCode";
 
-    private static final String PLAYBOOK_NAME_KEY = "PlaybookName";
-    private static final String AGENT_URL_KEY = "AgentUrl";
-    private static final String PASS_KEY = "Password";
-    private static final String USER_KEY = "User";
-    private static final String ID_KEY = "Id";
+    private static final String JSON_ERROR_MESSAGE = "JSONException: Error parsing response";
 
-    private static final String LOCAL_PARAMETERS_OPT_KEY = "LocalParameters";
-    private static final String FILE_PARAMETERS_OPT_KEY = "FileParameters";
-    private static final String ENV_PARAMETERS_OPT_KEY = "EnvParameters";
-    private static final String NODE_LIST_OPT_KEY = "NodeList";
-    private static final String TIMEOUT_OPT_KEY = "Timeout";
-    private static final String VERSION_OPT_KEY = "Version";
-    private static final String ACTION_OPT_KEY = "Action";
-
-    private String jsonException = "JSON exception";
     private static final Logger LOGGER = LoggerFactory.getLogger(AnsibleMessageParser.class);
 
     /**
      * Accepts a map of strings and
      * a) validates if all parameters are appropriate (else, throws an exception) and
      * b) if correct returns a JSON object with appropriate key-value pairs to send to the server.
-     *
+     * <p>
      * Mandatory parameters, that must be in the supplied information to the Ansible Adapter
      * 1. URL to connect to
-     * 2. credentials for URL (assume username password for now)
+     * 2. credentials for URL (assume user pswd for now)
      * 3. Playbook name
-     *
      */
     public JSONObject reqMessage(Map<String, String> params) throws SvcLogicException {
-        final String[] mandatoryTestParams = {AGENT_URL_KEY, PLAYBOOK_NAME_KEY, USER_KEY, PASS_KEY};
-        final String[] optionalTestParams = {ENV_PARAMETERS_OPT_KEY, NODE_LIST_OPT_KEY, LOCAL_PARAMETERS_OPT_KEY,
-                TIMEOUT_OPT_KEY, VERSION_OPT_KEY, FILE_PARAMETERS_OPT_KEY, ACTION_OPT_KEY};
-
+        final String[] mandatoryTestParams = {AGENT_URL, PLAYBOOK_NAME, USER, PSWD};
+        final String[] optionalTestParams = {ENV_PARAMETERS, NODE_LIST, LOCAL_PARAMETERS, TIMEOUT, VERSION, FILE_PARAMETERS,
+                                             ACTION, INVENTORY_NAMES, AUTO_NODE_LIST};
         JSONObject jsonPayload = new JSONObject();
 
         for (String key : mandatoryTestParams) {
@@ -97,8 +76,7 @@ public class AnsibleMessageParser {
 
         // Generate a unique uuid for the test
         String reqId = UUID.randomUUID().toString();
-        jsonPayload.put(ID_KEY, reqId);
-
+        jsonPayload.put(ID, reqId);
         return jsonPayload;
     }
 
@@ -108,28 +86,39 @@ public class AnsibleMessageParser {
      * the appropriate url, else an empty string.
      */
     public String reqUriResult(Map<String, String> params) throws SvcLogicException {
+        final String[] mandatoryTestParams = {AGENT_URL, ID, USER, PSWD};
+        for (String key : mandatoryTestParams) {
+            throwIfMissingMandatoryParam(params, key);
+        }
+        return params.get(AGENT_URL) + "?Id=" + params.get(ID) + "&Type=GetResult";
+    }
 
-        final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
-
+    /**
+     * Method that validates that the Map has enough information to query Ansible
+     * server for a result. If so, it returns the appropriate url, else an empty
+     * string.
+     */
+    public String reqUriResultWithIP(Map<String, String> params, String serverIP) throws SvcLogicException {
+        final String[] mandatoryTestParams = {AGENT_URL, ID, USER, PSWD};
         for (String key : mandatoryTestParams) {
             throwIfMissingMandatoryParam(params, key);
         }
-        return params.get(AGENT_URL_KEY) + "?Id=" + params.get(ID_KEY) + "&Type=GetResult";
+        String[] arr1 = params.get(AGENT_URL).split("//", 2);
+        String[] arr2 = arr1[1].split(":", 2);
+        return arr1[0] + "//" + serverIP + ":" + arr2[1] + "?Id=" + params.get(ID) + "&Type=GetResult";
     }
 
     /**
-     * Method that validates that the Map has enough information
-     * to query Ansible server for logs. If so, it populates the appropriate
-     * returns the appropriate url, else an empty string.
+     * Method that validates that the Map has enough information to query Ansible
+     * server for logs. If so, it populates the appropriate returns the appropriate
+     * url, else an empty string.
      */
     public String reqUriLog(Map<String, String> params) throws SvcLogicException {
-
-        final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
-
+        final String[] mandatoryTestParams = {AGENT_URL, ID, USER, PSWD};
         for (String mandatoryParam : mandatoryTestParams) {
             throwIfMissingMandatoryParam(params, mandatoryParam);
         }
-        return params.get(AGENT_URL_KEY) + "?Id=" + params.get(ID_KEY) + "&Type=GetLog";
+        return params.get(AGENT_URL) + "?Id=" + params.get(ID) + "&Type=GetLog";
     }
 
     /**
@@ -138,13 +127,11 @@ public class AnsibleMessageParser {
      * the appropriate url, else an empty string.
      */
     public String reqUriOutput(Map<String, String> params) throws SvcLogicException {
-
-        final String[] mandatoryTestParams = {AGENT_URL_KEY, ID_KEY, USER_KEY, PASS_KEY};
-
+        final String[] mandatoryTestParams = {AGENT_URL, ID, USER, PSWD};
         for (String mandatoryParam : mandatoryTestParams) {
             throwIfMissingMandatoryParam(params, mandatoryParam);
         }
-        return params.get(AGENT_URL_KEY) + "?Id=" + params.get(ID_KEY) + "&Type=GetOutput";
+        return params.get(AGENT_URL) + "?Id=" + params.get(ID) + "&Type=GetOutput";
     }
 
     /**
@@ -155,21 +142,25 @@ public class AnsibleMessageParser {
         AnsibleResult ansibleResult;
         try {
             JSONObject postResponse = new JSONObject(input);
-
-            int code = postResponse.getInt(STATUS_CODE_KEY);
-            String msg = postResponse.getString(STATUS_MESSAGE_KEY);
-
+            int code = postResponse.getInt(STATUS_CODE);
             int initResponseValue = AnsibleResultCodes.INITRESPONSE.getValue();
             boolean validCode = AnsibleResultCodes.CODE.checkValidCode(initResponseValue, code);
             if (!validCode) {
-                throw new SvcLogicException("Invalid InitResponse code  = " + code + " received. MUST be one of "
-                        + AnsibleResultCodes.CODE.getValidCodes(initResponseValue));
+                throw new SvcLogicException(String.format("Invalid InitResponse code = %s received. MUST be one of %s",
+                        code, AnsibleResultCodes.CODE.getValidCodes(initResponseValue)));
             }
 
-            ansibleResult = new AnsibleResult(code, msg);
-
+            ansibleResult = new AnsibleResult(code, postResponse.getString(STATUS_MESSAGE));
+            if (postResponse.has(ANSIBLE_SERVER) && StringUtils.isNotBlank(postResponse.getString(ANSIBLE_SERVER))) {
+                ansibleResult.setServerIp(postResponse.getString(ANSIBLE_SERVER));
+            }
+            if (!postResponse.isNull(OUTPUT)) {
+                LOGGER.info("Processing results-output in post response");
+                JSONObject output = postResponse.getJSONObject(OUTPUT);
+                ansibleResult.setOutput(output.toString());
+            }
         } catch (JSONException e) {
-            LOGGER.error(jsonException, e);
+            LOGGER.error(JSON_ERROR_MESSAGE, e);
             ansibleResult = new AnsibleResult(600, "Error parsing response = " + input + ". Error = " + e.getMessage());
         }
         return ansibleResult;
@@ -180,36 +171,31 @@ public class AnsibleMessageParser {
      * and returns an AnsibleResult object.
      **/
     public AnsibleResult parseGetResponse(String input) throws SvcLogicException {
-
         AnsibleResult ansibleResult = new AnsibleResult();
-
         try {
             JSONObject postResponse = new JSONObject(input);
-            ansibleResult = parseGetResponseNested(ansibleResult, postResponse);
+            parseGetResponseNested(ansibleResult, postResponse);
         } catch (JSONException e) {
-            LOGGER.error(jsonException, e);
+            LOGGER.error(JSON_ERROR_MESSAGE, e);
             ansibleResult = new AnsibleResult(AnsibleResultCodes.INVALID_PAYLOAD.getValue(),
                     "Error parsing response = " + input + ". Error = " + e.getMessage(), "");
         }
         return ansibleResult;
     }
 
-    private AnsibleResult parseGetResponseNested(AnsibleResult ansibleResult, JSONObject postRsp) throws SvcLogicException  {
-
-        int codeStatus = postRsp.getInt(STATUS_CODE_KEY);
-        String messageStatus = postRsp.getString(STATUS_MESSAGE_KEY);
+    private void parseGetResponseNested(AnsibleResult ansibleResult, JSONObject postRsp) throws SvcLogicException {
+        String messageStatus = postRsp.getString(STATUS_MESSAGE);
+        int codeStatus = postRsp.getInt(STATUS_CODE);
         int finalCode = AnsibleResultCodes.FINAL_SUCCESS.getValue();
-
-        boolean valCode =
-                AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.FINALRESPONSE.getValue(), codeStatus);
-
+        boolean valCode = AnsibleResultCodes.CODE.checkValidCode(AnsibleResultCodes.FINALRESPONSE.getValue(), codeStatus);
         if (!valCode) {
-            throw new SvcLogicException("Invalid FinalResponse code  = " + codeStatus + " received. MUST be one of "
-                    + AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.FINALRESPONSE.getValue()));
+            throw new SvcLogicException(String.format("Invalid InitResponse code = %s received. MUST be one of %s",
+                    codeStatus, AnsibleResultCodes.CODE.getValidCodes(AnsibleResultCodes.FINALRESPONSE.getValue())));
         }
 
         ansibleResult.setStatusCode(codeStatus);
         ansibleResult.setStatusMessage(messageStatus);
+        ansibleResult.setConfigData("UNKNOWN");
         LOGGER.info("Received response with code = {}, Message = {}", codeStatus, messageStatus);
 
         if (!postRsp.isNull("Results")) {
@@ -219,43 +205,51 @@ public class AnsibleMessageParser {
 
             LOGGER.info("Processing results in response");
             JSONObject results = postRsp.getJSONObject("Results");
-            LOGGER.info("Get JSON dictionary from Results ..");
-            Iterator<String> hosts = results.keys();
-            LOGGER.info("Iterating through hosts");
 
+            LOGGER.info("Get JSON dictionary from Results by Iterating through hosts");
+            Iterator<String> hosts = results.keys();
             while (hosts.hasNext()) {
                 String host = hosts.next();
-                LOGGER.info("Processing host = {}", host);
-
+                LOGGER.info("Processing host = {}",
+                        (host.matches("^[\\w\\-.]+$")) ? host : "[unexpected value, logging suppressed]");
                 try {
                     JSONObject hostResponse = results.getJSONObject(host);
-                    int subCode = hostResponse.getInt(STATUS_CODE_KEY);
-                    String message = hostResponse.getString(STATUS_MESSAGE_KEY);
+                    int subCode = hostResponse.getInt(STATUS_CODE);
+                    String message = hostResponse.getString(STATUS_MESSAGE);
 
                     LOGGER.info("Code = {}, Message = {}", subCode, message);
 
-                    if (subCode != 200 || !("SUCCESS").equals(message)) {
+                    if (subCode != 200 || !"SUCCESS".equals(message)) {
                         finalCode = AnsibleResultCodes.REQ_FAILURE.getValue();
                     }
+                    if ((hostResponse.optJSONObject(OUTPUT)) != null) {
+                        JSONObject hostResponseObjectInfo = hostResponse.optJSONObject(OUTPUT).optJSONObject("info");
+                        JSONObject hostResponseConfigData = hostResponseObjectInfo.optJSONObject("configData");
+                        if (hostResponseConfigData != null) {
+                            ansibleResult.setConfigData(hostResponseConfigData.toString());
+                        }
+                    }
                 } catch (JSONException e) {
-                    LOGGER.error(jsonException, e);
+                    LOGGER.error(JSON_ERROR_MESSAGE, e);
                     ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
-                    ansibleResult.setStatusMessage(String.format(
-                            "Error processing response message = %s from host %s", results.getString(host), host));
+                    ansibleResult.setStatusMessage(String.format("Error processing response message = %s from host %s",
+                            results.getString(host), host));
                     break;
                 }
             }
-
             ansibleResult.setStatusCode(finalCode);
 
             // We return entire Results object as message
             ansibleResult.setResults(results.toString());
-
         } else {
             ansibleResult.setStatusCode(AnsibleResultCodes.INVALID_RESPONSE.getValue());
             ansibleResult.setStatusMessage("Results not found in GET for response");
         }
-        return ansibleResult;
+        if (!postRsp.isNull(OUTPUT)) {
+            LOGGER.info("Processing results-output in response");
+            JSONObject output = postRsp.getJSONObject(OUTPUT);
+            ansibleResult.setOutput(output.toString());
+        }
     }
 
     private void parseOptionalParams(Map<String, String> params, String[] optionalTestParams, JSONObject jsonPayload) {
@@ -264,11 +258,9 @@ public class AnsibleMessageParser {
         Collections.addAll(optionalParamsSet, optionalTestParams);
 
         //@formatter:off
-        params.entrySet()
-            .stream()
-            .filter(entry -> optionalParamsSet.contains(entry.getKey()))
-            .filter(entry -> !Strings.isNullOrEmpty(entry.getValue()))
-             .forEach(entry -> parseOptionalParam(entry, jsonPayload));
+        params.entrySet().stream().filter(entry -> optionalParamsSet.contains(entry.getKey()))
+                .filter(entry -> !Strings.isNullOrEmpty(entry.getValue()))
+                .forEach(entry -> parseOptionalParam(entry, jsonPayload));
         //@formatter:on
     }
 
@@ -277,30 +269,51 @@ public class AnsibleMessageParser {
         String payload = params.getValue();
 
         switch (key) {
-            case TIMEOUT_OPT_KEY:
+            case TIMEOUT:
+                if (dataIsVariable(payload)) {
+                    break;
+                }
                 int timeout = Integer.parseInt(payload);
                 if (timeout < 0) {
                     throw new NumberFormatException(" : specified negative integer for timeout = " + payload);
                 }
                 jsonPayload.put(key, payload);
                 break;
-
-            case VERSION_OPT_KEY:
+            case AUTO_NODE_LIST:
+                if (payload.equalsIgnoreCase("true") || payload.equalsIgnoreCase("false")) {
+                    jsonPayload.put(key, payload);
+                } else {
+                    throw new IllegalArgumentException(" : specified invalid boolean value of AutoNodeList = " + payload);
+                }
+                break;
+            case VERSION:
+                if (dataIsVariable(payload)) {
+                    break;
+                }
+            case INVENTORY_NAMES:
                 jsonPayload.put(key, payload);
                 break;
 
-            case LOCAL_PARAMETERS_OPT_KEY:
-            case ENV_PARAMETERS_OPT_KEY:
+            case LOCAL_PARAMETERS:
+            case ENV_PARAMETERS:
+            case EXTRA_VARS:
                 JSONObject paramsJson = new JSONObject(payload);
+                jsonDataIsVariable(paramsJson);
                 jsonPayload.put(key, paramsJson);
                 break;
 
-            case NODE_LIST_OPT_KEY:
+            case NODE_LIST:
+                if (payload.startsWith("$")) {
+                    break;
+                }
                 JSONArray paramsArray = new JSONArray(payload);
                 jsonPayload.put(key, paramsArray);
                 break;
 
-            case FILE_PARAMETERS_OPT_KEY:
+            case FILE_PARAMETERS:
+                if (dataIsVariable(payload)) {
+                    break;
+                }
                 jsonPayload.put(key, getFilePayload(payload));
                 break;
 
@@ -320,13 +333,35 @@ public class AnsibleMessageParser {
     private void throwIfMissingMandatoryParam(Map<String, String> params, String key) throws SvcLogicException {
         if (!params.containsKey(key)) {
             throw new SvcLogicException(String.format(
-                    "Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !",
-                    key));
+                    "Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
         }
         if (Strings.isNullOrEmpty(params.get(key))) {
             throw new SvcLogicException(String.format(
-                    "Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !",
-                    key));
+                    "Ansible: Mandatory AnsibleAdapter key %s not found in parameters provided by calling agent !", key));
+        }
+        if (StringUtils.startsWith(params.get(key), "$")) {
+            throw new SvcLogicException(String.format(
+                    "Ansible: Mandatory AnsibleAdapter key %s is a variable", key));
         }
     }
+
+    private boolean dataIsVariable(String payload) {
+        return StringUtils.startsWith(payload, "$") || StringUtils.isEmpty(payload);
+    }
+
+    private void jsonDataIsVariable(JSONObject paramsJson) {
+        LOGGER.info("input json is " + paramsJson);
+        String[] keys = JSONObject.getNames(paramsJson);
+        for (String k : keys) {
+            Object a = paramsJson.get(k);
+            if (a instanceof String) {
+                if (StringUtils.startsWith(a.toString(), "$") || StringUtils.isEmpty(a.toString())) {
+                    LOGGER.info("removing key " + k);
+                    paramsJson.remove(k);
+                }
+            }
+        }
+        LOGGER.info("returning json as {}", paramsJson);
+    }
+
 }
index 3d1b3cf..bad0f5e 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -25,7 +23,7 @@
 package org.onap.ccsdk.sli.adaptors.ansible.model;
 
 /**
- *  Simple class to store code and message returned by POST/GET to an Ansible Server
+ * Simple class to store code and message returned by POST/GET to an Ansible Server
  */
 public class AnsibleResult {
 
@@ -34,6 +32,9 @@ public class AnsibleResult {
     private int statusCode;
     private String statusMessage;
     private String results;
+    private String output;
+    private String serverIp;
+    private String configData;
 
     public AnsibleResult() {
         this(-1, EMPTY_VALUE, EMPTY_VALUE);
@@ -49,33 +50,66 @@ public class AnsibleResult {
         results = result;
     }
 
-    public void setStatusCode(int code) {
-        this.statusCode = code;
+    public AnsibleResult(int code, String message, String result, String outputData) {
+        statusCode = code;
+        statusMessage = message;
+        results = result;
+        output = outputData;
     }
 
-    public void setStatusMessage(String message) {
-        this.statusMessage = message;
+    public String getOutput() {
+        return output;
     }
 
-    public void setResults(String results) {
-        this.results = results;
+    public void setOutput(String output) {
+        this.output = output;
     }
 
-    void set(int code, String message, String results) {
+    void set(int code, String message, String results, String output) {
         this.statusCode = code;
         this.statusMessage = message;
         this.results = results;
+        this.output = output;
     }
 
     public int getStatusCode() {
         return this.statusCode;
     }
 
+    public void setStatusCode(int code) {
+        this.statusCode = code;
+    }
+
     public String getStatusMessage() {
         return this.statusMessage;
     }
 
+    public void setStatusMessage(String message) {
+        this.statusMessage = message;
+    }
+
     public String getResults() {
         return this.results;
     }
+
+    public void setResults(String results) {
+        this.results = results;
+    }
+
+    public String getServerIp() {
+        return this.serverIp;
+    }
+
+    public void setServerIp(String serverIp) {
+        this.serverIp = serverIp;
+    }
+
+    public String getConfigData() {
+        return this.configData;
+    }
+
+    public void setConfigData(String configData) {
+        this.configData = configData;
+    }
+
 }
index a529e4a..55a1e70 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -65,7 +63,7 @@ public enum AnsibleResultCodes {
 
     AnsibleResultCodes(int value) {
         this.value = value;
-    };
+    }
 
     public int getValue() {
         return value;
@@ -77,7 +75,7 @@ public enum AnsibleResultCodes {
 
     public String getValidCodes(int type) {
         StringBuilder sb = new StringBuilder("[ ");
-        codeSets.get(type).stream().forEach(s -> sb.append(s).append(","));
+        codeSets.get(type).forEach(s -> sb.append(s).append(","));
         return sb.append("]").toString();
     }
 
@@ -87,7 +85,7 @@ public enum AnsibleResultCodes {
 
     public String getValidMessages() {
         StringBuilder sb = new StringBuilder("[ ");
-        messageSet.stream().forEach(s -> sb.append(s).append(","));
+        messageSet.forEach(s -> sb.append(s).append(","));
         return sb.append("]").toString();
     }
 }
index 993c700..a10a0ae 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * ============LICENSE_END=========================================================
  */
 
-
-
-/*
- * Class to emulate responses from the Ansible Server that is compliant with the APP-C Ansible Server
- * Interface. Used for jUnit tests to verify code is working. In tests it can be used
- * as a replacement for methods from ConnectionBuilder class
- */
-
 package org.onap.ccsdk.sli.adaptors.ansible.model;
 
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.commons.lang.StringUtils;
 import org.json.JSONException;
 import org.json.JSONObject;
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
+
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.PLAYBOOK_NAME;
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.STATUS_CODE;
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.STATUS_MESSAGE;
 
 public class AnsibleServerEmulator {
 
     private final EELFLogger logger = EELFManager.getInstance().getLogger(AnsibleServerEmulator.class);
 
-    private static final String PLAYBOOK_NAME = "PlaybookName";
-    private static final String STATUS_CODE = "StatusCode";
-    private static final String STATUS_MESSAGE = "StatusMessage";
-
-    private String playbookName = "test_playbook.yaml";
-
     /**
      * Method that emulates the response from an Ansible Server
      * when presented with a request to execute a playbook
      * Returns an ansible object result. The response code is always the http code 200 (i.e connection successful)
      * payload is json string as would be sent back by Ansible Server
      **/
-    public AnsibleResult Post(String agentUrl, String payload) {
+    public AnsibleResult post(String payload) {
         AnsibleResult result = new AnsibleResult();
 
         try {
             // Request must be a JSON object
 
             JSONObject message = new JSONObject(payload);
+            String playbookName = "test_playbook.yaml";
             if (message.isNull("Id")) {
                 rejectRequest(result, "Must provide a valid Id");
             } else if (message.isNull(PLAYBOOK_NAME)) {
@@ -84,9 +73,8 @@ public class AnsibleServerEmulator {
      * Server when presented with a GET request
      * Returns an ansibl object result. The response code is always the http code 200 (i.e connection successful)
      * payload is json string as would be sent back by Ansible Server
-     *
      **/
-    public AnsibleResult Get(String agentUrl) {
+    public AnsibleResult get(String agentUrl) {
 
         Pattern pattern = Pattern.compile(".*?\\?Id=(.*?)&Type.*");
         Matcher matcher = pattern.matcher(agentUrl);
@@ -134,4 +122,5 @@ public class AnsibleServerEmulator {
         response.put(STATUS_MESSAGE, "PENDING");
         result.setStatusMessage(response.toString());
     }
+
 }
\ No newline at end of file
index d7be01e..76abc82 100755 (executable)
@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
   ============LICENSE_START=======================================================
-  openECOMP : SDN-C
+  ONAP : SLI
   ================================================================================
-  Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights
-                          reserved.
+  Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
   ================================================================================
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
+
+  ECOMP is a trademark and service mark of AT&T Intellectual Property.
   ============LICENSE_END=========================================================
   -->
 
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+<blueprint xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+           xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            odl:use-default-for-reference-types="true">
 
-    <bean id="propProvider" class="org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl" />
+    <bean id="propProvider" class="org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl"/>
 
     <bean id="ansibleAdapterInstance" class="org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterImpl">
         <argument ref="propProvider"/>
index 761758b..8def3da 100644 (file)
@@ -1,11 +1,9 @@
 ###
 # ============LICENSE_START=======================================================
-# ONAP : APPC
+# ONAP : SLI
 # ================================================================================
-# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
 # ================================================================================
-# Copyright (C) 2017 Amdocs
-# =============================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 # ============LICENSE_END=========================================================
-###
 
+###
 #
-# Default properties for the APP-C TestService Adapter
+# Default properties for the APP-C Provider Adapter
 #
 # -------------------------------------------------------------------------------------------------
 #
 # Define the name and path of any user-provided configuration (bootstrap) file that can be loaded
 # to supply configuration options
 org.onap.appc.bootstrap.file=appc.properties
-org.onap.appc.bootstrap.path=${user.home},/opt/opendaylight/current/properties
-
+org.onap.appc.bootstrap.path=${user.home},/opt/opendaylight/current/properties,.
 appc.application.name=APPC
-
 #
 # Define the message resource bundle name to be loaded
-org.onap.appc.resources=org.onap/appc/i18n/MessageResources
+org.onap.appc.resources=org/onap/appc/i18n/MessageResources
 #
 # The name of the adapter.
 org.onap.appc.provider.adaptor.name=org.onap.appc.appc_ansible_adapter
-
-
 # Default truststore path and password
 org.onap.appc.adapter.ansible.trustStore=/opt/opendaylight/tls-client/mykeystore.js
 org.onap.appc.adapter.ansible.trustStore.trustPasswd=changeit
index d7be01e..76abc82 100755 (executable)
@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
   ============LICENSE_START=======================================================
-  openECOMP : SDN-C
+  ONAP : SLI
   ================================================================================
-  Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights
-                          reserved.
+  Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
   ================================================================================
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
+
+  ECOMP is a trademark and service mark of AT&T Intellectual Property.
   ============LICENSE_END=========================================================
   -->
 
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-           xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+<blueprint xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+           xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            odl:use-default-for-reference-types="true">
 
-    <bean id="propProvider" class="org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl" />
+    <bean id="propProvider" class="org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl"/>
 
     <bean id="ansibleAdapterInstance" class="org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterImpl">
         <argument ref="propProvider"/>
index 4636d24..be4bfd8 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
 
 package org.onap.ccsdk.adapter.ansible.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
 import java.util.HashMap;
 import java.util.Map;
-
+import java.util.Properties;
+import org.json.JSONException;
+import org.json.JSONObject;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
 import org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterImpl;
+import org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl;
+import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleMessageParser;
+import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResult;
 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+import org.powermock.reflect.Whitebox;
 
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.*;
+@RunWith(MockitoJUnitRunner.class)
 public class TestAnsibleAdapterImpl {
 
-    private final String PENDING = "100";
-    private final String SUCCESS = "400";
-    private String message = "{\"Results\":{\"192.168.1.10\":{\"Id\":\"101\",\"StatusCode\":200,\"StatusMessage\":\"SUCCESS\"}},\"StatusCode\":200,\"StatusMessage\":\"FINISHED\"}";
+    private static final String PENDING = "100";
+    private static final String AGENT_URL = "https://192.168.1.1";
 
-    private AnsibleAdapterImpl adapter;
-    private String TestId;
+    private static String KEYSTORE_PSWD;
+    private static Properties properties;
     private boolean testMode = true;
+
+    private AnsibleAdapterImpl adapter;
+    private AnsibleResult result;
+    private AnsibleAdapterImpl spyAdapter;
     private Map<String, String> params;
     private SvcLogicContext svcContext;
+    private JSONObject jsonPayload;
 
+    @Mock
+    private AnsibleMessageParser messageProcessor;
+
+    @BeforeClass
+    public static void once() {
+        properties = new AnsibleAdapterPropertiesProviderImpl().getProperties();
+        KEYSTORE_PSWD = properties.getProperty("org.onap.appc.adapter.ansible.trustStore.trustPasswd");
+    }
 
+    /**
+     * Use reflection to locate fields and methods so that they can be manipulated
+     * during the test to change the internal state accordingly.
+     */
     @Before
-    public void setup() throws IllegalArgumentException {
+    public void setup() {
         testMode = true;
         svcContext = new SvcLogicContext();
         adapter = new AnsibleAdapterImpl(testMode);
-
         params = new HashMap<>();
-        params.put("AgentUrl", "https://192.168.1.1");
-        params.put("User", "test");
-        params.put("Password", "test");
+        params.put("AgentUrl", AGENT_URL);
+        jsonPayload = new JSONObject();
+        jsonPayload.put("Id", "100");
+        jsonPayload.put("User", "test");
+        jsonPayload.put("Password", "test");
+        jsonPayload.put("PlaybookName", "test_playbook.yaml");
+        jsonPayload.put("Timeout", "60000");
+        jsonPayload.put("AgentUrl", AGENT_URL);
+        result = new AnsibleResult();
+        result.setStatusMessage("Success");
+        result.setResults("Success");
+        result.setOutput("{}");
+        Whitebox.setInternalState(adapter, "messageProcessor", messageProcessor);
+        spyAdapter = Mockito.spy(adapter);
     }
 
     @After
@@ -72,76 +109,131 @@ public class TestAnsibleAdapterImpl {
     }
 
     @Test
-    public void reqExec_shouldSetPending() throws IllegalStateException, IllegalArgumentException {
+    public void reqExec_shouldSetPending() throws SvcLogicException {
+        result.setStatusCode(Integer.parseInt(PENDING));
+        when(messageProcessor.reqMessage(params)).thenReturn(jsonPayload);
+        when(messageProcessor.parsePostResponse(anyString())).thenReturn(result);
+        spyAdapter.reqExec(params, svcContext);
+        assertEquals(PENDING, svcContext.getAttribute(RESULT_CODE_ATTRIBUTE_NAME));
+    }
 
-        params.put("PlaybookName", "test_playbook.yaml");
+    @Test(expected = SvcLogicException.class)
+    public void reqExecResult_shouldSetSuccess() throws SvcLogicException {
+        params.put("Id", "100");
+        result.setStatusMessage(SUCCESS);
+        when(messageProcessor.reqUriResult(params)).thenReturn(AGENT_URL);
+        when(messageProcessor.parseGetResponse(anyString())).thenReturn(result);
+        spyAdapter.reqExecResult(params, svcContext);
+        assertEquals(SUCCESS, svcContext.getAttribute(SUCCESS));
+    }
+    @Test(expected = SvcLogicException.class)
+    public void reqExecResult_Failure() throws SvcLogicException {
+        params.put("Id", "100");
+        result.setStatusCode(100);
+        result.setStatusMessage("Failed");
+        JSONObject cData = new JSONObject();
+        cData.put("GatewayInfo", "Radius");
+        result.setConfigData(cData.toString());
+        result.setOutput(cData.toString());
+        when(messageProcessor.reqUriResult(params)).thenReturn(AGENT_URL);
+        when(messageProcessor.parseGetResponse(anyString())).thenReturn(result);
+        adapter.reqExecResult(params, svcContext);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void reqExecResult_SvcLogicException() throws SvcLogicException {
+        when(messageProcessor.reqUriResult(params)).thenThrow(new SvcLogicException());
+        adapter.reqExecResult(params, svcContext);
+    }
 
-        try {
-            adapter.reqExec(params, svcContext);
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.result.code");
-            TestId = svcContext.getAttribute("org.onap.appc.adapter.ansible.result.Id");
-            System.out.println("Comparing " + PENDING + " and " + status);
-            assertEquals(PENDING, status);
-        } catch (SvcLogicException e) {
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.result.code");
-            fail(e.getMessage() + " Code = " + status);
-        } catch (Exception e) {
-            fail(e.getMessage() + " Unknown exception encountered ");
-        }
+    @Test(expected = SvcLogicException.class)
+    public void reqExecResult_numberFormatException()
+            throws IllegalStateException, IllegalArgumentException, SvcLogicException {
+        when(messageProcessor.reqUriResult(params)).thenThrow(new NumberFormatException());
+        adapter.reqExecResult(params, svcContext);
     }
 
     @Test
-    public void reqExecResult_shouldSetSuccess() throws IllegalStateException, IllegalArgumentException {
+    public void reqExecLog_shouldSetMessage() throws SvcLogicException {
+        params.put("Id", "101");
+        when(messageProcessor.reqUriLog(params)).thenReturn(AGENT_URL);
+        adapter.reqExecLog(params, svcContext);
+        String message = getResponseMessage();
+        assertEquals(message, svcContext.getAttribute(LOG_ATTRIBUTE_NAME));
+    }
 
-        params.put("Id", "100");
+    private String getResponseMessage() {
+        JSONObject response = new JSONObject();
+        response.put(STATUS_CODE, 200);
+        response.put(STATUS_MESSAGE, "FINISHED");
+        JSONObject results = new JSONObject();
 
-        for (String ukey : params.keySet()) {
-            System.out.println(String.format("Ansible Parameter %s = %s", ukey, params.get(ukey)));
-        }
+        JSONObject vmResults = new JSONObject();
+        vmResults.put(STATUS_CODE, 200);
+        vmResults.put(STATUS_MESSAGE, "SUCCESS");
+        vmResults.put("Id", "");
+        results.put("192.168.1.10", vmResults);
 
-        try {
-            adapter.reqExecResult(params, svcContext);
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.result.code");
-            assertEquals(SUCCESS, status);
-        } catch (SvcLogicException e) {
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.result.code");
-            fail(e.getMessage() + " Code = " + status);
-        } catch (Exception e) {
-            fail(e.getMessage() + " Unknown exception encountered ");
-        }
+        response.put("Results", results);
+        return response.toString();
     }
 
-    @Test
-    public void reqExecLog_shouldSetMessage() throws IllegalStateException, IllegalArgumentException {
+    @Test(expected = SvcLogicException.class)
+    public void reqExecException()
+            throws IllegalStateException, IllegalArgumentException, SvcLogicException {
+        when(messageProcessor.reqUriLog(params)).thenThrow(new SvcLogicException("Appc Exception"));
+        adapter.reqExecLog(params, svcContext);
+    }
 
-        params.put("Id", "101");
+    @Test(expected = SvcLogicException.class)
+    public void reqExec_SvcLogicException()
+            throws IllegalStateException, IllegalArgumentException, SvcLogicException {
+        when(messageProcessor.reqMessage(params)).thenThrow(new SvcLogicException());
+        adapter.reqExec(params, svcContext);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void reqExec_JsonException()
+            throws IllegalStateException, IllegalArgumentException, SvcLogicException {
+        when(messageProcessor.reqMessage(params)).thenThrow(new JSONException("Json Exception"));
+        adapter.reqExec(params, svcContext);
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void reqExec_NumberFormatException()
+            throws IllegalStateException, IllegalArgumentException, SvcLogicException {
+        when(messageProcessor.reqMessage(params)).thenThrow(new NumberFormatException("Numbre Format Exception"));
+        adapter.reqExec(params, svcContext);
+    }
 
-        try {
-            adapter.reqExecLog(params, svcContext);
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.log");
-            assertEquals(message, status);
-        } catch (SvcLogicException e) {
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.log");
-            fail(e.getMessage() + " Code = " + status);
-        } catch (Exception e) {
-            fail(e.getMessage() + " Unknown exception encountered ");
-        }
+    @Test
+    public void testInitializeWithDefault() {
+        properties.setProperty("org.onap.appc.adapter.ansible.clientType", "");
+        adapter = new AnsibleAdapterImpl();
+        assertNotNull(adapter);
     }
 
     @Test
-    public void reqExecOutput_shouldSetMessage() throws IllegalStateException, IllegalArgumentException {
+    public void testInitializeWithTrustAll() {
+        properties.setProperty("org.onap.appc.adapter.ansible.clientType", "TRUST_ALL");
+        adapter = new AnsibleAdapterImpl();
+        assertNotNull(adapter);
+    }
 
-        params.put("Id", "101");
+    @Test
+    public void testInitializeWithTrustCert() {
+        properties.setProperty("org.onap.appc.adapter.ansible.clientType", "TRUST_CERT");
+        properties.setProperty("org.onap.appc.adapter.ansible.trustStore.trustPasswd", KEYSTORE_PSWD);
+        adapter = new AnsibleAdapterImpl();
+        assertNotNull(adapter);
+    }
+
+    @Test
+    public void testInitializeWithException() {
+        properties.setProperty("org.onap.appc.adapter.ansible.clientType", "TRUST_CERT");
+        properties.setProperty("org.onap.appc.adapter.ansible.trustStore.trustPasswd", "appc");
+        adapter = new AnsibleAdapterImpl();
+        assertNotNull(adapter);
+    }
 
-        try {
-            adapter.reqExecOutput(params, svcContext);
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.output");
-            assertEquals(message, status);
-        } catch (SvcLogicException e) {
-            String status = svcContext.getAttribute("org.onap.appc.adapter.ansible.output");
-            fail(e.getMessage() + " Code = " + status);
-        } catch (Exception e) {
-            fail(e.getMessage() + " Unknown exception encountered ");
-        }
-    }
-}
+}
\ No newline at end of file
index b3c01e9..5ce1712 100644 (file)
@@ -1,8 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * onap
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2018 Samsung
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.ccsdk.adapter.ansible.impl;
 
-import org.junit.Before;
+import java.io.File;
+import java.util.Properties;
 import org.junit.Test;
 import org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl;
 
-import java.util.Properties;
-
 import static org.junit.Assert.assertEquals;
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.*;
 
 public class TestAnsibleAdapterPropertiesProviderImpl {
-    AnsibleAdapterPropertiesProviderImpl adaptor;
-    @Before
-    public void setup() throws IllegalArgumentException {
-        adaptor = new AnsibleAdapterPropertiesProviderImpl();
-    }
-
 
     @Test
     public void testGetProperties() throws IllegalStateException, IllegalArgumentException {
-        Properties prop = adaptor.getProperties();
+        Properties prop = new AnsibleAdapterPropertiesProviderImpl().getProperties();
+
+        assertEquals("TRUST_ALL", prop.getProperty(CLIENT_TYPE_PROPERTY_NAME));
+        assertEquals("org.onap.appc.appc_ansible_adapter", prop.getProperty("org.onap.appc.provider.adaptor.name"));
+        assertEquals("changeit", prop.getProperty(TRUSTSTORE_PASS_PROPERTY_NAME));
+        assertEquals("${user.home},/opt/opendaylight/current/properties,.", prop.getProperty("org.onap.appc.bootstrap.path"));
+        assertEquals("APPC", prop.getProperty("appc.application.name"));
+        assertEquals("appc.properties", prop.getProperty("org.onap.appc.bootstrap.file"));
+        assertEquals("org/onap/appc/i18n/MessageResources", prop.getProperty("org.onap.appc.resources"));
+        assertEquals("/opt/opendaylight/tls-client/mykeystore.js", prop.getProperty(TRUSTSTORE_PROPERTY_NAME));
+    }
 
-        System.out.println("All Property params : " + prop);
-        assertEquals("TRUST_ALL", prop.getProperty("org.onap.appc.adapter.ansible.clientType"));
+    @Test
+    public void testGetTestProperties() throws IllegalStateException, IllegalArgumentException {
+        final String configFilePath = "src/test/resources/properties/ansible-adapter-test.properties".replace("/", File.separator);
+        Properties prop = new AnsibleAdapterPropertiesProviderImpl(configFilePath).getProperties();
+
+        assertEquals("appc", prop.getProperty(CLIENT_TYPE_PROPERTY_NAME));
         assertEquals("org.onap.appc.appc_ansible_adapter", prop.getProperty("org.onap.appc.provider.adaptor.name"));
-        assertEquals("changeit", prop.getProperty("org.onap.appc.adapter.ansible.trustStore.trustPasswd"));
-        assertEquals("${user.home},/opt/opendaylight/current/properties", prop.getProperty("org.onap.appc.bootstrap.path"));
+        assertEquals("Aa123456", prop.getProperty(TRUSTSTORE_PASS_PROPERTY_NAME));
+        assertEquals("${user.home},/opt/opendaylight/current/properties,.", prop.getProperty("org.onap.appc.bootstrap.path"));
         assertEquals("APPC", prop.getProperty("appc.application.name"));
         assertEquals("appc.properties", prop.getProperty("org.onap.appc.bootstrap.file"));
-        assertEquals("org.onap/appc/i18n/MessageResources", prop.getProperty("org.onap.appc.resources"));
-        assertEquals("/opt/opendaylight/tls-client/mykeystore.js", prop.getProperty("org.onap.appc.adapter.ansible.trustStore"));
+        assertEquals("org/onap/appc/i18n/MessageResources", prop.getProperty("org.onap.appc.resources"));
+        assertEquals("src/test/resources/org/onap/appc/asdc-client.jks", prop.getProperty(TRUSTSTORE_PROPERTY_NAME));
     }
+
 }
index c94655f..25f8986 100644 (file)
@@ -1,8 +1,8 @@
 /*-
  * ============LICENSE_START=======================================================
- * onap
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2018 Samsung
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.ccsdk.adapter.ansible.impl;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.onap.ccsdk.sli.adaptors.ansible.impl.ConnectionBuilder;
-import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResult;
-import org.onap.ccsdk.sli.core.sli.SvcLogicException;
-
-import javax.net.ssl.SSLException;
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.security.KeyManagementException;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
+import java.util.Properties;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImpl;
+import org.onap.ccsdk.sli.adaptors.ansible.impl.ConnectionBuilder;
+import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResult;
+import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResultCodes;
+import org.powermock.reflect.Whitebox;
 
 import static org.junit.Assert.assertEquals;
-
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterConstants.*;
+
+@RunWith(MockitoJUnitRunner.class)
 public class TestConnectionBuilder {
-    ConnectionBuilder builder;
+
+    private static String KEYSTORE_FILE;
+    private static String KEYSTORE_PSWD;
+    private static String KEYSTORE_CERTIFICATE;
+    private static String USER;
+    private static String PSWD;
+    private static String URL;
+
+    private final int SUCCESS_STATUS = 200;
+    private ConnectionBuilder connectionBuilder;
+
+    @Mock
+    private CloseableHttpClient httpClient;
+
+    @Mock
+    private HttpClientContext httpClientContext;
+
+    @Mock
+    private CloseableHttpResponse response;
+
+    @Mock
+    private HttpEntity entity;
+
+    @Mock
+    private StatusLine statusLine;
+
+    /**
+     * Load the configuration properties
+     */
+    @BeforeClass
+    public static void once() {
+        final String configFilePath = "src/test/resources/properties/ansible-adapter-test.properties".replace("/", File.separator);
+        Properties properties = new AnsibleAdapterPropertiesProviderImpl(configFilePath).getProperties();
+
+        KEYSTORE_FILE = properties.getProperty(TRUSTSTORE_PROPERTY_NAME);
+        KEYSTORE_PSWD = properties.getProperty(TRUSTSTORE_PASS_PROPERTY_NAME);
+        KEYSTORE_CERTIFICATE = properties.getProperty("org.onap.appc.adapter.ansible.cert");
+        USER = properties.getProperty("org.onap.appc.adapter.ansible.username");
+        PSWD = properties.getProperty("org.onap.appc.adapter.ansible.password");
+        URL = properties.getProperty("org.onap.appc.adapter.ansible.identity");
+    }
+
     @Before
-    public void setup()
-            throws SSLException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
-        builder = new ConnectionBuilder(1);
+    public void setup() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
+        connectionBuilder = new ConnectionBuilder(1, 2000);
+        Whitebox.setInternalState(connectionBuilder, "httpClient", httpClient);
+        Whitebox.setInternalState(connectionBuilder, "httpContext", httpClientContext);
+        HttpResponse httpResponse = response;
+        when(httpResponse.getEntity()).thenReturn(entity);
+        when(httpResponse.getStatusLine()).thenReturn(statusLine);
+        when(statusLine.getStatusCode()).thenReturn(SUCCESS_STATUS);
     }
 
+    @After
+    public void tearDown() {
+        connectionBuilder = null;
+    }
 
     @Test
-    public void testSetHttpContext() throws IllegalStateException, IllegalArgumentException {
-        String user = "testUser";
-        String pass = "testPassword";
-
-        builder.setHttpContext(user, pass);
+    public void testConnectionBuilder() throws KeyManagementException, KeyStoreException, CertificateException,
+            NoSuchAlgorithmException, IOException {
+        char[] trustStorePassword = KEYSTORE_PSWD.toCharArray();
+        ConnectionBuilder connectionBuilder = new ConnectionBuilder(KEYSTORE_FILE, trustStorePassword, 600000, "");
+        assertNotNull(connectionBuilder);
     }
 
     @Test
-    public void testPost() throws IllegalStateException, IllegalArgumentException {
-        String user = "testUser";
-        String pass = "testPassword";
-        String agentUrl = "test/server.com";
-        String payload = "testPayload";
+    public void testConnectionBuilderWithFilePath() throws KeyManagementException, KeyStoreException,
+            CertificateException, NoSuchAlgorithmException, IOException {
+        new ConnectionBuilder(KEYSTORE_CERTIFICATE, 600000);
+    }
 
-        builder.setHttpContext(user, pass);
-        AnsibleResult result = builder.post(agentUrl, payload);
+    @Test
+    public void testSetHttpContext() {
+        ConnectionBuilder spyConnectionBuilder = Mockito.spy(connectionBuilder);
+        spyConnectionBuilder.setHttpContext(USER, PSWD);
+        verify(spyConnectionBuilder, times(1)).setHttpContext(USER, PSWD);
+    }
 
-        assertEquals(611, result.getStatusCode());
-        assertEquals(null, result.getStatusMessage());
+    @Test
+    public void testPost() throws IOException {
+        when(httpClient.execute(anyObject(), eq(httpClientContext))).thenReturn(response);
+        AnsibleResult result = connectionBuilder.post(URL, "appc");
+        assertNull(result.getStatusMessage());
+        assertEquals(SUCCESS_STATUS, result.getStatusCode());
         assertEquals("UNKNOWN", result.getResults());
     }
 
     @Test
-    public void testGet() throws IllegalStateException, IllegalArgumentException {
-        String user = "testUser";
-        String pass = "testPassword";
-        String agentUrl = "test/server.com";
-
-        builder.setHttpContext(user, pass);
-        AnsibleResult result = builder.get(agentUrl);
+    public void testPostWithException() throws IOException {
+        when(httpClient.execute(anyObject(), eq(httpClientContext))).thenThrow(new IOException());
+        AnsibleResult result = connectionBuilder.post(URL, "appc");
+        assertEquals(AnsibleResultCodes.IO_EXCEPTION.getValue(), result.getStatusCode());
+    }
 
-        assertEquals(611, result.getStatusCode());
-        assertEquals(null, result.getStatusMessage());
+    @Ignore
+    @Test
+    public void testGet() throws IOException {
+        when(httpClient.execute(anyObject(), eq(httpClientContext))).thenReturn(response);
+        AnsibleResult result = connectionBuilder.get(URL);
+        assertNull(result.getStatusMessage());
+        assertEquals(SUCCESS_STATUS, result.getStatusCode());
         assertEquals("UNKNOWN", result.getResults());
     }
 
     @Test
-    public void testGetMode()
-            throws SSLException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
-        String user = "testUser";
-        String pass = "testPassword";
-        String agentUrl = "test/server.com";
+    public void testGetWithException() throws IOException {
+        when(httpClient.execute(anyObject(), eq(httpClientContext))).thenThrow(new IOException());
+        AnsibleResult result = connectionBuilder.get(URL);
+        assertEquals(AnsibleResultCodes.IO_EXCEPTION.getValue(), result.getStatusCode());
+    }
 
-        builder = new ConnectionBuilder(2);
-        builder.setHttpContext(user, pass);
-        AnsibleResult result = builder.get(agentUrl);
+    @Test
+    public void testClose() {
+        connectionBuilder.close();
+    }
+
+    @Test
+    public void testGetMode() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+        connectionBuilder = new ConnectionBuilder(2, 2000);
+        connectionBuilder.setHttpContext(USER, PSWD);
+        AnsibleResult result = connectionBuilder.get("test.server.com");
 
         assertEquals(611, result.getStatusCode());
-        assertEquals(null, result.getStatusMessage());
+        assertNull(result.getStatusMessage());
         assertEquals("UNKNOWN", result.getResults());
     }
 
     @Test (expected = FileNotFoundException.class)
-    public void testGetModeNoCert()
-            throws KeyStoreException, CertificateException, IOException,
-            KeyManagementException, NoSuchAlgorithmException, SvcLogicException {
-        String user = "testUser";
-        String pass = "testPassword";
-        String agentUrl = "test/server.com";
+    public void testGetModeNoCert() throws KeyStoreException, CertificateException, IOException,
+            KeyManagementException, NoSuchAlgorithmException {
         String certFile = "testCert";
 
-        builder = new ConnectionBuilder(certFile);
-        builder.setHttpContext(user, pass);
-        AnsibleResult result = builder.get(agentUrl);
+        connectionBuilder = new ConnectionBuilder(certFile, 2000);
+        connectionBuilder.setHttpContext(USER, PSWD);
+        AnsibleResult result = connectionBuilder.get(URL);
 
         assertEquals(611, result.getStatusCode());
-        assertEquals(null, result.getStatusMessage());
+        assertNull(result.getStatusMessage());
         assertEquals("UNKNOWN", result.getResults());
     }
 
     @Test
-    public void testGetModeCert()
-            throws KeyStoreException, CertificateException, IOException,
-            KeyManagementException, NoSuchAlgorithmException, SvcLogicException {
-        String user = "testUser";
-        String pass = "testPassword";
-        String agentUrl = "test/server.com";
+    public void testGetModeCert() throws KeyStoreException, CertificateException, IOException,
+            KeyManagementException, NoSuchAlgorithmException {
         String certFile = "src/test/resources/cert";
 
-        builder = new ConnectionBuilder(certFile);
-        builder.setHttpContext(user, pass);
-        AnsibleResult result = builder.get(agentUrl);
+        connectionBuilder = new ConnectionBuilder(certFile, 2000);
+        connectionBuilder.setHttpContext(USER, PSWD);
+        AnsibleResult result = connectionBuilder.get("test.server.com");
 
         assertEquals(611, result.getStatusCode());
-        assertEquals(null, result.getStatusMessage());
+        assertNull(result.getStatusMessage());
         assertEquals("UNKNOWN", result.getResults());
     }
 
     @Test (expected = IOException.class)
-    public void testGetModeStore()
-            throws KeyStoreException, CertificateException, IOException,
-            KeyManagementException, NoSuchAlgorithmException, SvcLogicException {
-        String user = "testUser";
-        String pass = "testPassword";
-        String agentUrl = "test/server.com";
+    public void testGetModeStore() throws KeyStoreException, CertificateException, IOException,
+            KeyManagementException, NoSuchAlgorithmException {
         String store = "src/test/resources/cert";
 
-        builder = new ConnectionBuilder(store, new char['t'] );
-        builder.setHttpContext(user, pass);
-        AnsibleResult result = builder.get(agentUrl);
+        connectionBuilder = new ConnectionBuilder(store, new char['t'], 2000, "1.1.1.1" );
+        connectionBuilder.setHttpContext(USER, PSWD);
+        AnsibleResult result = connectionBuilder.get(URL);
 
         assertEquals(611, result.getStatusCode());
-        assertEquals(null, result.getStatusMessage());
+        assertNull(result.getStatusMessage());
         assertEquals("UNKNOWN", result.getResults());
     }
 
index 6fc90d0..3e1929b 100644 (file)
@@ -1,11 +1,9 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
-package org.onap.ccsdk.adapter.ansible.model;
 
-import static org.junit.Assert.assertNotNull;
+package org.onap.ccsdk.adapter.ansible.model;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.lang.reflect.*;
-import org.junit.After;
-import org.junit.Before;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.json.JSONObject;
 import org.junit.Test;
 import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleMessageParser;
 import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResult;
 import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleServerEmulator;
 
-public class TestAnsibleAdapter {
+import static org.junit.Assert.assertNotNull;
 
-    private Class[] parameterTypes;
-    private AnsibleMessageParser ansibleMessageParser;
-    private Method m;
-    private String name;
+public class TestAnsibleAdapter {
 
     @Test
-    public void callPrivateConstructorsMethodsForCodeCoverage() throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
+    public void callPrivateConstructorsMethodsForCodeCoverage()
+            throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException,
+            InvocationTargetException {
 
-          /* test constructors */
-          Class<?>[] classesOne = {AnsibleMessageParser.class};
-          for(Class<?> clazz : classesOne) {
-                Constructor<?> constructor = clazz.getDeclaredConstructor();
-                name = constructor.getName();
-                constructor.setAccessible(true);
-                assertNotNull(constructor.newInstance());
-          }
-          Class<?>[] classesTwo = {AnsibleServerEmulator.class};
-          for(Class<?> clazz : classesTwo) {
-                Constructor<?> constructor = clazz.getDeclaredConstructor();
-                name = constructor.getName();
-                constructor.setAccessible(true);
-                assertNotNull(constructor.newInstance());
-          }
-          Class<?>[] classesThree = {AnsibleResult.class};
-          for(Class<?> clazz : classesThree) {
-                Constructor<?> constructor = clazz.getDeclaredConstructor();
-                name = constructor.getName();
-                constructor.setAccessible(true);
-                assertNotNull(constructor.newInstance());
-          }
+        /* test constructors */
+        Class<?>[] classesOne = {AnsibleMessageParser.class};
+        for (Class<?> clazz : classesOne) {
+            Constructor<?> constructor = clazz.getDeclaredConstructor();
+            constructor.setAccessible(true);
+            assertNotNull(constructor.newInstance());
+        }
+        Class<?>[] classesTwo = {AnsibleServerEmulator.class};
+        for (Class<?> clazz : classesTwo) {
+            Constructor<?> constructor = clazz.getDeclaredConstructor();
+            constructor.setAccessible(true);
+            assertNotNull(constructor.newInstance());
+        }
+        Class<?>[] classesThree = {AnsibleResult.class};
+        for (Class<?> clazz : classesThree) {
+            Constructor<?> constructor = clazz.getDeclaredConstructor();
+            constructor.setAccessible(true);
+            assertNotNull(constructor.newInstance());
+        }
 
-          /* test methods */
-          ansibleMessageParser = new AnsibleMessageParser();
-          parameterTypes = new Class[1];
-          parameterTypes[0] = java.lang.String.class;
+        /* test methods */
+        AnsibleMessageParser ansibleMessageParser = new AnsibleMessageParser();
+        Class<?>[] parameterTypes = new Class[1];
+        parameterTypes[0] = java.lang.String.class;
 
-          m = ansibleMessageParser.getClass().getDeclaredMethod("getFilePayload", parameterTypes);
-          m.setAccessible(true);
-          assertNotNull(m.invoke(ansibleMessageParser,"{\"test\": test}"));
+        Method m = ansibleMessageParser.getClass().getDeclaredMethod("getFilePayload", parameterTypes);
+        m.setAccessible(true);
+        assertNotNull(m.invoke(ansibleMessageParser, "{\"test\": test}"));
 
+        // test logging-suppression for an invalid host value (Fortify Log Forging fix)
+        String input = "{"
+                       + "  \"Results\": {"
+                       + "    \"192.168.1.10\": {"
+                       + "      \"Id\": \"101\","
+                       + "      \"StatusCode\": 200,"
+                       + "      \"StatusMessage\": \"SUCCESS\""
+                       + "    },"
+                       + "    \"192%168%1%10\": {"
+                       + "      \"Id\": \"102\","
+                       + "      \"StatusCode\": 200,"
+                       + "      \"StatusMessage\": \"SUCCESS\""
+                       + "    },"
+                       + "    \"server-dev.att.com\": {"
+                       + "      \"Id\": \"103\","
+                       + "      \"StatusCode\": 200,"
+                       + "      \"StatusMessage\": \"SUCCESS\""
+                       + "    }"
+                       + "  },"
+                       + "  \"StatusCode\": 200,"
+                       + "  \"StatusMessage\": \"FINISHED\""
+                       + "}";
+        Method m2 = ansibleMessageParser.getClass().getDeclaredMethod("parseGetResponseNested", AnsibleResult.class, JSONObject.class);
+        m2.setAccessible(true);
+        m2.invoke(ansibleMessageParser, new AnsibleResult(), new JSONObject(input));
     }
+
 }
+
diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleMessageParser.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleMessageParser.java
new file mode 100644 (file)
index 0000000..bcf18e3
--- /dev/null
@@ -0,0 +1,249 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : SLI
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.ccsdk.adapter.ansible.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleMessageParser;
+import org.onap.ccsdk.sli.core.sli.SvcLogicException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TestAnsibleMessageParser {
+    private AnsibleMessageParser msgParser;
+
+    @Before
+    public void setup() {
+        msgParser = new AnsibleMessageParser();
+    }
+
+    @Test
+    public void testReqMessage() throws Exception {
+        // String result = "{"\AgentUrl : TestAgentUrl}";
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "TestAgentUrl");
+        params.put("PlaybookName", "TestPlaybookName");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+
+        assertEquals("TestAgentUrl", msgParser.reqMessage(params).get("AgentUrl"));
+    }
+
+    @Test
+    public void testReqUriResult() throws Exception {
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "TestAgentUrl");
+        params.put("Id", "TestId");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+
+        assertTrue(msgParser.reqUriResult(params).contains("TestId"));
+    }
+
+    @Test
+    public void testReqUriLog() throws Exception {
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "TestAgent-Url");
+        params.put("Id", "TestId");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+
+        assertTrue(msgParser.reqUriLog(params).contains("TestAgent-Url"));
+    }
+
+    @Test
+    public void TestParsePostResponse() throws Exception {
+        String input = "{\"StatusCode\":\"100\",\"StatusMessage\":\"TestMessage\"}";
+        assertEquals("TestMessage", msgParser.parsePostResponse(input).getStatusMessage());
+
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void TestParsePostResponseException() throws Exception {
+        String input = "{\"StatusCode\":\"600\",\"StatusMessage\":\"TestMessage\"}";
+        assertTrue(msgParser.parsePostResponse(input).getStatusMessage().contains("Error parsing response"));
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void TestParsePostResponseException2() throws Exception {
+        String input = "{\"StatusCode\":\"600\"}";
+        assertTrue(msgParser.parsePostResponse(input).getStatusMessage().contains("Error parsing response"));
+    }
+
+    @Test(expected = SvcLogicException.class)
+    public void TestParseGetResponseException() throws Exception {
+        String input = "{\"StatusCode\":\"100\",\"StatusMessage\":\"TestMessage\"}";
+        assertTrue(msgParser.parseGetResponse(input).getStatusMessage().contains("Invalid FinalResponse code"));
+    }
+
+    @Test
+    public void TestParseGetResponseExec() throws Exception {
+        String input = "{\"StatusCode\":\"200\",\"StatusMessage\":\"TestMessage\"}";
+        assertTrue(msgParser.parseGetResponse(input).getStatusMessage().contains("Results not found in GET for response"));
+    }
+
+    @Test
+    public void TestParseGetResponse() throws Exception {
+        String input = "{"
+                       + "  \"StatusCode\": \"200\","
+                       + "  \"StatusMessage\": \"TestMessage\","
+                       + "  \"Results\": {"
+                       + "    \"host\": {"
+                       + "      \"StatusCode\": \"200\","
+                       + "      \"StatusMessage\": \"SUCCESS\""
+                       + "    }"
+                       + "  },"
+                       + "  \"Output\": {"
+                       + "    \"results-output\": {"
+                       + "      \"OutputResult\": \"TestOutPutResult\""
+                       + "    }"
+                       + "  }"
+                       + "}";
+        assertTrue(msgParser.parseGetResponse(input).getOutput().contains("TestOutPutResult"));
+    }
+
+    @Test
+    public void TestParseGetResponseEx() throws Exception {
+        String input = "{\"StatusCode\":\"200\",\"StatusMessage\":\"TestMessage\",\"Results\":{\"host\":\"TestHost\"}}";
+        assertTrue(msgParser.parseGetResponse(input).getStatusMessage().contains("Error processing response message"));
+    }
+
+    @Test
+    public void TestParseGetResponseJsonEx() throws Exception {
+        String input = "{\"StatusCode\":\"200\",\"StatusMessage\":\"TestMessage\",\"Results\":\"host\":\"TestHost\"}";
+        assertTrue(msgParser.parseGetResponse(input).getStatusMessage().contains("Error parsing response"));
+    }
+
+    @Test
+    public void TestParseGetResponseResultEx() throws Exception {
+        String input = "{"
+                       + "  \"StatusCode\": \"200\","
+                       + "  \"StatusMessage\": \"TestMessage\","
+                       + "  \"Results\": {"
+                       + "    \"host\": {"
+                       + "      \"StatusCode\": \"100\","
+                       + "      \"StatusMessage\": \"Failure\""
+                       + "    }"
+                       + "  },"
+                       + "  \"Output\": {"
+                       + "    \"results-output\": {"
+                       + "      \"OutputResult\": \"TestOutPutResult\""
+                       + "    }"
+                       + "  }"
+                       + "}";
+        assertTrue(msgParser.parseGetResponse(input).getOutput().contains("TestOutPutResult"));
+    }
+
+    @Test
+    public void testParseOptionalParam() throws Exception {
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "TestAgentUrl");
+        params.put("PlaybookName", "TestPlaybookName");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+        params.put("Timeout", "3");
+        params.put("Version", "1");
+        params.put("InventoryNames", "VNFC");
+
+        JSONObject jObject = msgParser.reqMessage(params);
+        assertEquals("1", jObject.get("Version"));
+        assertEquals("VNFC", jObject.get("InventoryNames"));
+    }
+
+    @Test
+    public void testParseOptionalParamForEnvParameters() throws Exception {
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "TestAgentUrl");
+        params.put("PlaybookName", "TestPlaybookName");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+        params.put("EnvParameters", "{name:value}");
+
+        JSONObject result = msgParser.reqMessage(params);
+        assertEquals("TestAgentUrl", result.get("AgentUrl"));
+        assertEquals("TestPlaybookName", result.get("PlaybookName"));
+        assertEquals("TestUser", result.get("User"));
+        assertEquals("TestPass", result.get("Password"));
+    }
+
+    @Test
+    public void TestParseGetConfigResponseResult() throws Exception {
+        String input = "{"
+                       + "  \"StatusCode\": \"200\","
+                       + "  \"StatusMessage\": \"TestMessage\","
+                       + "  \"Results\": {"
+                       + "    \"host\": {"
+                       + "      \"StatusCode\": \"200\","
+                       + "      \"StatusMessage\": \"SUCCESS\","
+                       + "      \"Output\": {"
+                       + "        \"info\": {"
+                       + "          \"configData\": {"
+                       + "            \"abc\": \"TestOutPutResult\","
+                       + "            \"rtr\": \"vfc\""
+                       + "          }"
+                       + "        }"
+                       + "      }"
+                       + "    }"
+                       + "  }"
+                       + "}";
+        assertTrue(msgParser.parseGetResponse(input).getConfigData().contains("abc"));
+    }
+
+    @Test
+    public void testParseOptionalParamTest2() throws Exception {
+
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "TestAgentUrl");
+        params.put("PlaybookName", "TestPlaybookName");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+        //params.put("Timeout", "3");
+        params.put("Version", "1");
+        params.put("InventoryNames", "VNFC");
+        params.put("Timeout", "4");
+        params.put("EnvParameters", "{ \"userID\": \"$0002\", \"vnf-type\" : \"\", \"vnf\" : \"abc\" }");
+        params.put("NodeList", "${Nodelist}");
+
+        JSONObject jObject = msgParser.reqMessage(params);
+        assertEquals("1", jObject.get("Version"));
+        assertEquals("4", jObject.get("Timeout"));
+    }
+
+    @Test
+    public void testReqUriResultWithIPs() throws Exception {
+        Map<String, String> params = new HashMap<>();
+        params.put("AgentUrl", "http://xx:yy:zz");
+        params.put("Id", "TestId");
+        params.put("User", "TestUser");
+        params.put("Password", "TestPass");
+        String serverIp = "10.0.2.3";
+        String actual = msgParser.reqUriResultWithIP(params, serverIp);
+        String expected = "http://10.0.2.3:yy:zz?Id=TestId&Type=GetResult";
+        assertEquals(expected, actual);
+    }
+
+}
diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleResult.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleResult.java
new file mode 100644 (file)
index 0000000..301cce1
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : SLI
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.ccsdk.adapter.ansible.model;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.ccsdk.sli.adaptors.ansible.model.AnsibleResult;
+
+import static org.junit.Assert.assertEquals;
+
+public class TestAnsibleResult {
+    private AnsibleResult ansibleResult;
+
+    @Before
+    public void setUp() {
+        ansibleResult = new AnsibleResult(10, "message", "result", "outputData");
+    }
+
+    @Test
+    public void testServerIp() {
+        ansibleResult.setServerIp("10.0.9.87");
+        assertEquals("10.0.9.87", ansibleResult.getServerIp());
+    }
+
+}
index 3555d7d..b6476d9 100644 (file)
@@ -1,23 +1,21 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- * 
+ *
  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
@@ -31,7 +29,6 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
 import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin;
 
@@ -49,92 +46,79 @@ public class ExecutorHarness {
     /**
      * The collection of all exec methods found on the class
      */
-    private Map<String, Method> methods;
-
-    /**
-     * The field of the class being tested that contains the reference to the logger to be used. This is modified to
-     * point to our interception logger for the test.
-     */
-    private Field contextLogger;
-
-    /**
-     * The interception logger that buffers all messages logged and allows us to look at them as part of the test case.
-     */
-    private InterceptLogger logger;
+    private final Map<String, Method> methods;
 
     /**
      * Create the harness and initialize it
-     * 
-     * @throws SecurityException
-     *             If a security manager, s, is present and any of the following conditions is met:
-     *             <ul>
-     *             <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared field</li>
-     *             <li>the caller's class loader is not the same as or an ancestor of the class loader for the current
-     *             class and invocation of s.checkPackageAccess() denies access to the package of this class</li>
-     *             </ul>
-     * @throws NoSuchFieldException
-     *             if a field with the specified name is not found.
-     * @throws IllegalAccessException
-     *             if this Field object is enforcing Java language access control and the underlying field is either
-     *             inaccessible or final.
-     * @throws IllegalArgumentException
-     *             if the specified object is not an instance of the class or interface declaring the underlying field
-     *             (or a subclass or implementor thereof), or if an unwrapping conversion fails.
+     *
+     * @throws SecurityException        If a security manager, s, is present and any of the following conditions is met:
+     *                                  <ul>
+     *                                  <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared field</li>
+     *                                  <li>the caller's class loader is not the same as or an ancestor of the class loader for the current
+     *                                  class and invocation of s.checkPackageAccess() denies access to the package of this class</li>
+     *                                  </ul>
+     * @throws NoSuchFieldException     if a field with the specified name is not found.
+     * @throws IllegalAccessException   if this Field object is enforcing Java language access control and the underlying field is either
+     *                                  inaccessible or final.
+     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring the underlying field
+     *                                  (or a subclass or implementor thereof), or if an unwrapping conversion fails.
      */
     @SuppressWarnings("nls")
     public ExecutorHarness() throws NoSuchFieldException, SecurityException, IllegalArgumentException,
-                    IllegalAccessException {
+            IllegalAccessException {
         methods = new HashMap<>();
         new SvcLogicContext();
 
         Class<?> contextClass = SvcLogicContext.class;
-        contextLogger = contextClass.getDeclaredField("LOG");
+        /**
+         * The field of the class being tested that contains the reference to the logger to be used. This is modified to
+         * point to our interception logger for the test.
+         */
+        Field contextLogger = contextClass.getDeclaredField("LOG");
         contextLogger.setAccessible(true);
-        logger = new InterceptLogger();
+        /**
+         * The interception logger that buffers all messages logged and allows us to look at them as part of the test case.
+         */
+        InterceptLogger logger = new InterceptLogger();
         contextLogger.set(null, logger);
     }
 
     /**
      * Convenience constructor
-     * 
-     * @param executor
-     *            The executor to be tested by the harness
-     * @throws SecurityException
-     *             If a security manager, s, is present and any of the following conditions is met:
-     *             <ul>
-     *             <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared field</li>
-     *             <li>the caller's class loader is not the same as or an ancestor of the class loader for the current
-     *             class and invocation of s.checkPackageAccess() denies access to the package of this class</li>
-     *             </ul>
-     * @throws NoSuchFieldException
-     *             if a field with the specified name is not found.
-     * @throws IllegalAccessException
-     *             if this Field object is enforcing Java language access control and the underlying field is either
-     *             inaccessible or final.
-     * @throws IllegalArgumentException
-     *             if the specified object is not an instance of the class or interface declaring the underlying field
-     *             (or a subclass or implementor thereof), or if an unwrapping conversion fails.
+     *
+     * @param executor The executor to be tested by the harness
+     *
+     * @throws SecurityException        If a security manager, s, is present and any of the following conditions is met:
+     *                                  <ul>
+     *                                  <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared field</li>
+     *                                  <li>the caller's class loader is not the same as or an ancestor of the class loader for the current
+     *                                  class and invocation of s.checkPackageAccess() denies access to the package of this class</li>
+     *                                  </ul>
+     * @throws NoSuchFieldException     if a field with the specified name is not found.
+     * @throws IllegalAccessException   if this Field object is enforcing Java language access control and the underlying field is either
+     *                                  inaccessible or final.
+     * @throws IllegalArgumentException if the specified object is not an instance of the class or interface declaring the underlying field
+     *                                  (or a subclass or implementor thereof), or if an unwrapping conversion fails.
      */
     public ExecutorHarness(SvcLogicJavaPlugin executor) throws NoSuchFieldException, SecurityException,
-                    IllegalArgumentException, IllegalAccessException {
+            IllegalArgumentException, IllegalAccessException {
         this();
         setExecutor(executor);
     }
 
     /**
-     * @param executor
-     *            The java plugin class to be executed
+     * @return The java plugin class to be executed
      */
-    public void setExecutor(SvcLogicJavaPlugin executor) {
-        this.executor = executor;
-        scanExecutor();
+    public SvcLogicJavaPlugin getExecutor() {
+        return executor;
     }
 
     /**
-     * @return The java plugin class to be executed
+     * @param executor The java plugin class to be executed
      */
-    public SvcLogicJavaPlugin getExecutor() {
-        return executor;
+    public void setExecutor(SvcLogicJavaPlugin executor) {
+        this.executor = executor;
+        scanExecutor();
     }
 
     /**
@@ -148,11 +132,11 @@ public class ExecutorHarness {
 
     /**
      * Returns an indication if the named method is a valid executor method that could be called from a DG execute node
-     * 
-     * @param methodName
-     *            The method name to be validated
+     *
+     * @param methodName The method name to be validated
+     *
      * @return True if the method name meets the signature requirements, false if the method either does not exist or
-     *         does not meet the requirements.
+     * does not meet the requirements.
      */
     public boolean isExecMethod(String methodName) {
         return methods.containsKey(methodName);
@@ -178,4 +162,5 @@ public class ExecutorHarness {
             }
         }
     }
+
 }
index 92235cb..3ed3237 100644 (file)
@@ -1,23 +1,21 @@
 /*-
  * ============LICENSE_START=======================================================
- * ONAP : APPC
+ * ONAP : SLI
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
- * Copyright (C) 2017 Amdocs
- * =============================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- * 
+ *
  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  * ============LICENSE_END=========================================================
  */
 
 package org.onap.ccsdk.test;
 
+import ch.qos.logback.classic.Level;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
-
 import org.slf4j.Marker;
 
-import ch.qos.logback.classic.Level;
-
 /**
  * This class is used as an intercept logger that can be used in testing to intercept and record all messages that are
  * logged, thus allowing a junit test case to examine the log output and make assertions.
  */
 public class InterceptLogger implements org.slf4j.Logger {
 
-    /**
-     * This inner class represents an intercepted log event
-     */
-    public class LogRecord {
-        private Level level;
-        private String message;
-        private long timestamp;
-        private Throwable t;
-
-        public LogRecord(Level level, String message) {
-            setLevel(level);
-            setTimestamp(System.currentTimeMillis());
-            setMessage(message);
-        }
-
-        public LogRecord(Level level, String message, Throwable t) {
-            this(level, message);
-            setThrowable(t);
-        }
-
-        /**
-         * @return the value of level
-         */
-        public Level getLevel() {
-            return level;
-        }
-
-        /**
-         * @return the value of message
-         */
-        public String getMessage() {
-            return message;
-        }
-
-        /**
-         * @return the value of timestamp
-         */
-        public long getTimestamp() {
-            return timestamp;
-        }
-
-        /**
-         * @param level
-         *            the value for level
-         */
-        public void setLevel(Level level) {
-            this.level = level;
-        }
-
-        /**
-         * @param message
-         *            the value for message
-         */
-        public void setMessage(String message) {
-            this.message = message;
-        }
-
-        /**
-         * @param timestamp
-         *            the value for timestamp
-         */
-        public void setTimestamp(long timestamp) {
-            this.timestamp = timestamp;
-        }
-
-        /**
-         * @return the value of t
-         */
-        public Throwable getThrowable() {
-            return t;
-        }
-
-        /**
-         * @param t
-         *            the value for t
-         */
-        public void setThrowable(Throwable t) {
-            this.t = t;
-        }
-
-    }
-
     /**
      * The list of all intercepted log events
      */
-    private List<LogRecord> events;
+    private final List<LogRecord> events;
 
     /**
      * Create the intercept logger
      */
     public InterceptLogger() {
-        events = new ArrayList<LogRecord>(1000);
+        events = new ArrayList<>(1000);
     }
 
     /**
@@ -451,4 +365,83 @@ public class InterceptLogger implements org.slf4j.Logger {
     public void warn(String msg, Throwable t) {
         events.add(new LogRecord(Level.WARN, msg, t));
     }
+
+    /**
+     * This inner class represents an intercepted log event
+     */
+    public class LogRecord {
+        private Level level;
+        private String message;
+        private long timestamp;
+        private Throwable t;
+
+        public LogRecord(Level level, String message) {
+            setLevel(level);
+            setTimestamp(System.currentTimeMillis());
+            setMessage(message);
+        }
+
+        public LogRecord(Level level, String message, Throwable t) {
+            this(level, message);
+            setThrowable(t);
+        }
+
+        /**
+         * @return the value of level
+         */
+        public Level getLevel() {
+            return level;
+        }
+
+        /**
+         * @param level the value for level
+         */
+        public void setLevel(Level level) {
+            this.level = level;
+        }
+
+        /**
+         * @return the value of message
+         */
+        public String getMessage() {
+            return message;
+        }
+
+        /**
+         * @param message the value for message
+         */
+        public void setMessage(String message) {
+            this.message = message;
+        }
+
+        /**
+         * @return the value of timestamp
+         */
+        public long getTimestamp() {
+            return timestamp;
+        }
+
+        /**
+         * @param timestamp the value for timestamp
+         */
+        public void setTimestamp(long timestamp) {
+            this.timestamp = timestamp;
+        }
+
+        /**
+         * @return the value of t
+         */
+        public Throwable getThrowable() {
+            return t;
+        }
+
+        /**
+         * @param t the value for t
+         */
+        public void setThrowable(Throwable t) {
+            this.t = t;
+        }
+
+    }
+
 }
diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client-cert.crt b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client-cert.crt
new file mode 100644 (file)
index 0000000..941c1d8
--- /dev/null
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+  MIIBezCCASWgAwIBAgIQyWD8dLUoqpJFyDxrfRlrsTANBgkqhkiG9w0BAQQFADAW
+  MRQwEgYDVQQDEwtSb290IEFnZW5jeTAeFw0wMTEwMTkxMjU5MjZaFw0zOTEyMzEy
+  MzU5NTlaMBoxGDAWBgNVBAMTD1Jvb3RDZXJ0aWZpY2F0ZTBcMA0GCSqGSIb3DQEB
+  AQUAA0sAMEgCQQC+NFKszPjatUZKWmyWaFjir1wB93FX2u5SL+GMjgUsMs1JcTKQ
+  Kh0cnnQKknNkV4cTW4NPn31YCoB1+0KA3mknAgMBAAGjSzBJMEcGA1UdAQRAMD6A
+  EBLkCS0GHR1PAI1hIdwWZGOhGDAWMRQwEgYDVQQDEwtSb290IEFnZW5jeYIQBjds
+  AKoAZIoRz7jUqlw19DANBgkqhkiG9w0BAQQFAANBACJxAfP57yqaT9N+nRgAOugM
+  JG0aN3/peCIvL3p29epRL2xoWFvxpUUlsH2I39OZ6b8+twWCebhkv1I62segXAk=
+  -----END CERTIFICATE-----
\ No newline at end of file
diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client.jks b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client.jks
new file mode 100644 (file)
index 0000000..eb0a0d3
Binary files /dev/null and b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client.jks differ
@@ -1,45 +1,49 @@
 ###
 # ============LICENSE_START=======================================================
-# ONAP : APPC
+# ONAP : SLI
 # ================================================================================
-# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
 # ================================================================================
-# Copyright (C) 2017 Amdocs
-# =============================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 #      http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-# 
+#
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 # ============LICENSE_END=========================================================
-###
 
+###
 #
 # Default properties for the APP-C Provider Adapter
 #
 # -------------------------------------------------------------------------------------------------
 #
-# Define the name and path of any user-provided configuration (bootstrap) file that can be loaded 
-# to supply configuration options 
+# Define the name and path of any user-provided configuration (bootstrap) file that can be loaded
+# to supply configuration options
 org.onap.appc.bootstrap.file=appc.properties
-org.onap.appc.bootstrap.path=/opt/onap/appc/data/properties,${user.home},.
-
+org.onap.appc.bootstrap.path=${user.home},/opt/opendaylight/current/properties,.
 appc.application.name=APPC
-
-#
-# Define the message resource bundle name to be loaded 
+#Define ansible property
+org.onap.appc.adapter.ansible.clientType=appc
+org.onap.appc.adapter.ansible.trustStore=src/test/resources/org/onap/appc/asdc-client.jks
+org.onap.appc.adapter.ansible.trustStore.trustPasswd=Aa123456
+org.onap.appc.adapter.ansible.cert=src/test/resources/org/onap/appc/asdc-client-cert.crt
+org.onap.appc.adapter.ansible.identity=http://localhost:9081/v2.0
+org.onap.appc.adapter.ansible.username=appc
+org.onap.appc.adapter.ansible.password=appc
+#
+# Define the message resource bundle name to be loaded
 org.onap.appc.resources=org/onap/appc/i18n/MessageResources
 #
 # The name of the adapter.
-org.onap.appc.provider.adaptor.name=org.onap.appc.appc_provider_adapter
+org.onap.appc.provider.adaptor.name=org.onap.appc.appc_ansible_adapter
 #
 # Set up the logging environment
 #
@@ -48,58 +52,52 @@ org.onap.appc.logging.path=${user.home};etc;../etc
 org.onap.appc.logger=org.onap.appc
 org.onap.appc.security.logger=org.onap.appc.security
 #
-# The minimum and maximum provider/tenant context pool sizes.  Min=1 means that as soon 
-# as the provider/tenant is referenced a Context is opened and added to the pool.  Max=0 
-# means that the upper bound on the pool is unbounded. 
+# The minimum and maximum provider/tenant context pool sizes.  Min=1 means that as soon
+# as the provider/tenant is referenced a Context is opened and added to the pool.  Max=0
+# means that the upper bound on the pool is unbounded.
 org.onap.appc.provider.min.pool=1
 org.onap.appc.provider.max.pool=0
-
 #
-# The following properties are used to configure the retry logic for connection to the 
+# The following properties are used to configure the retry logic for connection to the
 # IaaS provider(s).  The retry delay property is the amount of time, in seconds, the
 # application waits between retry attempts.  The retry limit is the number of retries
 # that are allowed before the request is failed.
-org.onap.appc.provider.retry.delay = 30
-org.onap.appc.provider.retry.limit = 10
-
+org.onap.appc.provider.retry.delay=30
+org.onap.appc.provider.retry.limit=10
 #
 # The trusted hosts list for SSL access when a certificate is not provided.
 #
 provider.trusted.hosts=*
 #
 # The amount of time, in seconds, to wait for a server state change (start->stop, stop->start, etc).
-# If the server does not change state to a valid state within the alloted time, the operation 
+# If the server does not change state to a valid state within the alloted time, the operation
 # fails.
 org.onap.appc.server.state.change.timeout=300
 #
-# The amount of time to wait, in seconds, between subsequent polls to the OpenStack provider 
+# The amount of time to wait, in seconds, between subsequent polls to the OpenStack provider
 # to refresh the status of a resource we are waiting on.
 #
 org.onap.appc.openstack.poll.interval=20
 #
-# The connection information to connect to the provider we are using.  These properties 
-# are "structured" properties, in that the name is a compound name, where the nodes 
+# The connection information to connect to the provider we are using.  These properties
+# are "structured" properties, in that the name is a compound name, where the nodes
 # of the name can be ordered (1, 2, 3, ...).  All of the properties with the same ordinal
-# position are defining the same entity.  For example, provider1.type and provider1.name 
+# position are defining the same entity.  For example, provider1.type and provider1.name
 # are defining the same provider, whereas provider2.name and provider2.type are defining
-# the values for a different provider.  Any number of providers can be defined in this 
-# way. 
+# the values for a different provider.  Any number of providers can be defined in this
+# way.
 #
-
 # Don't change these 2 right now since they are hard coded in the DG
 #provider1.type=appc
 #provider1.name=appc
-
 #These you can change
 #provider1.identity=appc
 #provider1.tenant1.name=appc
 #provider1.tenant1.userid=appc
 #provider1.tenant1.password=appc
-
 # After a change to the provider make sure to recheck these values with an api call to provider1.identity/tokens
 test.expected-regions=1
 test.expected-endpoints=1
-
 #Your OpenStack IP
 #test.ip=192.168.1.2
 # Your OpenStack Platform's Keystone Port (default is 5000)
index 377df49..5fd02ba 100644 (file)
@@ -48,7 +48,6 @@
 
     <dependencyManagement>
         <dependencies>
-
             <dependency>
                 <groupId>org.onap.appc</groupId>
                 <artifactId>ansible-adapter-features</artifactId>
                 <type>xml</type>
                 <classifier>features</classifier>
             </dependency>
-
             <dependency>
                 <groupId>org.onap.appc</groupId>
                 <artifactId>ansible-adapter-provider</artifactId>
                 <version>${project.version}</version>
             </dependency>
-
         </dependencies>
-
     </dependencyManagement>
 
     <pluginRepositories>
             <name>JCenter Repository</name>
             <url>http://jcenter.bintray.com</url>
         </pluginRepository>
-
     </pluginRepositories>
 
     <build>
         <plugins>
-
             <!-- Black duck plugin Not required for regular builds
             <plugin> <groupId>com.blackducksoftware.integration</groupId> <artifactId>hub-maven-plugin</artifactId>
                   <version>1.4.0</version> <inherited>false</inherited> <configuration> <hubProjectName>${project.name}</hubProjectName>
                    </goals>
                </execution>
                </executions>
-
             </plugin>
             -->
-
         </plugins>
     </build>
 
index 4233ee5..ac9941a 100644 (file)
             <version>${junit.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
index 2e9f267..0dca284 100644 (file)
@@ -34,7 +34,7 @@ public class EnvProperties extends Properties {
            String propName = (String) propNames.nextElement();
            super.setProperty(propName, EnvProperties.resolveValue(getProperty(propName)));
        }
-       
+
     }
 
     public static String resolveValue(String value) {
@@ -45,7 +45,7 @@ public class EnvProperties extends Properties {
         Pattern p = Pattern.compile("\\$\\{(\\w+)((?:\\:\\-)([^\\}]*))?\\}");
         Matcher m = p.matcher(value);
 
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         while (m.find()) {
             String envVarName = null == m.group(1) ? m.group(2) : m.group(1);
             String envVarDefault = null == m.group(3) ? "" : m.group(3);
@@ -56,6 +56,6 @@ public class EnvProperties extends Properties {
          }
         m.appendTail(sb);
         return sb.toString();
-        
+
     }
 }
diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionTool.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionTool.java
new file mode 100644 (file)
index 0000000..84317c5
--- /dev/null
@@ -0,0 +1,170 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.ccsdk.sli.core.utils.encryption;
+
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+
+import java.util.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to encapsulate the encryption and decryption support in one place and to
+ * provide a utility to encrypt and decrypt data.
+ */
+public class EncryptionTool {
+
+    /**
+     * The prefix we insert onto any data we encrypt so that we can tell if it is encrypted later and
+     * therefore decrypt it
+     */
+    public static final String ENCRYPTED_VALUE_PREFIX = "enc:";
+
+    /**
+     * The instance of the encryption utility object
+     */
+    private static EncryptionTool instance = null;
+
+    /**
+     * The logger for this class.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(EncryptionTool.class);
+
+    /**
+     * The secret passphrase (PBE) that we use to perform encryption and decryption. The algorithm we
+     * are using is a symmetrical cipher.
+     */
+    private static final char[] secret = {'C', '_', 'z', 'l', '!', 'K', '!', '4', '?', 'O', 'z', 'E', 'K', 'E', '>', 'U', 'R',
+                                          '/', '%', 'Y', '\\', 'f', 'b', '"', 'e', 'n', '{', '"', 'l', 'U', 'F', '+', 'E', '\'', 'R', 'T', 'p', '1',
+                                          'V', '4', 'l', 'a', '9', 'w', 'v', '5', 'Z', '#', 'i', 'V', '"', 'd', 'l', '!', 'L', 'M', 'g', 'L', 'Q',
+                                          '{', 'v', 'v', 'K', 'V'};
+
+
+
+    /**
+     * Get an instance of the EncryptionTool
+     *
+     * @return The encryption tool to be used
+     */
+    public static synchronized EncryptionTool getInstance() {
+        if (instance == null) {
+            instance = new EncryptionTool();
+        }
+        return instance;
+    }
+
+    /**
+     * Create the EncryptionTool instance
+     */
+    private EncryptionTool() {
+
+        StringBuilder sb = new StringBuilder("Found the following security algorithms:");
+        for (Provider p : Security.getProviders()) {
+            for (Service s : p.getServices()) {
+                String algo = s.getAlgorithm();
+                sb.append(String.format("%n -Algorithm [ %s ] in provider [ %s ] and service [ %s ]", algo, p.getName(),
+                        s.getClassName()));
+            }
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(sb.toString());
+        }
+    }
+
+    /**
+     * Decrypt the provided encrypted text
+     *
+     * @param cipherText THe cipher text to be decrypted. If the ciphertext is not encrypted, then it is
+     *        returned as is.
+     * @return the clear test of the (possibly) encrypted value. The original value if the string is not
+     *         encrypted.
+     */
+    public synchronized String decrypt(String cipherText) {
+        if (isEncrypted(cipherText)) {
+            String encValue = cipherText.substring(ENCRYPTED_VALUE_PREFIX.length());
+            byte[] plainByte = Base64.getDecoder().decode(encValue.getBytes());
+            byte[] decryptByte = xorWithSecret(plainByte);
+            return new String(decryptByte);
+        } else {
+            return cipherText;
+        }
+
+    }
+
+    /**
+     * Encrypt the provided clear text
+     *
+     * @param clearText The clear text to be encrypted
+     * @return the encrypted text. If the clear text is empty (null or zero length), then an empty
+     *         string is returned. If the clear text is already encrypted, it is not encrypted again and
+     *         is returned as is. Otherwise, the clear text is encrypted and returned.
+     */
+    public synchronized String encrypt(String clearText) {
+        if (clearText != null) {
+            byte[] encByte = xorWithSecret(clearText.getBytes());
+            String encryptedValue = new String(Base64.getEncoder().encode(encByte));
+            return ENCRYPTED_VALUE_PREFIX + encryptedValue;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Is a value encrypted? A value is considered to be encrypted if it begins with the
+     * {@linkplain #ENCRYPTED_VALUE_PREFIX encrypted value prefix}.
+     *
+     * @param value the value to check.
+     * @return true/false;
+     */
+    private static boolean isEncrypted(final String value) {
+        return value != null && value.startsWith(ENCRYPTED_VALUE_PREFIX);
+    }
+
+    /**
+     * XORs the input byte array with the secret key, padding 0x0 to the end of the secret key if the
+     * input is longer and returns a byte array the same size as input
+     *
+     * @param inp The byte array to be XORed with secret
+     * @return A byte array the same size as inp or null if input is null.
+     */
+    private byte[] xorWithSecret(byte[] inp) {
+        if (inp == null) {
+            return new byte[0];
+        }
+
+        byte[] secretBytes = new String(secret).getBytes();
+        int size = inp.length;
+
+        byte[] out = new byte[size];
+        for (int i = 0; i < size; i++) {
+            out[i] = (byte) ((inp[i]) ^ (secretBytes[i % secretBytes.length]));
+        }
+        return out;
+    }
+
+}
+
diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionToolTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionToolTest.java
new file mode 100644 (file)
index 0000000..e371233
--- /dev/null
@@ -0,0 +1,66 @@
+package org.onap.ccsdk.sli.core.utils.encryption;/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * ============LICENSE_END=========================================================
+ */
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class EncryptionToolTest {
+
+    private static final String PLAIN_TEXT = "text to encrypt";
+    private static final String EMPTY_STR = "";
+
+    private final EncryptionTool encryptionTool = EncryptionTool.getInstance();
+
+    @Test
+    public void should_return_prefix_given_empty_string() {
+        assertEquals("enc:", encryptionTool.encrypt(EMPTY_STR));
+    }
+
+    @Test
+    public void should_return_null_given_null() {
+        assertNull(encryptionTool.encrypt(null));
+    }
+
+    @Test
+    public void should_encrypt_given_string() {
+        String encrypted = encryptionTool.encrypt(PLAIN_TEXT);
+        assertNotEquals(encrypted, PLAIN_TEXT);
+        assertTrue(encrypted.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX));
+    }
+
+    @Test
+    public void should_not_decrypt_string_when_not_starting_with_prefix() {
+        assertNull(encryptionTool.decrypt(null));
+        assertEquals("mdi/12!dsao91", encryptionTool.decrypt("mdi/12!dsao91"));
+    }
+
+    @Test
+    public void should_decrypt_given_encrypted_string() {
+        String encrypted = encryptionTool.encrypt(PLAIN_TEXT);
+        assertEquals(PLAIN_TEXT, encryptionTool.decrypt(encrypted));
+    }
+}