aboutsummaryrefslogtreecommitdiffstats
path: root/adapters
diff options
context:
space:
mode:
Diffstat (limited to 'adapters')
-rw-r--r--adapters/mso-adapter-utils/src/main/java/org/onap/so/audit/beans/AuditInventory.java74
-rw-r--r--adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java420
-rw-r--r--adapters/mso-openstack-adapters/pom.xml10
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAudit.java39
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java68
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackServiceData.java86
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java111
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/HeatStackAudit.java199
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/AaiClientPropertiesImpl.java69
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java2
-rw-r--r--adapters/mso-openstack-adapters/src/main/resources/META-INF/services/org.onap.so.client.RestProperties1
-rw-r--r--adapters/mso-openstack-adapters/src/main/resources/application.yaml4
-rw-r--r--adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java150
-rw-r--r--adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditVServerTest.java332
-rw-r--r--adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/HeatStackAuditTest.java241
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNResourceGroupResponse.json79
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0.json41
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0Resources.json72
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1.json43
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1Resources.json72
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2.json41
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2Resources.json72
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/GetResources.json206
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/MISResourceGroupResponse.json31
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/MISSubInterface0.json41
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/MISSubInterface1Resources.json70
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/logback-test.xml6
27 files changed, 2363 insertions, 217 deletions
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/audit/beans/AuditInventory.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/audit/beans/AuditInventory.java
new file mode 100644
index 0000000000..025d40d7c4
--- /dev/null
+++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/audit/beans/AuditInventory.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017-2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.audit.beans;
+
+import java.io.Serializable;
+
+public class AuditInventory implements Serializable{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 4937350343452380760L;
+
+ private String cloudRegion;
+
+ private String cloudOwner;
+
+ private String tenantId;
+
+ private String heatStackName;
+
+ public String getCloudRegion() {
+ return cloudRegion;
+ }
+
+ public void setCloudRegion(String cloudRegion) {
+ this.cloudRegion = cloudRegion;
+ }
+
+ public String getCloudOwner() {
+ return cloudOwner;
+ }
+
+ public void setCloudOwner(String cloudOwner) {
+ this.cloudOwner = cloudOwner;
+ }
+
+ public String getTenantId() {
+ return tenantId;
+ }
+
+ public void setTenantId(String tenantId) {
+ this.tenantId = tenantId;
+ }
+
+ public String getHeatStackName() {
+ return heatStackName;
+ }
+
+ public void setHeatStackName(String heatStackName) {
+ this.heatStackName = heatStackName;
+ }
+
+
+
+}
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java
index f132f10ebb..14aee2f4f2 100644
--- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java
+++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java
@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Set;
import org.onap.so.adapters.vdu.CloudInfo;
@@ -79,6 +80,7 @@ import com.woorea.openstack.base.client.OpenStackRequest;
import com.woorea.openstack.base.client.OpenStackResponseException;
import com.woorea.openstack.heat.Heat;
import com.woorea.openstack.heat.model.CreateStackParam;
+import com.woorea.openstack.heat.model.Resources;
import com.woorea.openstack.heat.model.Stack;
import com.woorea.openstack.heat.model.Stack.Output;
import com.woorea.openstack.heat.model.Stacks;
@@ -311,37 +313,23 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
Stack heatStack = null;
try {
- // Execute the actual Openstack command to create the Heat stack
OpenStackRequest <Stack> request = heatClient.getStacks ().create (stack);
- // Begin X-Auth-User
- // Obtain an MSO token for the tenant
CloudIdentity cloudIdentity = cloudSite.getIdentityService();
- // cloudIdentity.getMsoId(), cloudIdentity.getMsoPass()
- //req
request.header ("X-Auth-User", cloudIdentity.getMsoId ());
request.header ("X-Auth-Key", CryptoUtils.decryptCloudConfigPassword(cloudIdentity.getMsoPass ()));
- LOGGER.debug ("headers added, about to executeAndRecordOpenstackRequest");
- //LOGGER.debug(this.requestToStringBuilder(stack).toString());
- // END - try to fix X-Auth-User
heatStack = executeAndRecordOpenstackRequest (request);
} catch (OpenStackResponseException e) {
- // Since this came on the 'Create Stack' command, nothing was changed
- // in the cloud. Return the error as an exception.
- if (e.getStatus () == 409) {
- // Stack already exists. Return a specific error for this case
+ if (e.getStatus () == 409) {
MsoStackAlreadyExists me = new MsoStackAlreadyExists (stackName, tenantId, cloudSiteId);
me.addContext (CREATE_STACK);
throw me;
- } else {
- // Convert the OpenStackResponseException to an MsoOpenstackException
+ } else {
LOGGER.debug("ERROR STATUS = " + e.getStatus() + ",\n" + e.getMessage() + "\n" + e.getLocalizedMessage());
throw heatExceptionToMsoException (e, CREATE_STACK);
}
- } catch (OpenStackConnectException e) {
- // Error connecting to Openstack instance. Convert to an MsoException
+ } catch (OpenStackConnectException e) {
throw heatExceptionToMsoException (e, CREATE_STACK);
- } catch (RuntimeException e) {
- // Catch-all
+ } catch (RuntimeException e) {
throw runtimeExceptionToMsoException (e, CREATE_STACK);
}
@@ -349,211 +337,197 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
// Otherwise, simple query by name returns a 302 redirect.
// NOTE: This is specific to the v1 Orchestration API.
String canonicalName = stackName + "/" + heatStack.getId ();
-
- // If client has requested a final response, poll for stack completion
+
if (pollForCompletion) {
- // Set a time limit on overall polling.
- // Use the resource (template) timeout for Openstack (expressed in minutes)
- // and add one poll interval to give Openstack a chance to fail on its own.s
-
- int createPollInterval = Integer.parseInt(this.environment.getProperty(createPollIntervalProp, createPollIntervalDefault));
- int pollTimeout = (timeoutMinutes * 60) + createPollInterval;
- // New 1610 - poll on delete if we rollback - use same values for now
- int deletePollInterval = createPollInterval;
- int deletePollTimeout = pollTimeout;
- boolean createTimedOut = false;
- StringBuilder stackErrorStatusReason = new StringBuilder("");
- LOGGER.debug("createPollInterval=" + createPollInterval + ", pollTimeout=" + pollTimeout);
-
- while (true) {
- try {
- heatStack = queryHeatStack (heatClient, canonicalName);
- LOGGER.debug (heatStack.getStackStatus () + " (" + canonicalName + ")");
- try {
- LOGGER.debug("Current stack " + this.getOutputsAsStringBuilder(heatStack).toString());
- } catch (Exception e) {
- LOGGER.debug("an error occurred trying to print out the current outputs of the stack", e);
- }
-
- if ("CREATE_IN_PROGRESS".equals (heatStack.getStackStatus ())) {
- // Stack creation is still running.
- // Sleep and try again unless timeout has been reached
- if (pollTimeout <= 0) {
- // Note that this should not occur, since there is a timeout specified
- // in the Openstack call.
- LOGGER.error (MessageEnum.RA_CREATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName, heatStack.getStackStatus (), "", "", MsoLogger.ErrorCode.AvailabilityError, "Create stack timeout");
- createTimedOut = true;
- break;
- }
-
- sleep(createPollInterval * 1000L);
-
- pollTimeout -= createPollInterval;
- LOGGER.debug("pollTimeout remaining: " + pollTimeout);
- } else {
- //save off the status & reason msg before we attempt delete
- stackErrorStatusReason.append("Stack error (" + heatStack.getStackStatus() + "): " + heatStack.getStackStatusReason());
- break;
- }
- } catch (MsoException me) {
- // Cannot query the stack status. Something is wrong.
- // Try to roll back the stack
- if (!backout)
- {
- LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, stack deletion suppressed", "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in Create Stack, stack deletion suppressed");
- }
- else
- {
- try {
- LOGGER.debug("Create Stack error - unable to query for stack status - attempting to delete stack: " + canonicalName + " - This will likely fail and/or we won't be able to query to see if delete worked");
- OpenStackRequest <Void> request = heatClient.getStacks ().deleteByName (canonicalName);
- executeAndRecordOpenstackRequest (request);
- // this may be a waste of time - if we just got an exception trying to query the stack - we'll just
- // get another one, n'est-ce pas?
- boolean deleted = false;
- while (!deleted) {
- try {
- heatStack = queryHeatStack(heatClient, canonicalName);
- if (heatStack != null) {
- LOGGER.debug(heatStack.getStackStatus());
- if ("DELETE_IN_PROGRESS".equals(heatStack.getStackStatus())) {
- if (deletePollTimeout <= 0) {
- LOGGER.error (MessageEnum.RA_CREATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName,
- heatStack.getStackStatus (), "", "", MsoLogger.ErrorCode.AvailabilityError,
- "Rollback: DELETE stack timeout");
- break;
- } else {
- sleep(deletePollInterval * 1000L);
- deletePollTimeout -= deletePollInterval;
- }
- } else if ("DELETE_COMPLETE".equals(heatStack.getStackStatus())){
- LOGGER.debug("DELETE_COMPLETE for " + canonicalName);
- deleted = true;
- continue;
- } else {
- //got a status other than DELETE_IN_PROGRESS or DELETE_COMPLETE - so break and evaluate
- break;
- }
- } else {
- // assume if we can't find it - it's deleted
- LOGGER.debug("heatStack returned null - assume the stack " + canonicalName + " has been deleted");
- deleted = true;
- continue;
- }
-
- } catch (Exception e3) {
- // Just log this one. We will report the original exception.
- LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack: Nested exception rolling back stack: " + e3, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack: Nested exception rolling back stack on error on query");
-
- }
- }
- } catch (Exception e2) {
- // Just log this one. We will report the original exception.
- LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack: Nested exception rolling back stack: " + e2, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack: Nested exception rolling back stack");
- }
- }
-
- // Propagate the original exception from Stack Query.
- me.addContext (CREATE_STACK);
- throw me;
- }
- }
-
- if (!"CREATE_COMPLETE".equals (heatStack.getStackStatus ())) {
- LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack error: Polling complete with non-success status: "
- + heatStack.getStackStatus () + ", " + heatStack.getStackStatusReason (), "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack error");
-
- // Rollback the stack creation, since it is in an indeterminate state.
- if (!backout)
- {
- LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, stack deletion suppressed", "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack error, stack deletion suppressed");
- }
- else
- {
- try {
- LOGGER.debug("Create Stack errored - attempting to DELETE stack: " + canonicalName);
- LOGGER.debug("deletePollInterval=" + deletePollInterval + ", deletePollTimeout=" + deletePollTimeout);
- OpenStackRequest <Void> request = heatClient.getStacks ().deleteByName (canonicalName);
- executeAndRecordOpenstackRequest (request);
- boolean deleted = false;
- while (!deleted) {
- try {
- heatStack = queryHeatStack(heatClient, canonicalName);
- if (heatStack != null) {
- LOGGER.debug(heatStack.getStackStatus() + " (" + canonicalName + ")");
- if ("DELETE_IN_PROGRESS".equals(heatStack.getStackStatus())) {
- if (deletePollTimeout <= 0) {
- LOGGER.error (MessageEnum.RA_CREATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName,
- heatStack.getStackStatus (), "", "", MsoLogger.ErrorCode.AvailabilityError,
- "Rollback: DELETE stack timeout");
- break;
- } else {
- sleep(deletePollInterval * 1000L);
- deletePollTimeout -= deletePollInterval;
- LOGGER.debug("deletePollTimeout remaining: " + deletePollTimeout);
- }
- } else if ("DELETE_COMPLETE".equals(heatStack.getStackStatus())){
- LOGGER.debug("DELETE_COMPLETE for " + canonicalName);
- deleted = true;
- continue;
- } else if ("DELETE_FAILED".equals(heatStack.getStackStatus())) {
- // Warn about this (?) - but still throw the original exception
- LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, stack deletion FAILED", "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack error, stack deletion FAILED");
- LOGGER.debug("Stack deletion FAILED on a rollback of a create - " + canonicalName + ", status=" + heatStack.getStackStatus() + ", reason=" + heatStack.getStackStatusReason());
- break;
- } else {
- //got a status other than DELETE_IN_PROGRESS or DELETE_COMPLETE - so break and evaluate
- break;
- }
- } else {
- // assume if we can't find it - it's deleted
- LOGGER.debug("heatStack returned null - assume the stack " + canonicalName + " has been deleted");
- deleted = true;
- continue;
- }
-
- } catch (MsoException me2) {
- // We got an exception on the delete - don't throw this exception - throw the original - just log.
- LOGGER.debug("Exception thrown trying to delete " + canonicalName + " on a create->rollback: " + me2.getContextMessage(), me2);
- LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, then stack deletion FAILED - exception thrown", "", "", MsoLogger.ErrorCode.BusinessProcesssError, me2.getContextMessage());
- }
-
- } // end while !deleted
- StringBuilder errorContextMessage;
- if (createTimedOut) {
- errorContextMessage = new StringBuilder("Stack Creation Timeout");
- } else {
- errorContextMessage = stackErrorStatusReason;
- }
- if (deleted) {
- errorContextMessage.append(" - stack successfully deleted");
- } else {
- errorContextMessage.append(" - encountered an error trying to delete the stack");
- }
-// MsoOpenstackException me = new MsoOpenstackException(0, "", stackErrorStatusReason.toString());
- // me.addContext(CREATE_STACK);
-
- // throw me;
- } catch (Exception e2) {
- // shouldn't happen - but handle
- LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack: Nested exception rolling back stack: " + e2, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in Create Stack: rolling back stack");
- }
- }
- MsoOpenstackException me = new MsoOpenstackException(0, "", stackErrorStatusReason.toString());
- me.addContext(CREATE_STACK);
-
- throw me;
- }
-
+ heatStack = pollStackForCompletion(cloudSiteId, tenantId, stackName, timeoutMinutes, backout, heatClient,
+ heatStack, canonicalName);
} else {
// Get initial status, since it will have been null after the create.
heatStack = queryHeatStack (heatClient, canonicalName);
LOGGER.debug (heatStack.getStackStatus ());
}
-
return new StackInfoMapper(heatStack).map();
}
+ private Stack pollStackForCompletion(String cloudSiteId, String tenantId, String stackName, int timeoutMinutes,
+ boolean backout, Heat heatClient, Stack heatStack, String canonicalName)
+ throws MsoException, MsoOpenstackException {
+ int createPollInterval = Integer.parseInt(this.environment.getProperty(createPollIntervalProp, createPollIntervalDefault));
+ int pollTimeout = (timeoutMinutes * 60) + createPollInterval;
+ int deletePollInterval = createPollInterval;
+ int deletePollTimeout = pollTimeout;
+ boolean createTimedOut = false;
+ StringBuilder stackErrorStatusReason = new StringBuilder("");
+ LOGGER.debug("createPollInterval=" + createPollInterval + ", pollTimeout=" + pollTimeout);
+
+ while (true) {
+ try {
+ heatStack = queryHeatStack (heatClient, canonicalName);
+ LOGGER.debug (heatStack.getStackStatus () + " (" + canonicalName + ")");
+ try {
+ LOGGER.debug("Current stack " + this.getOutputsAsStringBuilder(heatStack).toString());
+ } catch (Exception e) {
+ LOGGER.debug("an error occurred trying to print out the current outputs of the stack", e);
+ }
+
+ if ("CREATE_IN_PROGRESS".equals (heatStack.getStackStatus ())) {
+ if (pollTimeout <= 0) {
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName, heatStack.getStackStatus (), "", "", MsoLogger.ErrorCode.AvailabilityError, "Create stack timeout");
+ createTimedOut = true;
+ break;
+ }
+ sleep(createPollInterval * 1000L);
+ pollTimeout -= createPollInterval;
+ LOGGER.debug("pollTimeout remaining: " + pollTimeout);
+ } else {
+ stackErrorStatusReason.append("Stack error (" + heatStack.getStackStatus() + "): " + heatStack.getStackStatusReason());
+ break;
+ }
+ } catch (MsoException me) {
+ // Cannot query the stack status. Something is wrong.
+ // Try to roll back the stack
+ if (!backout)
+ {
+ LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, stack deletion suppressed", "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in Create Stack, stack deletion suppressed");
+ }
+ else
+ {
+ try {
+ LOGGER.debug("Create Stack error - unable to query for stack status - attempting to delete stack: " + canonicalName + " - This will likely fail and/or we won't be able to query to see if delete worked");
+ OpenStackRequest <Void> request = heatClient.getStacks ().deleteByName (canonicalName);
+ executeAndRecordOpenstackRequest (request);
+ boolean deleted = false;
+ while (!deleted) {
+ try {
+ heatStack = queryHeatStack(heatClient, canonicalName);
+ if (heatStack != null) {
+ LOGGER.debug(heatStack.getStackStatus());
+ if ("DELETE_IN_PROGRESS".equals(heatStack.getStackStatus())) {
+ if (deletePollTimeout <= 0) {
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName,
+ heatStack.getStackStatus (), "", "", MsoLogger.ErrorCode.AvailabilityError,
+ "Rollback: DELETE stack timeout");
+ break;
+ } else {
+ sleep(deletePollInterval * 1000L);
+ deletePollTimeout -= deletePollInterval;
+ }
+ } else if ("DELETE_COMPLETE".equals(heatStack.getStackStatus())){
+ LOGGER.debug("DELETE_COMPLETE for " + canonicalName);
+ deleted = true;
+ continue;
+ } else {
+ //got a status other than DELETE_IN_PROGRESS or DELETE_COMPLETE - so break and evaluate
+ break;
+ }
+ } else {
+ // assume if we can't find it - it's deleted
+ LOGGER.debug("heatStack returned null - assume the stack " + canonicalName + " has been deleted");
+ deleted = true;
+ continue;
+ }
+
+ } catch (Exception e3) {
+ // Just log this one. We will report the original exception.
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack: Nested exception rolling back stack: " + e3, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack: Nested exception rolling back stack on error on query");
+
+ }
+ }
+ } catch (Exception e2) {
+ // Just log this one. We will report the original exception.
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack: Nested exception rolling back stack: " + e2, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack: Nested exception rolling back stack");
+ }
+ }
+
+ // Propagate the original exception from Stack Query.
+ me.addContext (CREATE_STACK);
+ throw me;
+ }
+ }
+
+ if (!"CREATE_COMPLETE".equals (heatStack.getStackStatus ())) {
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack error: Polling complete with non-success status: "
+ + heatStack.getStackStatus () + ", " + heatStack.getStackStatusReason (), "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack error");
+
+ // Rollback the stack creation, since it is in an indeterminate state.
+ if (!backout)
+ {
+ LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, stack deletion suppressed", "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack error, stack deletion suppressed");
+ }
+ else
+ {
+ try {
+ LOGGER.debug("Create Stack errored - attempting to DELETE stack: " + canonicalName);
+ LOGGER.debug("deletePollInterval=" + deletePollInterval + ", deletePollTimeout=" + deletePollTimeout);
+ OpenStackRequest <Void> request = heatClient.getStacks ().deleteByName (canonicalName);
+ executeAndRecordOpenstackRequest (request);
+ boolean deleted = false;
+ while (!deleted) {
+ try {
+ heatStack = queryHeatStack(heatClient, canonicalName);
+ if (heatStack != null) {
+ LOGGER.debug(heatStack.getStackStatus() + " (" + canonicalName + ")");
+ if ("DELETE_IN_PROGRESS".equals(heatStack.getStackStatus())) {
+ if (deletePollTimeout <= 0) {
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName,
+ heatStack.getStackStatus (), "", "", MsoLogger.ErrorCode.AvailabilityError,
+ "Rollback: DELETE stack timeout");
+ break;
+ } else {
+ sleep(deletePollInterval * 1000L);
+ deletePollTimeout -= deletePollInterval;
+ LOGGER.debug("deletePollTimeout remaining: " + deletePollTimeout);
+ }
+ } else if ("DELETE_COMPLETE".equals(heatStack.getStackStatus())){
+ LOGGER.debug("DELETE_COMPLETE for " + canonicalName);
+ deleted = true;
+ continue;
+ } else if ("DELETE_FAILED".equals(heatStack.getStackStatus())) {
+ // Warn about this (?) - but still throw the original exception
+ LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, stack deletion FAILED", "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Create Stack error, stack deletion FAILED");
+ LOGGER.debug("Stack deletion FAILED on a rollback of a create - " + canonicalName + ", status=" + heatStack.getStackStatus() + ", reason=" + heatStack.getStackStatusReason());
+ break;
+ } else {
+ //got a status other than DELETE_IN_PROGRESS or DELETE_COMPLETE - so break and evaluate
+ break;
+ }
+ } else {
+ // assume if we can't find it - it's deleted
+ LOGGER.debug("heatStack returned null - assume the stack " + canonicalName + " has been deleted");
+ deleted = true;
+ continue;
+ }
+
+ } catch (MsoException me2) {
+ // We got an exception on the delete - don't throw this exception - throw the original - just log.
+ LOGGER.debug("Exception thrown trying to delete " + canonicalName + " on a create->rollback: " + me2.getContextMessage(), me2);
+ LOGGER.warn(MessageEnum.RA_CREATE_STACK_ERR, "Create Stack errored, then stack deletion FAILED - exception thrown", "", "", MsoLogger.ErrorCode.BusinessProcesssError, me2.getContextMessage());
+ }
+
+ } // end while !deleted
+ StringBuilder errorContextMessage;
+ if (createTimedOut) {
+ errorContextMessage = new StringBuilder("Stack Creation Timeout");
+ } else {
+ errorContextMessage = stackErrorStatusReason;
+ }
+ if (deleted) {
+ errorContextMessage.append(" - stack successfully deleted");
+ } else {
+ errorContextMessage.append(" - encountered an error trying to delete the stack");
+ }
+ } catch (Exception e2) {
+ // shouldn't happen - but handle
+ LOGGER.error (MessageEnum.RA_CREATE_STACK_ERR, "Create Stack: Nested exception rolling back stack: " + e2, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in Create Stack: rolling back stack");
+ }
+ }
+ MsoOpenstackException me = new MsoOpenstackException(0, "", stackErrorStatusReason.toString());
+ me.addContext(CREATE_STACK);
+ throw me;
+ }
+ return heatStack;
+ }
+
/**
* Query for a single stack (by Name) in a tenant. This call will always return a
* StackInfo object. If the stack does not exist, an "empty" StackInfo will be
@@ -1231,7 +1205,7 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
sb.append("[END]");
return sb;
}
-
+
public void copyBaseOutputsToInputs(Map<String, Object> inputs,
Map<String, Object> otherStackOutputs, List<String> paramNames, Map<String, String> aliases) {
@@ -1727,6 +1701,22 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin{
return vduStatus;
}
+
+ public Resources queryStackResources(String cloudSiteId, String tenantId, String stackName) throws MsoException {
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId)
+ .orElseThrow(() -> new MsoCloudSiteNotFound(cloudSiteId));
+ Heat heatClient = getHeatClient(cloudSite, tenantId);
+ OpenStackRequest<Resources> request = heatClient.getResources().listResources(stackName);
+ return executeAndRecordOpenstackRequest(request);
+ }
+
+ public <R> R executeHeatClientRequest(String url, String cloudSiteId, String tenantId, Class<R> returnType) throws MsoException {
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId)
+ .orElseThrow(() -> new MsoCloudSiteNotFound(cloudSiteId));
+ Heat heatClient = getHeatClient(cloudSite, tenantId);
+ OpenStackRequest<R> request = heatClient.get(url, returnType);
+ return executeAndRecordOpenstackRequest(request);
+ }
protected void sleep(long time) {
try {
diff --git a/adapters/mso-openstack-adapters/pom.xml b/adapters/mso-openstack-adapters/pom.xml
index 743c50dc75..8d4f30b631 100644
--- a/adapters/mso-openstack-adapters/pom.xml
+++ b/adapters/mso-openstack-adapters/pom.xml
@@ -269,5 +269,15 @@
<artifactId>cxf-logging</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.onap.so.libs.openstack-java-sdk</groupId>
+ <artifactId>nova-model</artifactId>
+ <version>${openstack.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.camunda.bpm</groupId>
+ <artifactId>camunda-external-task-client</artifactId>
+ <version>1.2.0-SNAPSHOT</version>
+ </dependency>
</dependencies>
</project>
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAudit.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAudit.java
new file mode 100644
index 0000000000..292cebf292
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAudit.java
@@ -0,0 +1,39 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import org.onap.so.client.aai.AAIResourcesClient;
+
+public class AbstractAudit {
+
+ private AAIResourcesClient aaiClient;
+
+ protected AAIResourcesClient getAaiClient(){
+ if(aaiClient == null)
+ return new AAIResourcesClient();
+ else
+ return aaiClient;
+ }
+
+ protected void setAaiClient(AAIResourcesClient aaiResource){
+ aaiClient = aaiResource;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java
new file mode 100644
index 0000000000..38b00688a7
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import java.security.GeneralSecurityException;
+
+import javax.annotation.PostConstruct;
+
+import org.camunda.bpm.client.ExternalTaskClient;
+import org.camunda.bpm.client.backoff.ExponentialBackoffStrategy;
+import org.camunda.bpm.client.interceptor.ClientRequestInterceptor;
+import org.camunda.bpm.client.interceptor.auth.BasicAuthProvider;
+import org.onap.so.utils.CryptoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+@Component
+@Profile("!test")
+public class AuditStackService {
+
+ private static final Logger logger = LoggerFactory.getLogger(AuditStackService.class);
+
+ @Autowired
+ public Environment env;
+
+ @Autowired
+ private AuditStackServiceData auditStack;
+
+ @PostConstruct
+ public void auditAAIInventory() {
+ String auth = "";
+ try {
+ auth = CryptoUtils.decrypt(env.getRequiredProperty("mso.auth"), env.getRequiredProperty("mso.msoKey"));
+ } catch (IllegalStateException | GeneralSecurityException e) {
+ logger.error("Error Decrypting Password", e);
+ }
+ ClientRequestInterceptor interceptor = new BasicAuthProvider(env.getRequiredProperty("mso.config.cadi.aafId"),
+ auth);
+ ExternalTaskClient client = ExternalTaskClient.create()
+ .baseUrl(env.getRequiredProperty("mso.workflow.endpoint")).maxTasks(5).addInterceptor(interceptor)
+ .asyncResponseTimeout(120000).backoffStrategy(new ExponentialBackoffStrategy(0, 0, 0)).build();
+ client.subscribe("InventoryAudit").lockDuration(5000)
+ .handler(auditStack::executeExternalTask).open();
+ }
+
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackServiceData.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackServiceData.java
new file mode 100644
index 0000000000..b0369395ed
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackServiceData.java
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017-2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import java.util.Collections;
+
+import org.camunda.bpm.client.task.ExternalTask;
+import org.camunda.bpm.client.task.ExternalTaskService;
+import org.onap.so.audit.beans.AuditInventory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AuditStackServiceData {
+
+ private static final String UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI = "Unable to find all VServers and L-Interaces in A&AI";
+
+ private static final int[] RETRY_SEQUENCE = new int[] { 1, 1, 2, 3, 5, 8, 13, 20};
+
+
+ private static final Logger logger = LoggerFactory.getLogger(AuditStackServiceData.class);
+
+ @Autowired
+ public HeatStackAudit heatStackAudit;
+
+ @Autowired
+ public Environment env;
+
+ protected void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService){
+ AuditInventory auditInventory = externalTask.getVariable("auditInventory");
+ boolean success = false;
+ try {
+ logger.info("Executing External Task Audit Inventory, Retry Number: {} \n {}", auditInventory,externalTask.getRetries());
+ success=heatStackAudit.auditHeatStack(auditInventory.getCloudRegion(), auditInventory.getCloudOwner(),
+ auditInventory.getTenantId(), auditInventory.getHeatStackName());
+ } catch (Exception e) {
+ logger.error("Error during audit of stack", e);
+ }
+
+ if (success) {
+ externalTaskService.complete(externalTask);
+ logger.debug("The External Task Id: {} Successful", externalTask.getId());
+ } else {
+ if(externalTask.getRetries() == null){
+ logger.debug("The External Task Id: {} Failed, Setting Retries to Default Start Value: {}", externalTask.getId(),RETRY_SEQUENCE.length);
+ externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, RETRY_SEQUENCE.length, 10000);
+ }else if(externalTask.getRetries() != null &&
+ externalTask.getRetries()-1 == 0){
+ logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTask.getId());
+ externalTaskService.handleBpmnError(externalTask, "AuditAAIInventoryFailure", "Number of Retries Exceeded auditing inventory");
+ }else{
+ logger.debug("The External Task Id: {} Failed, Decrementing Retries: {} , Retry Delay: ", externalTask.getId(),externalTask.getRetries()-1, calculateRetryDelay(externalTask.getRetries()));
+ externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, externalTask.getRetries()-1, calculateRetryDelay(externalTask.getRetries()));
+ }
+ logger.debug("The External Task Id: {} Failed", externalTask.getId());
+ }
+
+
+ }
+ protected long calculateRetryDelay(int currentRetries){
+ int retrySequence = RETRY_SEQUENCE.length - currentRetries;
+ long retryMultiplier = Long.parseLong(env.getProperty("mso.workflow.topics.retryMultiplier","6000"));
+ return RETRY_SEQUENCE[retrySequence] * retryMultiplier;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java
new file mode 100644
index 0000000000..6e6ecd51d4
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java
@@ -0,0 +1,111 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import java.util.Optional;
+import java.util.Set;
+
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.aai.domain.yang.LInterfaces;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.client.aai.AAIObjectPlurals;
+import org.onap.so.client.aai.AAIObjectType;
+import org.onap.so.client.aai.entities.AAIResultWrapper;
+import org.onap.so.client.aai.entities.uri.AAIResourceUri;
+import org.onap.so.client.aai.entities.uri.AAIUriFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AuditVServer extends AbstractAudit {
+ private static final Logger logger = LoggerFactory.getLogger(AuditVServer.class);
+
+ public boolean auditVservers(Set<Vserver> vServersToAudit, String tenantId, String cloudOwner, String cloudRegion) {
+ if (vServersToAudit == null || vServersToAudit.isEmpty()){
+ return false;
+ }
+ return vServersToAudit.stream()
+ .filter(vServer -> !doesVServerExistInAAI(vServer, tenantId, cloudOwner, cloudRegion)).findFirst()
+ .map(v -> false).orElse(true);
+ }
+
+ private boolean doesVServerExistInAAI(Vserver vServer, String tenantId, String cloudOwner, String cloudRegion) {
+ AAIResourceUri vserverURI = AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegion,
+ tenantId, vServer.getVserverId());
+ boolean vServerExists = getAaiClient().exists(vserverURI);
+ boolean doesExist = getAaiClient().exists(vserverURI);
+ logger.info("v-server {} exists: {}", vServer.getVserverId(), doesExist);
+ boolean allNeutronNetworksExist = true;
+ if (vServerExists && vServer.getLInterfaces() != null) {
+ allNeutronNetworksExist = vServer.getLInterfaces()
+ .getLInterface().stream().filter(lInterface -> !doesLinterfaceExistinAAI(lInterface,
+ vServer.getVserverId(), tenantId, cloudOwner, cloudRegion))
+ .findFirst().map(v -> false).orElse(true);
+ }
+ return vServerExists && allNeutronNetworksExist;
+ }
+
+ private boolean doesLinterfaceExistinAAI(LInterface lInterface, String vServerId, String tenantId,
+ String cloudOwner, String cloudRegion) {
+ boolean doesLInterfaceExist = false;
+ boolean doSubInterfacesExist = true;
+ AAIResourceUri linterfaceURI = AAIUriFactory
+ .createResourceUri(AAIObjectPlurals.L_INTERFACE, cloudOwner, cloudRegion, tenantId, vServerId)
+ .queryParam("interface-id", lInterface.getInterfaceId());
+ Optional<LInterfaces> queriedLInterface = getAaiClient().get(LInterfaces.class, linterfaceURI);
+ if (queriedLInterface.isPresent()) {
+ if (queriedLInterface.get().getLInterface().size() > 1) {
+ logger.error("Non-Unique LInterface Found stopping audit, L-Interface Id: " +lInterface.getInterfaceId());
+ doesLInterfaceExist = false;
+ } else {
+ doesLInterfaceExist = true;
+ lInterface.setInterfaceName(queriedLInterface.get().getLInterface().get(0).getInterfaceName());
+ }
+ }
+ logger.info("l-interface id:{} name: {} exists: {}", lInterface.getInterfaceId(), lInterface.getInterfaceName(),
+ doesLInterfaceExist);
+
+ if (doesLInterfaceExist && lInterface.getLInterfaces() != null) {
+ doSubInterfacesExist = lInterface.getLInterfaces().getLInterface()
+ .stream().filter(subInterface -> !doesSubInterfaceExistinAAI(subInterface,
+ lInterface.getInterfaceName(), vServerId, tenantId, cloudOwner, cloudRegion))
+ .findFirst().map(v -> false).orElse(true);
+ } else
+ logger.debug("l-interface {} does not contain any sub-iterfaces", lInterface.getInterfaceId());
+
+ return doesLInterfaceExist && doSubInterfacesExist;
+ }
+
+ private boolean doesSubInterfaceExistinAAI(LInterface subInterface, String linterfaceName, String vServerId,
+ String tenantId, String cloudOwner, String cloudRegion) {
+ logger.info("checking if sub-l-interface {} , linterfaceName: {} vserverId: {} exists",
+ subInterface.getInterfaceId(), linterfaceName, vServerId);
+
+ AAIResourceUri linterfaceURI = AAIUriFactory.createResourceUri(AAIObjectPlurals.SUB_L_INTERFACE, cloudOwner,
+ cloudRegion, tenantId, vServerId, linterfaceName)
+ .queryParam("interface-id", subInterface.getInterfaceId());
+
+ boolean doesExist = getAaiClient().exists(linterfaceURI);
+ logger.info("sub-l-interface {} exists: {}", subInterface.getInterfaceId(), doesExist);
+ return doesExist;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/HeatStackAudit.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/HeatStackAudit.java
new file mode 100644
index 0000000000..7bba136da2
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/HeatStackAudit.java
@@ -0,0 +1,199 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.aai.domain.yang.LInterfaces;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.openstack.utils.MsoHeatUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.woorea.openstack.heat.model.Link;
+import com.woorea.openstack.heat.model.Resource;
+import com.woorea.openstack.heat.model.Resources;
+import com.woorea.openstack.heat.model.Stack;
+
+@Component
+public class HeatStackAudit {
+
+ private static final String RESOURCES = "/resources";
+
+ protected static final Logger logger = LoggerFactory.getLogger(HeatStackAudit.class);
+
+ @Autowired
+ protected MsoHeatUtils heat;
+
+ @Autowired
+ protected AuditVServer auditVservers;
+
+ public boolean auditHeatStack(String cloudRegion, String cloudOwner, String tenantId, String heatStackName) {
+ try {
+ logger.debug("Fetching Top Level Stack Information");
+ Resources resources = heat.queryStackResources(cloudRegion, tenantId, heatStackName);
+ List<Resource> novaResources = resources.getList().stream()
+ .filter(p -> "OS::Nova::Server".equals(p.getType())).collect(Collectors.toList());
+ List<Resource> resourceGroups = resources.getList().stream()
+ .filter(p -> "OS::Heat::ResourceGroup".equals(p.getType()) && p.getName().contains("subinterfaces")).collect(Collectors.toList());
+ Set<Vserver> vserversToAudit = createVserverSet(resources, novaResources);
+ Set<Vserver> vserversWithSubInterfaces = processSubInterfaces(cloudRegion, tenantId, resourceGroups,
+ vserversToAudit);
+ return auditVservers.auditVservers(vserversWithSubInterfaces, tenantId, cloudOwner, cloudRegion);
+ } catch (Exception e) {
+ logger.error("Error during auditing stack resources", e);
+ return false;
+ }
+ }
+
+ protected Set<Vserver> processSubInterfaces(String cloudRegion, String tenantId, List<Resource> resourceGroups,
+ Set<Vserver> vServersToAudit) throws Exception {
+ for (Resource resourceGroup : resourceGroups) {
+ processResourceGroups(cloudRegion, tenantId, vServersToAudit, resourceGroup);
+ }
+ return vServersToAudit;
+ }
+
+ protected void processResourceGroups(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface,
+ Resource resourceGroup) throws Exception {
+ Optional<Link> stackLink = resourceGroup.getLinks().stream().filter(link -> "nested".equals(link.getRel()))
+ .findAny();
+ if (stackLink.isPresent()) {
+ try {
+ Optional<String> path = extractResourcePathFromHref(stackLink.get().getHref());
+ if (path.isPresent()) {
+ logger.debug("Fetching nested Resource Stack Information");
+ Resources nestedResourceGroupResources = heat.executeHeatClientRequest(path.get(), cloudRegion,
+ tenantId, Resources.class);
+ processNestedResourceGroup(cloudRegion, tenantId, vServersWithLInterface,
+ nestedResourceGroupResources);
+ } else
+ throw new Exception("Error finding Path from Self Link");
+ } catch (Exception e) {
+ logger.error("Error Parsing Link to obtain Path", e);
+ throw new Exception("Error finding Path from Self Link");
+ }
+
+ }
+ }
+
+ protected void processNestedResourceGroup(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface,
+ Resources nestedResourceGroupResources) throws Exception {
+ for (Resource resourceGroupNested : nestedResourceGroupResources) {
+ Optional<Link> subInterfaceStackLink = resourceGroupNested.getLinks().stream()
+ .filter(link -> "nested".equals(link.getRel())).findAny();
+ if (subInterfaceStackLink.isPresent()) {
+ addSubInterface(cloudRegion, tenantId, vServersWithLInterface,subInterfaceStackLink.get());
+ }
+ }
+ }
+
+ protected void addSubInterface(String cloudRegion, String tenantId, Set<Vserver> vServersWithLInterface, Link subInterfaceStackLink) throws Exception {
+ Optional<String> resourcePath = extractResourcePathFromHref(subInterfaceStackLink.getHref());
+ Optional<String> stackPath = extractStackPathFromHref(subInterfaceStackLink.getHref());
+ if (resourcePath.isPresent() && stackPath.isPresent()) {
+ logger.debug("Fetching nested Sub-Interface Stack Information");
+ Stack subinterfaceStack = heat.executeHeatClientRequest(stackPath.get(), cloudRegion, tenantId, Stack.class);
+ Resources subinterfaceResources = heat.executeHeatClientRequest(resourcePath.get(), cloudRegion, tenantId, Resources.class);
+ if (subinterfaceStack != null) {
+ addSubInterfaceToVserver(vServersWithLInterface, subinterfaceStack, subinterfaceResources);
+ }
+ } else
+ throw new Exception("Error finding Path from Self Link");
+
+ }
+
+ protected void addSubInterfaceToVserver(Set<Vserver> vServersWithLInterface, Stack subinterfaceStack, Resources subinterfaceResources) throws Exception {
+ String parentNeutronPortId = (String) subinterfaceStack.getParameters().get("port_interface");
+ logger.debug("Parent neutron Port: {} on SubInterface: {}", parentNeutronPortId, subinterfaceStack.getId());
+ for (Vserver auditVserver : vServersWithLInterface)
+ for (LInterface lInterface : auditVserver.getLInterfaces().getLInterface())
+
+ if (parentNeutronPortId.equals(lInterface.getInterfaceId())) {
+ logger.debug("Found Parent Port on VServer: {} on Port: {}", auditVserver.getVserverId(), lInterface.getInterfaceId());
+ Resource contrailVm = subinterfaceResources.getList().stream().filter(resource -> "OS::ContrailV2::VirtualMachineInterface".equals(resource.getType())).findAny()
+ .orElse(null);
+ if(contrailVm == null){
+ throw new Exception("Cannnot find Contrail Virtual Machine Interface on Stack: "+ subinterfaceStack.getId());
+ }
+ LInterface subInterface = new LInterface();
+ subInterface.setInterfaceId(contrailVm.getPhysicalResourceId());
+
+ if(lInterface.getLInterfaces() == null)
+ lInterface.setLInterfaces(new LInterfaces());
+
+ lInterface.getLInterfaces().getLInterface().add(subInterface);
+ }else
+ logger.debug("Did Not Find Parent Port on VServer: {} Parent Port: SubInterface: {}",auditVserver.getVserverId(),
+ lInterface.getInterfaceId(),subinterfaceStack.getId());
+ }
+
+ protected Set<Vserver> createVserverSet(Resources resources, List<Resource> novaResources) {
+ Set<Vserver> vserversToAudit = new HashSet<>();
+ for (Resource novaResource : novaResources) {
+ Vserver auditVserver = new Vserver();
+ auditVserver.setLInterfaces(new LInterfaces());
+ auditVserver.setVserverId(novaResource.getPhysicalResourceId());
+ Stream<Resource> filteredNeutronNetworks = resources.getList().stream()
+ .filter(network -> network.getRequiredBy().contains(novaResource.getLogicalResourceId()));
+ filteredNeutronNetworks.forEach(network -> {
+ LInterface lInterface = new LInterface();
+ lInterface.setInterfaceId(network.getPhysicalResourceId());
+ auditVserver.getLInterfaces().getLInterface().add(lInterface);
+ });
+ vserversToAudit.add(auditVserver);
+ }
+ return vserversToAudit;
+ }
+
+ protected Optional<String> extractResourcePathFromHref(String href) {
+ URI uri;
+ try {
+ uri = new URI(href);
+ return Optional.of(uri.getPath().replaceFirst("/v\\d+", "")+RESOURCES);
+ } catch (Exception e) {
+ logger.error("Error parsing URI", e);
+ }
+ return Optional.empty();
+ }
+
+ protected Optional<String> extractStackPathFromHref(String href) {
+ URI uri;
+ try {
+ uri = new URI(href);
+ return Optional.of(uri.getPath().replaceFirst("/v\\d+", ""));
+ } catch (Exception e) {
+ logger.error("Error parsing URI", e);
+ }
+ return Optional.empty();
+ }
+
+
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/AaiClientPropertiesImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/AaiClientPropertiesImpl.java
new file mode 100644
index 0000000000..c529413891
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/AaiClientPropertiesImpl.java
@@ -0,0 +1,69 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.openstack;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.onap.so.client.aai.AAIProperties;
+import org.onap.so.client.aai.AAIVersion;
+import org.onap.so.spring.SpringContextHelper;
+import org.springframework.context.ApplicationContext;
+
+public class AaiClientPropertiesImpl implements AAIProperties {
+
+ private String aaiEndpoint;
+ private String auth;
+ private String key;
+ private static final String SYSTEM_NAME = "MSO";
+
+ public AaiClientPropertiesImpl() {
+ ApplicationContext context = SpringContextHelper.getAppContext();
+ aaiEndpoint = context.getEnvironment().getProperty("aai.endpoint");
+ this.auth = context.getEnvironment().getProperty("aai.auth");
+ this.key = context.getEnvironment().getProperty("mso.msoKey");
+ }
+
+ @Override
+ public URL getEndpoint() throws MalformedURLException {
+ return new URL(aaiEndpoint);
+ }
+
+ @Override
+ public String getSystemName() {
+ return SYSTEM_NAME;
+ }
+
+ @Override
+ public AAIVersion getDefaultVersion() {
+ return AAIVersion.LATEST;
+ }
+
+ @Override
+ public String getAuth() {
+ return this.auth;
+ }
+
+ @Override
+ public String getKey() {
+ return this.key;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java
index a9aa50f654..9408f0d681 100644
--- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java
@@ -31,10 +31,12 @@ import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@SpringBootApplication(scanBasePackages = { "org.onap.so" })
@EnableAsync
+@EnableScheduling
@EnableJpaRepositories({ "org.onap.so.db.catalog.data.repository",
"org.onap.so.db.request.data.repository"})
@EntityScan({ "org.onap.so.db.catalog.beans", "org.onap.so.db.request.beans"})
diff --git a/adapters/mso-openstack-adapters/src/main/resources/META-INF/services/org.onap.so.client.RestProperties b/adapters/mso-openstack-adapters/src/main/resources/META-INF/services/org.onap.so.client.RestProperties
new file mode 100644
index 0000000000..4ce4d750a5
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/resources/META-INF/services/org.onap.so.client.RestProperties
@@ -0,0 +1 @@
+org.onap.so.adapters.openstack.AaiClientPropertiesImpl \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/main/resources/application.yaml b/adapters/mso-openstack-adapters/src/main/resources/application.yaml
index 8fd6d4279d..18084ced8d 100644
--- a/adapters/mso-openstack-adapters/src/main/resources/application.yaml
+++ b/adapters/mso-openstack-adapters/src/main/resources/application.yaml
@@ -13,7 +13,9 @@ mso:
core-pool-size: 50
max-pool-size: 50
queue-capacity: 500
-
+ workflow:
+ topics:
+ retryMultiplier: 60000
spring:
datasource:
jdbc-url: jdbc:mariadb://${DB_HOST}:${DB_PORT}/catalogdb
diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java
new file mode 100644
index 0000000000..52b67b8eb9
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java
@@ -0,0 +1,150 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017-2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import org.camunda.bpm.client.task.ExternalTask;
+import org.camunda.bpm.client.task.ExternalTaskService;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.so.audit.beans.AuditInventory;
+import org.springframework.core.env.Environment;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+public class AuditStackServiceDataTest extends AuditStackServiceData {
+
+ @InjectMocks
+ AuditStackServiceData auditStackService = new AuditStackServiceData();
+
+ @Mock
+ HeatStackAudit heatStackAuditMock;
+
+ @Mock
+ Environment mockEnv;
+
+ @Mock
+ ExternalTask mockExternalTask;
+
+ @Mock
+ ExternalTaskService mockExternalTaskService;
+
+ AuditInventory auditInventory = new AuditInventory();
+
+ @Before
+ public void setup() {
+ auditInventory.setCloudOwner("cloudOwner");
+ auditInventory.setCloudRegion("cloudRegion");
+ auditInventory.setTenantId("tenantId");
+ auditInventory.setHeatStackName("stackName");
+ MockitoAnnotations.initMocks(this);
+ doReturn(auditInventory).when(mockExternalTask).getVariable("auditInventory");
+ doReturn("6000").when(mockEnv).getProperty("mso.workflow.topics.retryMultiplier","6000");
+ doReturn("aasdfasdf").when(mockExternalTask).getId();
+ }
+
+ @Test
+ public void execute_external_task_audit_success_Test() {
+ doReturn(true).when(heatStackAuditMock).auditHeatStack("cloudRegion", "cloudOwner", "tenantId", "stackName");
+ auditStackService.executeExternalTask(mockExternalTask, mockExternalTaskService);
+ Mockito.verify(mockExternalTaskService).complete(mockExternalTask);
+ }
+
+ @Test
+ public void execute_external_task_audit_first_failure_Test() {
+ doReturn(false).when(heatStackAuditMock).auditHeatStack("cloudRegion", "cloudOwner", "tenantId", "stackName");
+ doReturn(null).when(mockExternalTask).getRetries();
+ auditStackService.executeExternalTask(mockExternalTask, mockExternalTaskService);
+ Mockito.verify(mockExternalTaskService).handleFailure(mockExternalTask,
+ "Unable to find all VServers and L-Interaces in A&AI",
+ "Unable to find all VServers and L-Interaces in A&AI", 8, 10000L);
+ }
+
+ @Test
+ public void execute_external_task_audit_intermediate_failure_Test() {
+ doReturn(false).when(heatStackAuditMock).auditHeatStack("cloudRegion", "cloudOwner", "tenantId", "stackName");
+ doReturn(6).when(mockExternalTask).getRetries();
+ auditStackService.executeExternalTask(mockExternalTask, mockExternalTaskService);
+ Mockito.verify(mockExternalTaskService).handleFailure(mockExternalTask,
+ "Unable to find all VServers and L-Interaces in A&AI",
+ "Unable to find all VServers and L-Interaces in A&AI", 5, 12000L);
+
+ }
+
+ @Test
+ public void execute_external_task_audit_final_failure_Test() {
+ doReturn(false).when(heatStackAuditMock).auditHeatStack("cloudRegion", "cloudOwner", "tenantId", "stackName");
+ doReturn(1).when(mockExternalTask).getRetries();
+ auditStackService.executeExternalTask(mockExternalTask, mockExternalTaskService);
+ Mockito.verify(mockExternalTaskService).handleBpmnError(mockExternalTask,
+ "AuditAAIInventoryFailure", "Number of Retries Exceeded auditing inventory");
+ }
+
+ @Test
+ public void retry_sequence_calculation_Test() {
+ long firstRetry = auditStackService.calculateRetryDelay(8);
+ assertEquals(6000L, firstRetry);
+ long secondRetry = auditStackService.calculateRetryDelay(7);
+ assertEquals(6000L, secondRetry);
+ long thirdRetry = auditStackService.calculateRetryDelay(6);
+ assertEquals(12000L, thirdRetry);
+ long fourthRetry = auditStackService.calculateRetryDelay(5);
+ assertEquals(18000L, fourthRetry);
+ long fifthRetry = auditStackService.calculateRetryDelay(4);
+ assertEquals(30000L, fifthRetry);
+ long sixRetry = auditStackService.calculateRetryDelay(3);
+ assertEquals(48000L, sixRetry);
+ long seventhRetry = auditStackService.calculateRetryDelay(2);
+ assertEquals(78000L, seventhRetry);
+ long eigthRetry = auditStackService.calculateRetryDelay(1);
+ assertEquals(120000L, eigthRetry);
+ }
+
+ @Test
+ public void retry_sequence_Test() {
+ long firstRetry = auditStackService.calculateRetryDelay(8);
+ assertEquals(6000L, firstRetry);
+ long secondRetry = auditStackService.calculateRetryDelay(7);
+ assertEquals(6000L, secondRetry);
+ long thirdRetry = auditStackService.calculateRetryDelay(6);
+ assertEquals(12000L, thirdRetry);
+ long fourthRetry = auditStackService.calculateRetryDelay(5);
+ assertEquals(18000L, fourthRetry);
+ long fifthRetry = auditStackService.calculateRetryDelay(4);
+ assertEquals(30000L, fifthRetry);
+ long sixRetry = auditStackService.calculateRetryDelay(3);
+ assertEquals(48000L, sixRetry);
+ long seventhRetry = auditStackService.calculateRetryDelay(2);
+ assertEquals(78000L, seventhRetry);
+ long eigthRetry = auditStackService.calculateRetryDelay(1);
+ assertEquals(120000L, eigthRetry);
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditVServerTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditVServerTest.java
new file mode 100644
index 0000000000..11e54404f4
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditVServerTest.java
@@ -0,0 +1,332 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017-2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.aai.domain.yang.LInterfaces;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.client.aai.AAIObjectPlurals;
+import org.onap.so.client.aai.AAIObjectType;
+import org.onap.so.client.aai.AAIResourcesClient;
+import org.onap.so.client.aai.entities.AAIResultWrapper;
+import org.onap.so.client.aai.entities.uri.AAIResourceUri;
+import org.onap.so.client.aai.entities.uri.AAIUriFactory;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.woorea.openstack.heat.model.Resource;
+import com.woorea.openstack.heat.model.Resources;
+
+@RunWith(MockitoJUnitRunner.Silent.class)
+public class AuditVServerTest extends AuditVServer {
+
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ @InjectMocks
+ private AuditVServer auditNova = new AuditVServer();
+
+ @Mock
+ private AAIResourcesClient aaiResourcesMock;
+
+ private String cloudOwner = "cloudOwner";
+ private String cloudRegion = "cloudRegion";
+ private String tenantId = "tenantId";
+
+ private AAIResourceUri vserverURI = AAIUriFactory.createResourceUri(AAIObjectType.VSERVER,cloudOwner, cloudRegion,
+ tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db");
+
+ private AAIResourceUri vserverURI2 = AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegion,
+ tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4dz");
+
+ private AAIResourceUri ssc_1_trusted_port_0_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db").queryParam("interface-id", "dec8bdc7-5718-41dc-bfbb-561ff6eeb81c");
+
+ private AAIResourceUri ssc_1_avpn_port_0_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db").queryParam("interface-id", "1c56a24b-5f03-435a-850d-31cd4252de56");
+
+ private AAIResourceUri ssc_1_mgmt_port_1_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db").queryParam("interface-id", "12afcd28-929f-4d80-8a5a-0833bfd5e20b");
+
+ private AAIResourceUri ssc_1_mgmt_port_0_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db").queryParam("interface-id", "80baec42-ffae-425f-ad8c-3f7b2c24bfff");
+
+ private AAIResourceUri ssc_1_mis_port_0_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db").queryParam("interface-id", "13eddf95-4cf3-45f2-823a-2d890a6549b4");
+
+ private AAIResourceUri ssc_1_int_ha_port_0_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db").queryParam("interface-id", "9cab2903-70f7-44fd-b681-491d6ae2adb8");
+
+ private AAIResourceUri test_port_1_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4dz").queryParam("interface-id", "9cab2903-70f7-44fd-b681-491d6ae2adz1");
+
+
+ private AAIResourceUri test_port_2_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4dz").queryParam("interface-id", "9cab2903-70f7-44fd-b681-491d6ae2adz2");
+
+
+
+ private AAIResourceUri mis_sub_1_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.SUB_L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db","interface-name").queryParam("interface-id", "f711be16-2654-4a09-b89d-0511fda20e81");
+
+ private AAIResourceUri avpn_sub_0_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.SUB_L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db","interface-name").queryParam("interface-id", "0d9cd813-2ae1-46c0-9ebb-48081f6cffbb");
+
+ private AAIResourceUri avpn_sub_1_uri = AAIUriFactory.createResourceUri(AAIObjectPlurals.SUB_L_INTERFACE,
+ cloudOwner, cloudRegion, tenantId, "3a4c2ca5-27b3-4ecc-98c5-06804867c4db","interface-name").queryParam("interface-id", "b7019dd0-2ee9-4447-bdef-ac25676b205a");
+
+
+
+ private Set<Vserver> vserversToAudit = new HashSet<>();
+
+
+ LInterface test_port_1 = new LInterface();
+ LInterface test_port_2 = new LInterface();
+ LInterface ssc_1_int_ha_port_0 = new LInterface();
+ LInterface mis_sub_interface_1 = new LInterface();
+ LInterface ssc_1_mis_port_0 = new LInterface();
+ LInterface ssc_1_mgmt_port_0 = new LInterface();
+ LInterface ssc_1_mgmt_port_1 = new LInterface();
+ LInterface avpn_sub_interface_2 = new LInterface();
+ LInterface avpn_sub_interface_1 = new LInterface();
+ LInterface ssc_1_avpn_port_0 = new LInterface();
+ LInterface ssc_1_trusted_port_0 = new LInterface();
+
+ LInterfaces test_port_1_plural = new LInterfaces();
+ LInterfaces test_port_2_plural = new LInterfaces();
+ LInterfaces ssc_1_int_ha_port_0_plural = new LInterfaces();
+ LInterfaces mis_sub_interface_1_plural = new LInterfaces();
+ LInterfaces ssc_1_mis_port_0_plural = new LInterfaces();
+ LInterfaces ssc_1_mgmt_port_0_plural = new LInterfaces();
+ LInterfaces ssc_1_mgmt_port_1_plural = new LInterfaces();
+ LInterfaces avpn_sub_interface_2_plural = new LInterfaces();
+ LInterfaces avpn_sub_interface_1_plural = new LInterfaces();
+ LInterfaces ssc_1_avpn_port_0_plural = new LInterfaces();
+ LInterfaces ssc_1_trusted_port_0_plural = new LInterfaces();
+
+
+ @Before
+ public void setup() {
+ auditNova.setAaiClient(aaiResourcesMock);
+
+ Vserver vServer1= new Vserver();
+ vServer1.setVserverId("3a4c2ca5-27b3-4ecc-98c5-06804867c4db");
+ LInterfaces vServer1Linterfaces = new LInterfaces();
+ vServer1.setLInterfaces(vServer1Linterfaces);
+
+ ssc_1_trusted_port_0.setInterfaceId("dec8bdc7-5718-41dc-bfbb-561ff6eeb81c");
+ ssc_1_trusted_port_0.setInterfaceName("interface-name");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_trusted_port_0);
+
+
+ ssc_1_avpn_port_0.setInterfaceId("1c56a24b-5f03-435a-850d-31cd4252de56");
+ ssc_1_avpn_port_0.setInterfaceName("interface-name");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_avpn_port_0);
+ ssc_1_avpn_port_0.setLInterfaces(new LInterfaces());
+
+
+ avpn_sub_interface_1.setInterfaceId("0d9cd813-2ae1-46c0-9ebb-48081f6cffbb");
+ ssc_1_avpn_port_0.getLInterfaces().getLInterface().add(avpn_sub_interface_1);
+
+
+ avpn_sub_interface_2.setInterfaceId("b7019dd0-2ee9-4447-bdef-ac25676b205a");
+ ssc_1_avpn_port_0.getLInterfaces().getLInterface().add(avpn_sub_interface_2);
+
+
+ ssc_1_mgmt_port_1.setInterfaceId("12afcd28-929f-4d80-8a5a-0833bfd5e20b");
+ ssc_1_mgmt_port_1.setInterfaceName("interface-name");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mgmt_port_1);
+
+ ssc_1_mgmt_port_0.setInterfaceId("80baec42-ffae-425f-ad8c-3f7b2c24bfff");
+ ssc_1_mgmt_port_0.setInterfaceName("interface-name");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mgmt_port_0);
+
+
+ ssc_1_mis_port_0.setLInterfaces(new LInterfaces());
+ ssc_1_mis_port_0.setInterfaceId("13eddf95-4cf3-45f2-823a-2d890a6549b4");
+ ssc_1_mis_port_0.setInterfaceName("interface-name");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mis_port_0);
+
+
+ mis_sub_interface_1.setInterfaceId("f711be16-2654-4a09-b89d-0511fda20e81");
+ ssc_1_mis_port_0.getLInterfaces().getLInterface().add(mis_sub_interface_1);
+
+
+ ssc_1_int_ha_port_0.setInterfaceId("9cab2903-70f7-44fd-b681-491d6ae2adb8");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_int_ha_port_0);
+
+
+ Vserver vServer2= new Vserver();
+ vServer2.setVserverId("3a4c2ca5-27b3-4ecc-98c5-06804867c4dz");
+ LInterfaces vServer2Linterfaces = new LInterfaces();
+ vServer2.setLInterfaces(vServer2Linterfaces);
+
+ test_port_1.setInterfaceId("9cab2903-70f7-44fd-b681-491d6ae2adz1");
+ test_port_1.setInterfaceName("interface-name");
+
+
+ test_port_2.setInterfaceId("9cab2903-70f7-44fd-b681-491d6ae2adz2");
+ test_port_2.setInterfaceName("interface-name");
+
+ vServer2.getLInterfaces().getLInterface().add(test_port_1);
+ vServer2.getLInterfaces().getLInterface().add(test_port_2);
+
+ vserversToAudit.add(vServer1);
+ vserversToAudit.add(vServer2);
+
+
+ test_port_1_plural.getLInterface().add(test_port_1);
+ test_port_2_plural.getLInterface().add(test_port_2);
+ ssc_1_int_ha_port_0_plural.getLInterface().add(ssc_1_int_ha_port_0);
+ ssc_1_mis_port_0_plural.getLInterface().add(ssc_1_mis_port_0);
+ ssc_1_mgmt_port_0_plural.getLInterface().add(ssc_1_mgmt_port_0);
+ ssc_1_mgmt_port_1_plural.getLInterface().add(ssc_1_mgmt_port_1);
+ ssc_1_avpn_port_0_plural.getLInterface().add(ssc_1_avpn_port_0);
+ ssc_1_trusted_port_0_plural.getLInterface().add(ssc_1_trusted_port_0);
+
+ }
+
+ @Test
+ public void audit_Vserver_Empty_HashSet() throws JsonParseException, JsonMappingException, IOException {
+ boolean exists = auditNova.auditVservers(new HashSet<Vserver>(), tenantId, cloudOwner, cloudRegion);
+ assertEquals(false, exists);
+ }
+
+ @Test
+ public void audit_Vserver_Found_Test() throws JsonParseException, JsonMappingException, IOException {
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI);
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI2);
+ doReturn(Optional.of(ssc_1_trusted_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_trusted_port_0_uri);
+ doReturn(Optional.of(ssc_1_avpn_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_avpn_port_0_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_1_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_mgmt_port_1_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_mgmt_port_0_uri);
+ doReturn(Optional.of(ssc_1_mis_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_mis_port_0_uri);
+ doReturn(Optional.of(ssc_1_int_ha_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_int_ha_port_0_uri);
+ doReturn(Optional.of(test_port_1_plural)).when(aaiResourcesMock).get(LInterfaces.class,test_port_1_uri);
+ doReturn(Optional.of(test_port_2_plural)).when(aaiResourcesMock).get(LInterfaces.class,test_port_2_uri);
+
+ doReturn(true).when(aaiResourcesMock).exists(mis_sub_1_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_0_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_1_uri);
+
+ boolean exists = auditNova.auditVservers(vserversToAudit, tenantId, cloudOwner, cloudRegion);
+ assertEquals(true, exists);
+ }
+
+ @Test
+ public void audit_Vserver_Found_Test_Network_Not_Found()
+ throws JsonParseException, JsonMappingException, IOException {
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI);
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI2);
+ doReturn(Optional.of(ssc_1_trusted_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_trusted_port_0_uri);
+ doReturn(Optional.of(ssc_1_avpn_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_avpn_port_0_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_1_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_mgmt_port_1_uri);
+ doReturn(Optional.empty()).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_mgmt_port_0_uri);
+ doReturn(Optional.of(ssc_1_mis_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_mis_port_0_uri);
+ doReturn(Optional.of(ssc_1_int_ha_port_0_plural)).when(aaiResourcesMock).get(LInterfaces.class,ssc_1_int_ha_port_0_uri);
+ doReturn(Optional.of(test_port_1_plural)).when(aaiResourcesMock).get(LInterfaces.class,test_port_1_uri);
+ doReturn(Optional.of(test_port_2_plural)).when(aaiResourcesMock).get(LInterfaces.class,test_port_2_uri);
+
+ doReturn(true).when(aaiResourcesMock).exists(mis_sub_1_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_0_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_1_uri);
+
+ boolean exists = auditNova.auditVservers(vserversToAudit, tenantId, cloudOwner, cloudRegion);
+ assertEquals(false, exists);
+ }
+
+ @Test
+ public void audit_Vserver_Found_Test_Network_Not_Found_Second_Server()
+ throws JsonParseException, JsonMappingException, IOException {
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI);
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI2);
+ doReturn(Optional.of(ssc_1_trusted_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_trusted_port_0_uri);
+ doReturn(Optional.of(ssc_1_avpn_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_avpn_port_0_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_1_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_mgmt_port_1_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_mgmt_port_0_uri);
+ doReturn(Optional.of(ssc_1_mis_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_mis_port_0_uri);
+ doReturn(Optional.of(ssc_1_int_ha_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_int_ha_port_0_uri);
+ doReturn(Optional.of(test_port_1_plural)).when(aaiResourcesMock).get(LInterface.class,test_port_1_uri);
+ doReturn(Optional.empty()).when(aaiResourcesMock).get(LInterface.class,test_port_2_uri);
+ doReturn(true).when(aaiResourcesMock).exists(mis_sub_1_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_0_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_1_uri);
+ boolean exists = auditNova.auditVservers(vserversToAudit, tenantId, cloudOwner, cloudRegion);
+ assertEquals(false, exists);
+ }
+
+ @Test
+ public void audit_Vserver_Not_Found_Test() throws JsonParseException, JsonMappingException, IOException {
+ doReturn(false).when(aaiResourcesMock).exists(vserverURI);
+ doReturn(false).when(aaiResourcesMock).exists(vserverURI2);
+ boolean exists = auditNova.auditVservers(vserversToAudit, tenantId, cloudOwner, cloudRegion);
+ assertEquals(false, exists);
+ }
+
+ @Test
+ public void audit_Vserver_first_Not_Found_Test() throws JsonParseException, JsonMappingException, IOException {
+ doReturn(false).when(aaiResourcesMock).exists(vserverURI);
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI2);
+ doReturn(Optional.of(test_port_1_plural)).when(aaiResourcesMock).get(LInterface.class,test_port_1_uri);
+ doReturn(Optional.of(test_port_2_plural)).when(aaiResourcesMock).get(LInterface.class,test_port_2_uri);
+ boolean exists = auditNova.auditVservers(vserversToAudit, tenantId, cloudOwner, cloudRegion);
+ assertEquals(false, exists);
+ }
+
+ @Test
+ public void audit_Vserver_Second_Not_Found_Test() throws JsonParseException, JsonMappingException, IOException {
+ doReturn(true).when(aaiResourcesMock).exists(vserverURI);
+ doReturn(Optional.of(ssc_1_trusted_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_trusted_port_0_uri);
+ doReturn(Optional.of(ssc_1_avpn_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_avpn_port_0_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_1_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_mgmt_port_1_uri);
+ doReturn(Optional.of(ssc_1_mgmt_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_mgmt_port_0_uri);
+ doReturn(Optional.of(ssc_1_mis_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_mis_port_0_uri);
+ doReturn(Optional.of(ssc_1_int_ha_port_0_plural)).when(aaiResourcesMock).get(LInterface.class,ssc_1_int_ha_port_0_uri);
+ doReturn(Optional.of(test_port_1_plural)).when(aaiResourcesMock).get(LInterface.class,test_port_1_uri);
+ doReturn(Optional.of(test_port_2_plural)).when(aaiResourcesMock).get(LInterface.class,test_port_2_uri);
+ doReturn(true).when(aaiResourcesMock).exists(mis_sub_1_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_0_uri);
+ doReturn(true).when(aaiResourcesMock).exists(avpn_sub_1_uri);
+ doReturn(false).when(aaiResourcesMock).exists(vserverURI2);
+ boolean exists = auditNova.auditVservers(vserversToAudit, tenantId, cloudOwner, cloudRegion);
+ assertEquals(false, exists);
+ }
+
+}
diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/HeatStackAuditTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/HeatStackAuditTest.java
new file mode 100644
index 0000000000..5df5d8200f
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/HeatStackAuditTest.java
@@ -0,0 +1,241 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017-2019 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.so.adapters.audit;
+
+import static com.shazam.shazamcrest.MatcherAssert.assertThat;
+import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.aai.domain.yang.LInterfaces;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.openstack.utils.MsoHeatUtils;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.woorea.openstack.heat.model.Resource;
+import com.woorea.openstack.heat.model.Resources;
+import com.woorea.openstack.heat.model.Stack;
+
+
+@RunWith(MockitoJUnitRunner.Silent.class)
+public class HeatStackAuditTest extends HeatStackAudit {
+
+ @InjectMocks
+ private HeatStackAudit heatStackAudit = new HeatStackAudit();
+
+ @Mock
+ private MsoHeatUtils msoHeatUtilsMock;
+
+ @Mock
+ private AuditVServer auditVserver;
+
+ private static final String cloudRegion = "cloudRegion";
+ private static final String tenantId = "tenantId";
+
+ private Resources resources = new Resources();
+
+ private ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ private ObjectMapper stackObjectMapper = new ObjectMapper().configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
+
+ @Before
+ public void setup() throws Exception{
+ resources= objectMapper.readValue(new File("src/test/resources/GetResources.json"), Resources.class);
+
+ }
+
+ @Test
+ public void extract_proper_path_Test(){
+ Optional<String> actualResult = extractStackPathFromHref("https://orchestration.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/test_stack/f711be16-2654-4a09-b89d-0511fda20e81");
+ assertEquals("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/test_stack/f711be16-2654-4a09-b89d-0511fda20e81", actualResult.get());
+ }
+
+ @Test
+ public void extract_proper_resources_path_Test(){
+ Optional<String> actualResult = extractResourcePathFromHref("https://orchestration.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/test_stack/f711be16-2654-4a09-b89d-0511fda20e81");
+ assertEquals("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/test_stack/f711be16-2654-4a09-b89d-0511fda20e81/resources", actualResult.get());
+ }
+
+ @Test
+ public void extract_invalid_uri_Test(){
+ Optional<String> actualResult = extractStackPathFromHref("orchestrn.com:8004/v18b44d60a6f94bdcb2738f9e/stacks/test_stack/f711be16-2654-4a09-b89d-0511fda20e81");
+ assertEquals(false, actualResult.isPresent());
+ }
+
+ @Test
+ public void createVserverSet_Test() throws Exception{
+ List<Resource> novaResources = resources.getList().stream()
+ .filter(p -> "OS::Nova::Server".equals(p.getType())).collect(Collectors.toList());
+
+ List<Resource> resourceGroups = resources.getList().stream()
+ .filter(p -> "OS::Heat::ResourceGroup".equals(p.getType())).collect(Collectors.toList());
+
+ Set<Vserver> expectedVservers = new HashSet<>();
+ Vserver vServer1= new Vserver();
+ vServer1.setVserverId("92272b67-d23f-42ca-87fa-7b06a9ec81f3");
+ LInterfaces vServer1Linterfaces = new LInterfaces();
+ vServer1.setLInterfaces(vServer1Linterfaces);
+
+ LInterface ssc_1_trusted_port_0 = new LInterface();
+ ssc_1_trusted_port_0.setInterfaceId("d2f51f82-0ec2-4581-bd1a-d2a82073e52b");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_trusted_port_0);
+
+
+
+ LInterface ssc_1_mgmt_port_1 = new LInterface();
+ ssc_1_mgmt_port_1.setInterfaceId("07f5b14c-147a-4d14-8c94-a9e94dbc097b");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mgmt_port_1);
+
+ LInterface ssc_1_mgmt_port_0 = new LInterface();
+ ssc_1_mgmt_port_0.setInterfaceId("8d93f63e-e972-48c7-ad98-b2122da47315");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mgmt_port_0);
+
+ LInterface ssc_1_mis_port_0 = new LInterface();
+ ssc_1_mis_port_0.setLInterfaces(new LInterfaces());
+ ssc_1_mis_port_0.setInterfaceId("0594a2f2-7ea4-42eb-abc2-48ea49677fca");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mis_port_0);
+
+ LInterface mis_sub_interface_1 = new LInterface();
+ mis_sub_interface_1.setInterfaceId("2bbfa345-33bb-495a-94b2-fb514ee1cffc");
+ ssc_1_mis_port_0.getLInterfaces().getLInterface().add(mis_sub_interface_1);
+
+ LInterface ssc_1_int_ha_port_0 = new LInterface();
+ ssc_1_int_ha_port_0.setInterfaceId("00bb8407-650e-48b5-b919-33b88d6f8fe3");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_int_ha_port_0);
+
+
+ LInterface ssc_1_avpn_port_0 = new LInterface();
+ ssc_1_avpn_port_0.setInterfaceId("27391d94-33af-474a-927d-d409249e8fd3");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_avpn_port_0);
+ ssc_1_avpn_port_0.setLInterfaces(new LInterfaces());
+
+ LInterface avpn_sub_interface_0 = new LInterface();
+ avpn_sub_interface_0.setInterfaceId("d54dfd09-75c6-4e04-b204-909455b8f933");
+ ssc_1_avpn_port_0.getLInterfaces().getLInterface().add(avpn_sub_interface_0);
+
+ LInterface avpn_sub_interface_1 = new LInterface();
+ avpn_sub_interface_1.setInterfaceId("f7a998c0-8939-4b07-bf4a-0862e9c325e1");
+ ssc_1_avpn_port_0.getLInterfaces().getLInterface().add(avpn_sub_interface_1);
+
+ LInterface avpn_sub_interface_2 = new LInterface();
+ avpn_sub_interface_2.setInterfaceId("621c1fea-60b8-44ee-aede-c01b8b1aaa70");
+ ssc_1_avpn_port_0.getLInterfaces().getLInterface().add(avpn_sub_interface_2);
+
+
+ expectedVservers.add(vServer1);
+
+ Resources avpnQueryResponse = objectMapper.readValue(new File("src/test/resources/AVPNResourceGroupResponse.json"), Resources.class);
+ doReturn(avpnQueryResponse).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672/resources", cloudRegion, tenantId, Resources.class);
+
+ Resources misQueryResponse =objectMapper.readValue(new File("src/test/resources/MISResourceGroupResponse.json"), Resources.class);
+ doReturn(misQueryResponse).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst/447a9b41-714e-434b-b1d0-6cce8d9f0f0c/resources", cloudRegion, tenantId, Resources.class);
+
+
+ Stack misStackQuerySubInt = stackObjectMapper.readValue(new File("src/test/resources/MISSubInterface0.json"), Stack.class);
+ doReturn(misStackQuerySubInt).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81", cloudRegion,tenantId, Stack.class);
+ Resources misResourceQuerySubInt = objectMapper.readValue(new File("src/test/resources/MISSubInterface1Resources.json"), Resources.class);
+ doReturn(misResourceQuerySubInt).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources", cloudRegion,tenantId, Resources.class);
+
+ Stack avpnStackQuerySubInt1 =stackObjectMapper.readValue(new File("src/test/resources/AVPNSubInterface0.json"), Stack.class);
+ doReturn(avpnStackQuerySubInt1).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-1-fmn5laetg5cs/0d9cd813-2ae1-46c0-9ebb-48081f6cffbb", cloudRegion,tenantId, Stack.class);
+ Resources avpnResourceQuerySubInt1 = objectMapper.readValue(new File("src/test/resources/AVPNSubInterface0Resources.json"), Resources.class);
+ doReturn(avpnResourceQuerySubInt1).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-1-fmn5laetg5cs/0d9cd813-2ae1-46c0-9ebb-48081f6cffbb/resources", cloudRegion,tenantId, Resources.class);
+
+
+ Stack avpnStackQuerySubInt2 =stackObjectMapper.readValue(new File("src/test/resources/AVPNSubInterface1.json"), Stack.class);
+ doReturn(avpnStackQuerySubInt2).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m/b7019dd0-2ee9-4447-bdef-ac25676b205a", cloudRegion,tenantId, Stack.class);
+ Resources avpnResourceQuerySubInt2 = objectMapper.readValue(new File("src/test/resources/AVPNSubInterface1Resources.json"), Resources.class);
+ doReturn(avpnResourceQuerySubInt2).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m/b7019dd0-2ee9-4447-bdef-ac25676b205a/resources", cloudRegion,tenantId, Resources.class);
+
+ Stack avpnStackQuerySubInt3 =stackObjectMapper.readValue(new File("src/test/resources/AVPNSubInterface2.json"), Stack.class);
+ doReturn(avpnStackQuerySubInt3).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv/bd0fc728-cbde-4301-a581-db56f494675c", cloudRegion,tenantId, Stack.class);
+ Resources avpnResourceQuerySubInt3 = objectMapper.readValue(new File("src/test/resources/AVPNSubInterface2Resources.json"), Resources.class);
+ doReturn(avpnResourceQuerySubInt3).when(msoHeatUtilsMock).executeHeatClientRequest("/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv/bd0fc728-cbde-4301-a581-db56f494675c/resources", cloudRegion,tenantId, Resources.class);
+
+ Set<Vserver> vServersToAudit = heatStackAudit.createVserverSet(resources, novaResources);
+ Set<Vserver> vserversWithSubInterfaces = heatStackAudit.processSubInterfaces(cloudRegion,tenantId,resourceGroups, vServersToAudit);
+
+ String actualValue = objectMapper.writeValueAsString(vserversWithSubInterfaces);
+ String expectedValue = objectMapper.writeValueAsString(expectedVservers);
+
+ JSONAssert.assertEquals(expectedValue, actualValue, false);
+ }
+
+
+ @Test
+ public void findInterfaceInformation_Test(){
+ List<Resource> novaResources = resources.getList().stream()
+ .filter(p -> "OS::Nova::Server".equals(p.getType())).collect(Collectors.toList());
+ Set<Vserver> expectedVservers = new HashSet<>();
+ Vserver vServer1= new Vserver();
+ vServer1.setVserverId("92272b67-d23f-42ca-87fa-7b06a9ec81f3");
+ LInterfaces vServer1Linterfaces = new LInterfaces();
+ vServer1.setLInterfaces(vServer1Linterfaces);
+
+ LInterface ssc_1_trusted_port_0 = new LInterface();
+ ssc_1_trusted_port_0.setInterfaceId("d2f51f82-0ec2-4581-bd1a-d2a82073e52b");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_trusted_port_0);
+
+ LInterface ssc_1_avpn_port_0 = new LInterface();
+ ssc_1_avpn_port_0.setInterfaceId("27391d94-33af-474a-927d-d409249e8fd3");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_avpn_port_0);
+
+ LInterface ssc_1_mgmt_port_1 = new LInterface();
+ ssc_1_mgmt_port_1.setInterfaceId("07f5b14c-147a-4d14-8c94-a9e94dbc097b");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mgmt_port_1);
+
+ LInterface ssc_1_mgmt_port_0 = new LInterface();
+ ssc_1_mgmt_port_0.setInterfaceId("8d93f63e-e972-48c7-ad98-b2122da47315");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mgmt_port_0);
+
+ LInterface ssc_1_mis_port_0 = new LInterface();
+ ssc_1_mis_port_0.setInterfaceId("0594a2f2-7ea4-42eb-abc2-48ea49677fca");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_mis_port_0);
+
+ LInterface ssc_1_int_ha_port_0 = new LInterface();
+ ssc_1_int_ha_port_0.setInterfaceId("00bb8407-650e-48b5-b919-33b88d6f8fe3");
+ vServer1.getLInterfaces().getLInterface().add(ssc_1_int_ha_port_0);
+
+ expectedVservers.add(vServer1);
+
+ Set<Vserver> actualVservers = heatStackAudit.createVserverSet(resources, novaResources);
+
+ assertThat(actualVservers, sameBeanAs(expectedVservers));
+ }
+
+
+}
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNResourceGroupResponse.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNResourceGroupResponse.json
new file mode 100644
index 0000000000..27f971b698
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNResourceGroupResponse.json
@@ -0,0 +1,79 @@
+{
+ "resources": [
+ {
+ "parent_resource": "ssc_1_subint_avpn_port_0_subinterfaces",
+ "resource_name": "1",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672/resources/1",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672",
+ "rel": "stack"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-1-fmn5laetg5cs/0d9cd813-2ae1-46c0-9ebb-48081f6cffbb",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "1",
+ "resource_status_reason": "state changed",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "0d9cd813-2ae1-46c0-9ebb-48081f6cffbb",
+ "resource_type": "vlan_subinterface_ssc_avpn.yaml"
+ },
+ {
+ "parent_resource": "ssc_1_subint_avpn_port_0_subinterfaces",
+ "resource_name": "0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672/resources/0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672",
+ "rel": "stack"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m/b7019dd0-2ee9-4447-bdef-ac25676b205a",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "0",
+ "resource_status_reason": "state changed",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "b7019dd0-2ee9-4447-bdef-ac25676b205a",
+ "resource_type": "vlan_subinterface_ssc_avpn.yaml"
+ },
+ {
+ "parent_resource": "ssc_1_subint_avpn_port_0_subinterfaces",
+ "resource_name": "2",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672/resources/2",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672",
+ "rel": "stack"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv/bd0fc728-cbde-4301-a581-db56f494675c",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "2",
+ "resource_status_reason": "state changed",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "bd0fc728-cbde-4301-a581-db56f494675c",
+ "resource_type": "vlan_subinterface_ssc_avpn.yaml"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0.json
new file mode 100644
index 0000000000..e0a2404eaf
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0.json
@@ -0,0 +1,41 @@
+{
+ "stack": {
+ "parent": "31d0647a-6043-49a4-81b6-ccab29380672",
+ "disable_rollback": true,
+ "description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-1-fmn5laetg5cs/0d9cd813-2ae1-46c0-9ebb-48081f6cffbb",
+ "rel": "self"
+ }
+ ],
+ "stack_status_reason": "Stack CREATE completed successfully",
+ "stack_name": "tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m",
+ "stack_user_project_id": "dfffe8b2401b45368ca6e21f19796ce1",
+ "stack_owner": "m08699",
+ "creation_time": "2019-01-23T19:34:57Z",
+ "capabilities": [],
+ "notification_topics": [],
+ "updated_time": null,
+ "timeout_mins": 120,
+ "stack_status": "CREATE_COMPLETE",
+ "parameters": {
+ "OS::project_id": "ea2d13cc98b44d60a6f94bdcb2738f9e",
+ "port_interface": "27391d94-33af-474a-927d-d409249e8fd3",
+ "OS::stack_id": "b7019dd0-2ee9-4447-bdef-ac25676b205a",
+ "OS::stack_name": "tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m",
+ "vip_v6_address": "2001:1890:e005:1403::",
+ "network_id": "1bc1c5fe-896f-4629-b499-a5a36ece4253,c2f4ad4a-0089-41fa-aba7-a80963def29b,70bc637c-ea0f-4452-8aca-01e90c842ff1",
+ "subinterface_name_prefix": "tsbc0005v_tsbc0005vm002_subint_untrusted_avpn",
+ "counter": "0",
+ "mac_address": "02:27:39:1d:94:33",
+ "vip_address": "12.251.1.8",
+ "vlan_tag": "101,102,103",
+ "ip_address": "12.251.1.5",
+ "ip_v6_address": "2001:1890:e005:1402:8000::"
+ },
+ "id": "0d9cd813-2ae1-46c0-9ebb-48081f6cffbb",
+ "outputs": [],
+ "template_description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n"
+ }
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0Resources.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0Resources.json
new file mode 100644
index 0000000000..e0631db0b5
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0Resources.json
@@ -0,0 +1,72 @@
+
+
+{
+ "resources": [
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [
+ "ssc_subint_mis_vmi_0_v6_ip_0",
+ "ssc_subint_mis_vmi_0_ip_0"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "d54dfd09-75c6-4e04-b204-909455b8f933",
+ "resource_type": "OS::ContrailV2::VirtualMachineInterface"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_v6_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "e7f25707-12fd-454f-95ac-6a05cd70806f",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "6d23f4d3-8f7b-42c5-bb9e-4aee5797d506",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1.json
new file mode 100644
index 0000000000..009533b476
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1.json
@@ -0,0 +1,43 @@
+
+
+{
+ "stack": {
+ "parent": "31d0647a-6043-49a4-81b6-ccab29380672",
+ "disable_rollback": true,
+ "description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m/b7019dd0-2ee9-4447-bdef-ac25676b205a",
+ "rel": "self"
+ }
+ ],
+ "stack_status_reason": "Stack CREATE completed successfully",
+ "stack_name": "tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m",
+ "stack_user_project_id": "dfffe8b2401b45368ca6e21f19796ce1",
+ "stack_owner": "m08699",
+ "creation_time": "2019-01-23T19:34:57Z",
+ "capabilities": [],
+ "notification_topics": [],
+ "updated_time": null,
+ "timeout_mins": 120,
+ "stack_status": "CREATE_COMPLETE",
+ "parameters": {
+ "OS::project_id": "ea2d13cc98b44d60a6f94bdcb2738f9e",
+ "port_interface": "27391d94-33af-474a-927d-d409249e8fd3",
+ "OS::stack_id": "b7019dd0-2ee9-4447-bdef-ac25676b205a",
+ "OS::stack_name": "tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-0-yghihziaf36m",
+ "vip_v6_address": "2001:1890:e005:1403::",
+ "network_id": "1bc1c5fe-896f-4629-b499-a5a36ece4253,c2f4ad4a-0089-41fa-aba7-a80963def29b,70bc637c-ea0f-4452-8aca-01e90c842ff1",
+ "subinterface_name_prefix": "tsbc0005v_tsbc0005vm002_subint_untrusted_avpn",
+ "counter": "0",
+ "mac_address": "02:27:39:1d:94:33",
+ "vip_address": "12.251.1.8",
+ "vlan_tag": "101,102,103",
+ "ip_address": "12.251.1.5",
+ "ip_v6_address": "2001:1890:e005:1402:8000::"
+ },
+ "id": "b7019dd0-2ee9-4447-bdef-ac25676b205a",
+ "outputs": [],
+ "template_description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n"
+ }
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1Resources.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1Resources.json
new file mode 100644
index 0000000000..1b10f16d6d
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1Resources.json
@@ -0,0 +1,72 @@
+
+
+{
+ "resources": [
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [
+ "ssc_subint_mis_vmi_0_v6_ip_0",
+ "ssc_subint_mis_vmi_0_ip_0"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "f7a998c0-8939-4b07-bf4a-0862e9c325e1",
+ "resource_type": "OS::ContrailV2::VirtualMachineInterface"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_v6_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "e7f25707-12fd-454f-95ac-6a05cd70806f",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "6d23f4d3-8f7b-42c5-bb9e-4aee5797d506",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2.json
new file mode 100644
index 0000000000..7488ee2045
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2.json
@@ -0,0 +1,41 @@
+{
+ "stack": {
+ "parent": "31d0647a-6043-49a4-81b6-ccab29380672",
+ "disable_rollback": true,
+ "description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbtsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv/bd0fc728-cbde-4301-a581-db56f494675cc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv/bd0fc728-cbde-4301-a581-db56f494675c",
+ "rel": "self"
+ }
+ ],
+ "stack_status_reason": "Stack CREATE completed successfully",
+ "stack_name": "tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv",
+ "stack_user_project_id": "dfffe8b2401b45368ca6e21f19796ce1",
+ "stack_owner": "m08699",
+ "creation_time": "2019-01-23T19:34:57Z",
+ "capabilities": [],
+ "notification_topics": [],
+ "updated_time": null,
+ "timeout_mins": 120,
+ "stack_status": "CREATE_COMPLETE",
+ "parameters": {
+ "OS::project_id": "ea2d13cc98b44d60a6f94bdcb2738f9e",
+ "port_interface": "27391d94-33af-474a-927d-d409249e8fd3",
+ "OS::stack_id": "bd0fc728-cbde-4301-a581-db56f494675c",
+ "OS::stack_name": "tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz-2-y3ndsavmsymv",
+ "vip_v6_address": "2001:1890:e005:1403::",
+ "network_id": "1bc1c5fe-896f-4629-b499-a5a36ece4253,c2f4ad4a-0089-41fa-aba7-a80963def29b,70bc637c-ea0f-4452-8aca-01e90c842ff1",
+ "subinterface_name_prefix": "tsbc0005v_tsbc0005vm002_subint_untrusted_avpn",
+ "counter": "2",
+ "mac_address": "02:27:39:1d:94:33",
+ "vip_address": "12.251.1.8",
+ "vlan_tag": "101,102,103",
+ "ip_address": "12.251.1.5",
+ "ip_v6_address": "2001:1890:e005:1402:8000::"
+ },
+ "id": "bd0fc728-cbde-4301-a581-db56f494675c",
+ "outputs": [],
+ "template_description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n"
+ }
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2Resources.json b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2Resources.json
new file mode 100644
index 0000000000..94c7c69de4
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2Resources.json
@@ -0,0 +1,72 @@
+
+
+{
+ "resources": [
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [
+ "ssc_subint_mis_vmi_0_v6_ip_0",
+ "ssc_subint_mis_vmi_0_ip_0"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "621c1fea-60b8-44ee-aede-c01b8b1aaa70",
+ "resource_type": "OS::ContrailV2::VirtualMachineInterface"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_v6_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "e7f25707-12fd-454f-95ac-6a05cd70806f",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "6d23f4d3-8f7b-42c5-bb9e-4aee5797d506",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/GetResources.json b/adapters/mso-openstack-adapters/src/test/resources/GetResources.json
new file mode 100644
index 0000000000..33e282caa7
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/GetResources.json
@@ -0,0 +1,206 @@
+{
+ "resources": [
+ {
+ "resource_name": "ssc_1_trusted_port_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_trusted_port_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_1_trusted_port_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [
+ "ssc_server_1"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "d2f51f82-0ec2-4581-bd1a-d2a82073e52b",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "ssc_1_avpn_port_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_avpn_port_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_1_avpn_port_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [
+ "ssc_1_subint_avpn_port_0_subinterfaces",
+ "ssc_server_1"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "27391d94-33af-474a-927d-d409249e8fd3",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "ssc_1_subint_mis_port_0_subinterfaces",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_subint_mis_port_0_subinterfaces",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst/447a9b41-714e-434b-b1d0-6cce8d9f0f0c",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "ssc_1_subint_mis_port_0_subinterfaces",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "447a9b41-714e-434b-b1d0-6cce8d9f0f0c",
+ "resource_type": "OS::Heat::ResourceGroup"
+ },
+ {
+ "resource_name": "ssc_1_mgmt_port_1",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_mgmt_port_1",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_1_mgmt_port_1",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [
+ "ssc_server_1"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "07f5b14c-147a-4d14-8c94-a9e94dbc097b",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "ssc_1_mgmt_port_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_mgmt_port_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_1_mgmt_port_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [
+ "ssc_server_1"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "8d93f63e-e972-48c7-ad98-b2122da47315",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "ssc_1_mis_port_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_mis_port_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_1_mis_port_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [
+ "ssc_1_subint_mis_port_0_subinterfaces",
+ "ssc_server_1"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "0594a2f2-7ea4-42eb-abc2-48ea49677fca",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "ssc_1_int_ha_port_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_int_ha_port_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_1_int_ha_port_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [
+ "ssc_server_1"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "00bb8407-650e-48b5-b919-33b88d6f8fe3",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "ssc_server_1",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_server_1",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_server_1",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "92272b67-d23f-42ca-87fa-7b06a9ec81f3",
+ "resource_type": "OS::Nova::Server"
+ },
+ {
+ "resource_name": "ssc_1_subint_avpn_port_0_subinterfaces",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34/resources/ssc_1_subint_avpn_port_0_subinterfaces",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001/75e046b1-cf7d-4590-91e7-a6079f83fd34",
+ "rel": "stack"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_avpn_port_0_subinterfaces-dtmxjmny7yjz/31d0647a-6043-49a4-81b6-ccab29380672",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "ssc_1_subint_avpn_port_0_subinterfaces",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:15Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "31d0647a-6043-49a4-81b6-ccab29380672",
+ "resource_type": "OS::Heat::ResourceGroup"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/MISResourceGroupResponse.json b/adapters/mso-openstack-adapters/src/test/resources/MISResourceGroupResponse.json
new file mode 100644
index 0000000000..2350138076
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/MISResourceGroupResponse.json
@@ -0,0 +1,31 @@
+
+
+{
+ "resources": [
+ {
+ "parent_resource": "ssc_1_subint_mis_port_0_subinterfaces",
+ "resource_name": "0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst/447a9b41-714e-434b-b1d0-6cce8d9f0f0c/resources/0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst/447a9b41-714e-434b-b1d0-6cce8d9f0f0c",
+ "rel": "stack"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "0",
+ "resource_status_reason": "state changed",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "f711be16-2654-4a09-b89d-0511fda20e81",
+ "resource_type": "vlan_subinterface_ssc_mis.yaml"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/MISSubInterface0.json b/adapters/mso-openstack-adapters/src/test/resources/MISSubInterface0.json
new file mode 100644
index 0000000000..d879b3be59
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/MISSubInterface0.json
@@ -0,0 +1,41 @@
+{
+ "stack": {
+ "parent": "447a9b41-714e-434b-b1d0-6cce8d9f0f0c",
+ "disable_rollback": true,
+ "description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "self"
+ }
+ ],
+ "stack_status_reason": "Stack CREATE completed successfully",
+ "stack_name": "tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y",
+ "stack_user_project_id": "dfffe8b2401b45368ca6e21f19796ce1",
+ "stack_owner": "m08699",
+ "creation_time": "2019-01-23T19:34:56Z",
+ "capabilities": [],
+ "notification_topics": [],
+ "updated_time": null,
+ "timeout_mins": 120,
+ "stack_status": "CREATE_COMPLETE",
+ "parameters": {
+ "OS::project_id": "ea2d13cc98b44d60a6f94bdcb2738f9e",
+ "port_interface": "0594a2f2-7ea4-42eb-abc2-48ea49677fca",
+ "OS::stack_id": "f711be16-2654-4a09-b89d-0511fda20e81",
+ "OS::stack_name": "tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y",
+ "vip_v6_address": "2001:1890:1001:4a32::3",
+ "network_id": "8be20e92-68d6-4aec-ae66-0fc0fc933546",
+ "subinterface_name_prefix": "tsbc0005v_tsbc0005vm002_subint_untrusted_mis",
+ "counter": "0",
+ "mac_address": "02:05:94:a2:f2:7e",
+ "vip_address": "32.68.12.91",
+ "vlan_tag": "81",
+ "ip_address": "32.68.12.92",
+ "ip_v6_address": "2001:1890:1001:4a32::4"
+ },
+ "id": "f711be16-2654-4a09-b89d-0511fda20e81",
+ "outputs": [],
+ "template_description": "HOT template to instantiate a single Contrail VLAN sub-interface with associated instance IP addresses and allowed address pairs\n"
+ }
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/MISSubInterface1Resources.json b/adapters/mso-openstack-adapters/src/test/resources/MISSubInterface1Resources.json
new file mode 100644
index 0000000000..5fa2795462
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/MISSubInterface1Resources.json
@@ -0,0 +1,70 @@
+{
+ "resources": [
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [
+ "ssc_subint_mis_vmi_0_v6_ip_0",
+ "ssc_subint_mis_vmi_0_ip_0"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "2bbfa345-33bb-495a-94b2-fb514ee1cffc",
+ "resource_type": "OS::ContrailV2::VirtualMachineInterface"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_v6_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_v6_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "e7f25707-12fd-454f-95ac-6a05cd70806f",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ },
+ {
+ "parent_resource": "0",
+ "resource_name": "ssc_subint_mis_vmi_0_ip_0",
+ "links": [
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81/resources/ssc_subint_mis_vmi_0_ip_0",
+ "rel": "self"
+ },
+ {
+ "href": "https://orchestration-aic.dyh3b.cci.att.com:8004/v1/ea2d13cc98b44d60a6f94bdcb2738f9e/stacks/tsbc0005vm002ssc001-ssc_1_subint_mis_port_0_subinterfaces-hlzdigtimzst-0-upfi5nhurk7y/f711be16-2654-4a09-b89d-0511fda20e81",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "ssc_subint_mis_vmi_0_ip_0",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2019-01-23T19:34:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "6d23f4d3-8f7b-42c5-bb9e-4aee5797d506",
+ "resource_type": "OS::ContrailV2::InstanceIp"
+ }
+ ]
+} \ No newline at end of file
diff --git a/adapters/mso-openstack-adapters/src/test/resources/logback-test.xml b/adapters/mso-openstack-adapters/src/test/resources/logback-test.xml
index 0611e62f3d..5d6eee746f 100644
--- a/adapters/mso-openstack-adapters/src/test/resources/logback-test.xml
+++ b/adapters/mso-openstack-adapters/src/test/resources/logback-test.xml
@@ -41,7 +41,11 @@
<appender-ref ref="STDOUT" />
</logger>
- <logger name="org.onap" level="${so.log.level:-DEBUG}" additivity="false">
+ <logger name="org.onap" level="${so.log.level:-DEBUG}" additivity="false">
+ <appender-ref ref="STDOUT" />
+ </logger>
+
+ <logger name="org.onap" level="${so.log.level:-DEBUG}" additivity="false">
<appender-ref ref="STDOUT" />
</logger>