diff options
30 files changed, 1905 insertions, 882 deletions
diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/pom.xml b/adaptors/ansible-adapter/ansible-adapter-bundle/pom.xml index 905221573..192bcec05 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/pom.xml +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/pom.xml @@ -54,71 +54,70 @@ <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> diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapter.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapter.java index e43d3e3c3..65f80a1c2 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapter.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapter.java @@ -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 index 000000000..20a8400bb --- /dev/null +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterConstants.java @@ -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"; + + +} diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterPropertiesProvider.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterPropertiesProvider.java index 6d9f4f12c..671b1e488 100755 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterPropertiesProvider.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/AnsibleAdapterPropertiesProvider.java @@ -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(); + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterImpl.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterImpl.java index 2361feebd..bc0af2782 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterImpl.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterImpl.java @@ -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 @@ -24,9 +22,16 @@ 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); @@ -282,57 +313,159 @@ public class AnsibleAdapterImpl implements AnsibleAdapter { } /** + * 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; } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImpl.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImpl.java index 36eec6a4b..e465e1378 100755 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImpl.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImpl.java @@ -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; } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/ConnectionBuilder.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/ConnectionBuilder.java index 672e0df67..1fbf20633 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/ConnectionBuilder.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/ConnectionBuilder.java @@ -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); + } + } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleMessageParser.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleMessageParser.java index 5f6342d94..e448f1c47 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleMessageParser.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleMessageParser.java @@ -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. @@ -26,66 +22,49 @@ 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); + } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResult.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResult.java index 3d1b3cfab..bad0f5e20 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResult.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResult.java @@ -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; + } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResultCodes.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResultCodes.java index a529e4a0c..55a1e7086 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResultCodes.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleResultCodes.java @@ -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(); } } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleServerEmulator.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleServerEmulator.java index 993c70062..a10a0aeb2 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleServerEmulator.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/model/AnsibleServerEmulator.java @@ -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 @@ -22,47 +20,38 @@ * ============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 diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/OSGI-INF/blueprint/ansible-adapter-blueprint.xml b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/OSGI-INF/blueprint/ansible-adapter-blueprint.xml index d7be01e9d..76abc8276 100755 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/OSGI-INF/blueprint/ansible-adapter-blueprint.xml +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/OSGI-INF/blueprint/ansible-adapter-blueprint.xml @@ -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. @@ -17,14 +16,16 @@ 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"/> diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/ansible-adapter.properties b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/ansible-adapter.properties index 761758bbb..8def3da30 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/ansible-adapter.properties +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/ansible-adapter.properties @@ -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 @@ -20,28 +18,24 @@ # # 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 diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/org/opendaylight/blueprint/ansible-adapter-blueprint.xml b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/org/opendaylight/blueprint/ansible-adapter-blueprint.xml index d7be01e9d..76abc8276 100755 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/org/opendaylight/blueprint/ansible-adapter-blueprint.xml +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/main/resources/org/opendaylight/blueprint/ansible-adapter-blueprint.xml @@ -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. @@ -17,14 +16,16 @@ 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"/> diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterImpl.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterImpl.java index 4636d2450..be4bfd8f2 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterImpl.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterImpl.java @@ -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 @@ -24,43 +22,82 @@ 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 diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterPropertiesProviderImpl.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterPropertiesProviderImpl.java index b3c01e9bd..5ce1712d3 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterPropertiesProviderImpl.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestAnsibleAdapterPropertiesProviderImpl.java @@ -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. @@ -15,39 +15,50 @@ * 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)); } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestConnectionBuilder.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestConnectionBuilder.java index c94655f56..25f89863d 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestConnectionBuilder.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/impl/TestConnectionBuilder.java @@ -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. @@ -15,140 +15,221 @@ * 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()); } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleAdapter.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleAdapter.java index 6fc90d012..3e1929bf5 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleAdapter.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleAdapter.java @@ -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 @@ -21,61 +19,82 @@ * 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 index 000000000..bcf18e3b2 --- /dev/null +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleMessageParser.java @@ -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 index 000000000..301cce135 --- /dev/null +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/adapter/ansible/model/TestAnsibleResult.java @@ -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()); + } + +} diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/ExecutorHarness.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/ExecutorHarness.java index 3555d7dfe..b6476d9dc 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/ExecutorHarness.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/ExecutorHarness.java @@ -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 { } } } + } diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/InterceptLogger.java b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/InterceptLogger.java index 92235cb39..3ed32376a 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/InterceptLogger.java +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/java/org/onap/ccsdk/test/InterceptLogger.java @@ -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========================================================= */ @@ -25,14 +23,12 @@ 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. @@ -40,97 +36,15 @@ import ch.qos.logback.classic.Level; 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 index 000000000..941c1d8f4 --- /dev/null +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client-cert.crt @@ -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 Binary files differnew file mode 100644 index 000000000..eb0a0d35a --- /dev/null +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/appc/asdc-client.jks diff --git a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/ccsdk/default.properties b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/properties/ansible-adapter-test.properties index 2f8fb4585..ef4bfb2e9 100644 --- a/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/org/onap/ccsdk/default.properties +++ b/adaptors/ansible-adapter/ansible-adapter-bundle/src/test/resources/properties/ansible-adapter-test.properties @@ -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) diff --git a/adaptors/ansible-adapter/pom.xml b/adaptors/ansible-adapter/pom.xml index 377df4918..5fd02ba09 100644 --- a/adaptors/ansible-adapter/pom.xml +++ b/adaptors/ansible-adapter/pom.xml @@ -48,7 +48,6 @@ <dependencyManagement> <dependencies> - <dependency> <groupId>org.onap.appc</groupId> <artifactId>ansible-adapter-features</artifactId> @@ -56,15 +55,12 @@ <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> @@ -74,12 +70,10 @@ <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> @@ -94,10 +88,8 @@ </goals> </execution> </executions> - </plugin> --> - </plugins> </build> diff --git a/core/utils/provider/pom.xml b/core/utils/provider/pom.xml index 4233ee574..ac9941aec 100644 --- a/core/utils/provider/pom.xml +++ b/core/utils/provider/pom.xml @@ -45,6 +45,10 @@ <version>${junit.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> </dependencies> <build> diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/common/EnvProperties.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/common/EnvProperties.java index 2e9f2673d..0dca28427 100644 --- a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/common/EnvProperties.java +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/common/EnvProperties.java @@ -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 index 000000000..84317c50a --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionTool.java @@ -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 index 000000000..e3712334e --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/encryption/EncryptionToolTest.java @@ -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)); + } +} |