compare resources from openstack to aai 47/77747/2
authorBenjamin, Max (mb388a) <mb388a@us.att.com>
Fri, 1 Feb 2019 23:13:35 +0000 (18:13 -0500)
committerBenjamin, Max (mb388a) <mb388a@us.att.com>
Fri, 1 Feb 2019 23:48:10 +0000 (18:48 -0500)
Address Review comments on pull request
Update Unit test to have proper variable for testing
update logic inside bpmn to reflect proper variable
Update unit test to check property for audit
Add flag to turn on and off audit behavior
Add license headers, remove un-used files
Update Building Block Tests and Activity Names
Fix additional unit tests in so-bpmn-tasks layer
Fix broken Junit Test, and correct Bug in if statement
Add annotation to ignore class under test profile
Additional bug fixes and unit tests for classes
Add Additional JUNITS, add more sample data
Add Openstack Audit functionality to Adapter

Change-Id: I0492063271e991eefc608b56336a5cdf1d5a7778
Issue-ID: SO-1456
Signed-off-by: Benjamin, Max (mb388a) <mb388a@us.att.com>
45 files changed:
adapters/mso-adapter-utils/src/main/java/org/onap/so/audit/beans/AuditInventory.java [new file with mode: 0644]
adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java
adapters/mso-openstack-adapters/pom.xml
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAudit.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackServiceData.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/HeatStackAudit.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/AaiClientPropertiesImpl.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java
adapters/mso-openstack-adapters/src/main/resources/META-INF/services/org.onap.so.client.RestProperties [new file with mode: 0644]
adapters/mso-openstack-adapters/src/main/resources/application.yaml
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditVServerTest.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/HeatStackAuditTest.java [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNResourceGroupResponse.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface0Resources.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface1Resources.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/AVPNSubInterface2Resources.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/GetResources.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/MISResourceGroupResponse.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/MISSubInterface0.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/MISSubInterface1Resources.json [new file with mode: 0644]
adapters/mso-openstack-adapters/src/test/resources/logback-test.xml
bpmn/MSOCommonBPMN/src/main/java/org/onap/so/bpmn/servicedecomposition/tasks/ExecuteBuildingBlockRainyDay.java
bpmn/MSOCommonBPMN/src/main/java/org/onap/so/client/exception/ExceptionBuilder.java
bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/ExecuteBuildlingBlockRainyDayTest.java
bpmn/mso-infrastructure-bpmn/src/main/resources/application.yaml
bpmn/so-bpmn-building-blocks/pom.xml
bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ActivateVfModuleBB.bpmn
bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/CreateVfModuleBB.bpmn
bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ExecuteBuildingBlock.bpmn
bpmn/so-bpmn-building-blocks/src/test/java/org/onap/so/bpmn/BaseBPMNTest.java
bpmn/so-bpmn-building-blocks/src/test/java/org/onap/so/bpmn/infrastructure/bpmn/subprocess/ActivateVfModuleBBTest.java
bpmn/so-bpmn-building-blocks/src/test/resources/application-test.yaml
bpmn/so-bpmn-building-blocks/src/test/resources/logback-test.xml
bpmn/so-bpmn-tasks/pom.xml
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/audit/AuditTasks.java [new file with mode: 0644]
bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/audit/AuditTasksTest.java [new file with mode: 0644]
common/src/main/java/org/onap/so/client/aai/AAIObjectPlurals.java
common/src/main/java/org/onap/so/client/aai/AAIObjectType.java
mso-api-handlers/mso-api-handler-infra/src/main/resources/application.yaml

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 (file)
index 0000000..025d40d
--- /dev/null
@@ -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;
+       }
+       
+       
+
+}
index f132f10..14aee2f 100644 (file)
@@ -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 {
index 743c50d..8d4f30b 100644 (file)
                        <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 (file)
index 0000000..292cebf
--- /dev/null
@@ -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 (file)
index 0000000..38b0068
--- /dev/null
@@ -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 (file)
index 0000000..b036939
--- /dev/null
@@ -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 (file)
index 0000000..6e6ecd5
--- /dev/null
@@ -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 (file)
index 0000000..7bba136
--- /dev/null
@@ -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 (file)
index 0000000..c529413
--- /dev/null
@@ -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;
+       }
+}
index a9aa50f..9408f0d 100644 (file)
@@ -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 (file)
index 0000000..4ce4d75
--- /dev/null
@@ -0,0 +1 @@
+org.onap.so.adapters.openstack.AaiClientPropertiesImpl
\ No newline at end of file
index 8fd6d42..18084ce 100644 (file)
@@ -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 (file)
index 0000000..52b67b8
--- /dev/null
@@ -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 (file)
index 0000000..11e5440
--- /dev/null
@@ -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 (file)
index 0000000..5df5d82
--- /dev/null
@@ -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 (file)
index 0000000..27f971b
--- /dev/null
@@ -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 (file)
index 0000000..e0a2404
--- /dev/null
@@ -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 (file)
index 0000000..e0631db
--- /dev/null
@@ -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 (file)
index 0000000..009533b
--- /dev/null
@@ -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 (file)
index 0000000..1b10f16
--- /dev/null
@@ -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 (file)
index 0000000..7488ee2
--- /dev/null
@@ -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 (file)
index 0000000..94c7c69
--- /dev/null
@@ -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 (file)
index 0000000..33e282c
--- /dev/null
@@ -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 (file)
index 0000000..2350138
--- /dev/null
@@ -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 (file)
index 0000000..d879b3b
--- /dev/null
@@ -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 (file)
index 0000000..5fa2795
--- /dev/null
@@ -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
index 0611e62..5d6eee7 100644 (file)
     <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> 
 
index d2e0b07..b210b5e 100644 (file)
@@ -40,18 +40,19 @@ import org.springframework.stereotype.Component;
 
 @Component
 public class ExecuteBuildingBlockRainyDay {
-       
-       private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, ExecuteBuildingBlockRainyDay.class);
+
+       private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL,
+                       ExecuteBuildingBlockRainyDay.class);
        public static final String HANDLING_CODE = "handlingCode";
-       
+
        @Autowired
        private CatalogDbClient catalogDbClient;
        @Autowired
        private RequestsDbClient requestDbclient;
        private static final String ASTERISK = "*";
-       
+
        @Autowired
-    private Environment environment;
+       private Environment environment;
        protected String retryDurationPath = "mso.rainyDay.retryDurationMultiplier";
        protected String defaultCode = "mso.rainyDay.defaultCode";
 
@@ -67,7 +68,7 @@ public class ExecuteBuildingBlockRainyDay {
                        throw new BpmnError("Unknown error incrementing retry counter");
                }
        }
-       
+
        public void queryRainyDayTable(DelegateExecution execution, boolean primaryPolicy) {
                try {
                        ExecuteBuildingBlock ebb = (ExecuteBuildingBlock) execution.getVariable("buildingBlock");
@@ -79,18 +80,20 @@ public class ExecuteBuildingBlockRainyDay {
                        boolean aLaCarte = (boolean) execution.getVariable("aLaCarte");
                        boolean suppressRollback = (boolean) execution.getVariable("suppressRollback");
                        String handlingCode = "";
-                       if(suppressRollback){
+                       if (suppressRollback) {
                                handlingCode = "Abort";
-                       }else{
+                       } else {
                                try {
-                                       serviceType = gBBInput.getCustomer().getServiceSubscription().getServiceInstances().get(0).getModelInfoServiceInstance().getServiceType();
+                                       serviceType = gBBInput.getCustomer().getServiceSubscription().getServiceInstances().get(0)
+                                                       .getModelInfoServiceInstance().getServiceType();
                                } catch (Exception ex) {
                                        // keep default serviceType value
                                }
                                String vnfType = ASTERISK;
                                try {
-                                       for(GenericVnf vnf : gBBInput.getCustomer().getServiceSubscription().getServiceInstances().get(0).getVnfs()) {
-                                               if(vnf.getVnfId().equalsIgnoreCase(lookupKeyMap.get(ResourceKey.GENERIC_VNF_ID))) {
+                                       for (GenericVnf vnf : gBBInput.getCustomer().getServiceSubscription().getServiceInstances().get(0)
+                                                       .getVnfs()) {
+                                               if (vnf.getVnfId().equalsIgnoreCase(lookupKeyMap.get(ResourceKey.GENERIC_VNF_ID))) {
                                                        vnfType = vnf.getVnfType();
                                                }
                                        }
@@ -104,58 +107,78 @@ public class ExecuteBuildingBlockRainyDay {
                                } catch (Exception ex) {
                                        // keep default errorCode value
                                }
+                               try {
+                                       errorCode = "" + (String) execution.getVariable("WorkflowExceptionCode");
+                               } catch (Exception ex) {
+                                       // keep default errorCode value
+                               }
+
                                String workStep = ASTERISK;
                                try {
                                        workStep = workflowException.getWorkStep();
                                } catch (Exception ex) {
                                        // keep default workStep value
                                }
-                               //Extract error data to be returned to WorkflowAction
-                               execution.setVariable("WorkflowExceptionErrorMessage", workflowException.getErrorMessage());
+                               
+                               try {
+                                       // Extract error data to be returned to WorkflowAction
+                                       execution.setVariable("WorkflowExceptionErrorMessage", workflowException.getErrorMessage());
+                               } catch (Exception e) {
+                                       msoLogger.error("No WorkflowException Found",e);
+                               }
                                RainyDayHandlerStatus rainyDayHandlerStatus;
-                               rainyDayHandlerStatus = catalogDbClient.getRainyDayHandlerStatusByFlowNameAndServiceTypeAndVnfTypeAndErrorCodeAndWorkStep(bbName,serviceType,vnfType,errorCode,workStep);
-                               if(rainyDayHandlerStatus==null){
-                                       rainyDayHandlerStatus = catalogDbClient.getRainyDayHandlerStatusByFlowNameAndServiceTypeAndVnfTypeAndErrorCodeAndWorkStep(bbName,ASTERISK,ASTERISK,ASTERISK,ASTERISK);
-                                       if(rainyDayHandlerStatus==null){
+                               rainyDayHandlerStatus = catalogDbClient
+                                               .getRainyDayHandlerStatusByFlowNameAndServiceTypeAndVnfTypeAndErrorCodeAndWorkStep(bbName,
+                                                               serviceType, vnfType, errorCode, workStep);
+                               if (rainyDayHandlerStatus == null) {
+                                       rainyDayHandlerStatus = catalogDbClient
+                                                       .getRainyDayHandlerStatusByFlowNameAndServiceTypeAndVnfTypeAndErrorCodeAndWorkStep(bbName,
+                                                                       ASTERISK, ASTERISK, errorCode, ASTERISK);
+                               }
+                               
+                               if (rainyDayHandlerStatus == null) {
+                                       rainyDayHandlerStatus = catalogDbClient
+                                                       .getRainyDayHandlerStatusByFlowNameAndServiceTypeAndVnfTypeAndErrorCodeAndWorkStep(bbName,
+                                                                       ASTERISK, ASTERISK, ASTERISK, ASTERISK);
+                                       if (rainyDayHandlerStatus == null) {
                                                handlingCode = "Abort";
-                                       }else{
-                                               if(primaryPolicy){
+                                       } else {
+                                               if (primaryPolicy) {
                                                        handlingCode = rainyDayHandlerStatus.getPolicy();
-                                               }else{
+                                               } else {
                                                        handlingCode = rainyDayHandlerStatus.getSecondaryPolicy();
                                                }
                                        }
-                               }else{
-                                       if(primaryPolicy){
+                               } else {
+                                       if (primaryPolicy) {
                                                handlingCode = rainyDayHandlerStatus.getPolicy();
-                                       }else{
+                                       } else {
                                                handlingCode = rainyDayHandlerStatus.getSecondaryPolicy();
                                        }
                                }
-                               if(!primaryPolicy){
-                                       try{
+                               if (!primaryPolicy) {
+                                       try {
                                                InfraActiveRequests request = requestDbclient.getInfraActiveRequestbyRequestId(requestId);
                                                request.setRetryStatusMessage("Retries have been exhausted.");
                                                requestDbclient.updateInfraActiveRequests(request);
-                                       } catch(Exception ex){
-                                               msoLogger.debug(ex.toString());
-                                               msoLogger.error("Failed to update Request Db Infra Active Requests with Retry Status");
+                                       } catch (Exception ex) {
+                                               msoLogger.error("Failed to update Request Db Infra Active Requests with Retry Status",ex);
                                        }
                                }
-                               if(handlingCode.equals("RollbackToAssigned")&&!aLaCarte){
+                               if (handlingCode.equals("RollbackToAssigned") && !aLaCarte) {
                                        handlingCode = "Rollback";
                                }
                        }
                        msoLogger.debug("RainyDayHandler Status Code is: " + handlingCode);
                        execution.setVariable(HANDLING_CODE, handlingCode);
                } catch (Exception e) {
-                       msoLogger.error("Failed to determine RainyDayHandler Status. Seting handlingCode = Abort");
+                       msoLogger.error("Failed to determine RainyDayHandler Status. Seting handlingCode = Abort", e);
                        String code = this.environment.getProperty(defaultCode);
                        execution.setVariable(HANDLING_CODE, code);
                }
        }
-       
-       public void setHandlingStatusSuccess(DelegateExecution execution){
+
+       public void setHandlingStatusSuccess(DelegateExecution execution) {
                execution.setVariable(HANDLING_CODE, "Success");
        }
 }
index adffee6..459ef66 100644 (file)
@@ -78,7 +78,6 @@ public class ExceptionBuilder {
                                        break;
                                }
                        }
-
                        msoLogger.error(MessageEnum.BPMN_GENERAL_EXCEPTION_ARG, msg, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, msg.toString());
                        execution.setVariable(errorVariable, exception.getMessage());
                } catch (Exception ex){
@@ -108,6 +107,11 @@ public class ExceptionBuilder {
                msoLogger.info("Throwing MSOWorkflowException");
                throw new BpmnError("MSOWorkflowException");
        }
+       
+       public void buildAndThrowWorkflowException(DelegateExecution execution, String errorCode, String errorMessage) {
+               execution.setVariable("WorkflowExceptionErrorMessage", errorMessage);
+               throw new BpmnError(errorCode,errorMessage);
+       }
 
        public String getProcessKey(DelegateExecution execution) {
                String testKey = (String) execution.getVariable("testProcessKey");
index cb5683d..868aabf 100644 (file)
@@ -93,7 +93,7 @@ public class ExecuteBuildlingBlockRainyDayTest extends BaseTest {
                vnf.setVnfType("vnft1");
                delegateExecution.setVariable("aLaCarte", true);                
                delegateExecution.setVariable("suppressRollback", false);
-
+               delegateExecution.setVariable("WorkflowExceptionCode", "7000");
                RainyDayHandlerStatus rainyDayHandlerStatus = new RainyDayHandlerStatus();
                rainyDayHandlerStatus.setErrorCode("7000");
                rainyDayHandlerStatus.setFlowName("AssignServiceInstanceBB");
@@ -116,7 +116,7 @@ public class ExecuteBuildlingBlockRainyDayTest extends BaseTest {
                vnf.setVnfType("vnft1");
                delegateExecution.setVariable("aLaCarte", true);
                delegateExecution.setVariable("suppressRollback", false);
-               
+               delegateExecution.setVariable("WorkflowExceptionCode", ASTERISK);
                RainyDayHandlerStatus rainyDayHandlerStatus = new RainyDayHandlerStatus();
                rainyDayHandlerStatus.setErrorCode(ASTERISK);
                rainyDayHandlerStatus.setFlowName("AssignServiceInstanceBB");
@@ -164,7 +164,7 @@ public class ExecuteBuildlingBlockRainyDayTest extends BaseTest {
                vnf.setVnfType("vnft1");
                delegateExecution.setVariable("aLaCarte", true);
                delegateExecution.setVariable("suppressRollback", false);
-               
+               delegateExecution.setVariable("WorkflowExceptionCode", "7000");
                RainyDayHandlerStatus rainyDayHandlerStatus = new RainyDayHandlerStatus();
                rainyDayHandlerStatus.setErrorCode("7000");
                rainyDayHandlerStatus.setFlowName("AssignServiceInstanceBB");
@@ -188,7 +188,7 @@ public class ExecuteBuildlingBlockRainyDayTest extends BaseTest {
                vnf.setVnfType("vnft1");
                delegateExecution.setVariable("aLaCarte", false);
                delegateExecution.setVariable("suppressRollback", false);
-               
+               delegateExecution.setVariable("WorkflowExceptionCode", "7000");
                RainyDayHandlerStatus rainyDayHandlerStatus = new RainyDayHandlerStatus();
                rainyDayHandlerStatus.setErrorCode("7000");
                rainyDayHandlerStatus.setFlowName("AssignServiceInstanceBB");
@@ -212,7 +212,7 @@ public class ExecuteBuildlingBlockRainyDayTest extends BaseTest {
                vnf.setVnfType("vnft1");
                delegateExecution.setVariable("aLaCarte", true);
                delegateExecution.setVariable("suppressRollback", false);
-               
+               delegateExecution.setVariable("WorkflowExceptionCode", "7000");
                RainyDayHandlerStatus rainyDayHandlerStatus = new RainyDayHandlerStatus();
                rainyDayHandlerStatus.setErrorCode("7000");
                rainyDayHandlerStatus.setFlowName("AssignServiceInstanceBB");
index 203988a..829fc12 100644 (file)
@@ -2,7 +2,9 @@ server:
   port: 8080  
   tomcat:
     max-threads: 50
-
+mso:
+  infra:
+    auditInventory: true
 spring: 
   datasource:
      driver-class-name: org.mariadb.jdbc.Driver 
index 4fe02ee..0971a9d 100644 (file)
                        <artifactId>mariaDB4j</artifactId>
                        <version>2.2.3</version>
                        <scope>test</scope>
-               </dependency>           
+               </dependency>   
+
        </dependencies>
 </project>
index 3670676..fd24be1 100644 (file)
@@ -1,16 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="2.0.3">
+<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.7.1">
   <bpmn:process id="ActivateVfModuleBB" name="ActivateVfModuleBB" isExecutable="true">
     <bpmn:startEvent id="ActivateVfModuleBB_Start">
       <bpmn:outgoing>SequenceFlow_0ieafii</bpmn:outgoing>
     </bpmn:startEvent>
-    <bpmn:sequenceFlow id="SequenceFlow_0ieafii" sourceRef="ActivateVfModuleBB_Start" targetRef="SetTimerDuration" />
+    <bpmn:sequenceFlow id="SequenceFlow_0ieafii" sourceRef="ActivateVfModuleBB_Start" targetRef="CheckAuditVariable" />
     <bpmn:endEvent id="ActivateVfModuleBB_End">
       <bpmn:incoming>SequenceFlow_0xsp0pv</bpmn:incoming>
     </bpmn:endEvent>
     <bpmn:serviceTask id="ActivateVfModule" name="&#10;SDNC&#10;Activate&#10;(vf module)&#10;" camunda:expression="${SDNCActivateTasks.activateVfModule(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
-      <bpmn:incoming>SequenceFlow_0e44ywc</bpmn:incoming>
-      <bpmn:outgoing>SequenceFlow_1yzril6</bpmn:outgoing>
+      <bpmn:incoming>SequenceFlow_07ybdik</bpmn:incoming>
+      <bpmn:incoming>SequenceFlow_0ee42yq</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_1a495wm</bpmn:outgoing>
     </bpmn:serviceTask>
     <bpmn:serviceTask id="UpdateVfModuleActiveStatus" name="&#10;AAI&#10;Update&#10;(vf module)&#10;" camunda:expression="${AAIUpdateTasks.updateOrchestrationStatusActivateVfModule(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
       <bpmn:incoming>SequenceFlow_1j4x1ej</bpmn:incoming>
         <camunda:out source="WorkflowException" target="WorkflowException" />
         <camunda:in source="mso-request-id" target="mso-request-id" />
       </bpmn:extensionElements>
-      <bpmn:incoming>SequenceFlow_1yzril6</bpmn:incoming>
+      <bpmn:incoming>SequenceFlow_1a495wm</bpmn:incoming>
       <bpmn:outgoing>SequenceFlow_1j4x1ej</bpmn:outgoing>
     </bpmn:callActivity>
+    <bpmn:sequenceFlow id="SequenceFlow_1a495wm" sourceRef="ActivateVfModule" targetRef="CallActivity_sdncHandler" />
     <bpmn:sequenceFlow id="SequenceFlow_1j4x1ej" sourceRef="CallActivity_sdncHandler" targetRef="UpdateVfModuleActiveStatus" />
-    <bpmn:serviceTask id="SetTimerDuration" name="Set Timer Duration" camunda:expression="${ActivateVfModule.setTimerDuration(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
+    <bpmn:sequenceFlow id="SequenceFlow_0xndboi" sourceRef="Setup_AAI_Inventory_Audit" targetRef="Audit_AAI_Inventory" />
+    <bpmn:serviceTask id="Setup_AAI_Inventory_Audit" name="Setup Inventory Audit Variable" camunda:expression="${AuditTasks.setupAuditVariable(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
+      <bpmn:incoming>SequenceFlow_0ghzwlo</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_0xndboi</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:serviceTask id="Audit_AAI_Inventory" name="Validate A&#38;AI Inventory" camunda:type="external" camunda:topic="InventoryAudit">
+      <bpmn:incoming>SequenceFlow_0xndboi</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_0ee42yq</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:boundaryEvent id="BoundaryEvent_1nb1hw4" attachedToRef="Audit_AAI_Inventory">
+      <bpmn:outgoing>SequenceFlow_1t99ceh</bpmn:outgoing>
+      <bpmn:errorEventDefinition />
+    </bpmn:boundaryEvent>
+    <bpmn:sequenceFlow id="SequenceFlow_1t99ceh" sourceRef="BoundaryEvent_1nb1hw4" targetRef="Task_0swpw3v" />
+    <bpmn:serviceTask id="Task_0swpw3v" name="Throw Exception" camunda:expression="${ExceptionBuilder.buildAndThrowWorkflowException(execution, &#34;AuditAAIInventoryFailure&#34;, &#34;Error Auditing Cloud Inventory in A&#38;AI&#34;)}" camunda:resultVariable="ExceptionBuilder">
+      <bpmn:incoming>SequenceFlow_1t99ceh</bpmn:incoming>
+    </bpmn:serviceTask>
+    <bpmn:exclusiveGateway id="ExclusiveGateway_1v8bmbu" default="SequenceFlow_07ybdik">
+      <bpmn:incoming>SequenceFlow_1xqyur9</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_07ybdik</bpmn:outgoing>
+      <bpmn:outgoing>SequenceFlow_0ghzwlo</bpmn:outgoing>
+    </bpmn:exclusiveGateway>
+    <bpmn:sequenceFlow id="SequenceFlow_07ybdik" sourceRef="ExclusiveGateway_1v8bmbu" targetRef="ActivateVfModule" />
+    <bpmn:sequenceFlow id="SequenceFlow_0ghzwlo" sourceRef="ExclusiveGateway_1v8bmbu" targetRef="Setup_AAI_Inventory_Audit">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression"><![CDATA[${execution.getVariable("auditInventoryNeeded").equals("true")}]]></bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:sequenceFlow id="SequenceFlow_0ee42yq" sourceRef="Audit_AAI_Inventory" targetRef="ActivateVfModule" />
+    <bpmn:serviceTask id="CheckAuditVariable" name="Check Audit Variable" camunda:expression="${AuditTasks.isAuditNeeded(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
       <bpmn:incoming>SequenceFlow_0ieafii</bpmn:incoming>
-      <bpmn:outgoing>SequenceFlow_0qc2sao</bpmn:outgoing>
+      <bpmn:outgoing>SequenceFlow_1xqyur9</bpmn:outgoing>
     </bpmn:serviceTask>
-    <bpmn:intermediateCatchEvent id="Timer" name="Timer">
-      <bpmn:incoming>SequenceFlow_0qc2sao</bpmn:incoming>
-      <bpmn:outgoing>SequenceFlow_0e44ywc</bpmn:outgoing>
-      <bpmn:timerEventDefinition>
-        <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">${execution.getVariable("vfModuleActivateTimerDuration")}</bpmn:timeDuration>
-      </bpmn:timerEventDefinition>
-    </bpmn:intermediateCatchEvent>
-    <bpmn:sequenceFlow id="SequenceFlow_0qc2sao" sourceRef="SetTimerDuration" targetRef="Timer" />
-    <bpmn:sequenceFlow id="SequenceFlow_0e44ywc" sourceRef="Timer" targetRef="ActivateVfModule" />
-    <bpmn:sequenceFlow id="SequenceFlow_1yzril6" sourceRef="ActivateVfModule" targetRef="CallActivity_sdncHandler" />
+    <bpmn:sequenceFlow id="SequenceFlow_1xqyur9" sourceRef="CheckAuditVariable" targetRef="ExclusiveGateway_1v8bmbu" />
   </bpmn:process>
-  <bpmn:error id="Error_0q258vt" name="gDelegateError" errorCode="7000" />
+  <bpmn:error id="Error_0q258vt" errorCode="7000" />
   <bpmndi:BPMNDiagram id="BPMNDiagram_1">
     <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="ActivateVfModuleBB">
       <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="ActivateVfModuleBB_Start">
-        <dc:Bounds x="173" y="102" width="36" height="36" />
+        <dc:Bounds x="73" y="102" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="179" y="138" width="24" height="12" />
+          <dc:Bounds x="46" y="138" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_0ieafii_di" bpmnElement="SequenceFlow_0ieafii">
-        <di:waypoint x="209" y="120" />
-        <di:waypoint x="274" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="109" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="161" y="120" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="190.5" y="99" width="90" height="12" />
+          <dc:Bounds x="90" y="99" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="EndEvent_1v967li_di" bpmnElement="ActivateVfModuleBB_End">
-        <dc:Bounds x="956" y="102" width="36" height="36" />
+        <dc:Bounds x="1104" y="102" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="710" y="142" width="90" height="12" />
+          <dc:Bounds x="935" y="142" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="ServiceTask_0hawa84_di" bpmnElement="ActivateVfModule">
-        <dc:Bounds x="490" y="80" width="100" height="80" />
+        <dc:Bounds x="539" y="80" width="100" height="80" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="ServiceTask_175e9ul_di" bpmnElement="UpdateVfModuleActiveStatus">
-        <dc:Bounds x="770" y="80" width="100" height="80" />
+        <dc:Bounds x="952" y="80" width="100" height="80" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_0xsp0pv_di" bpmnElement="SequenceFlow_0xsp0pv">
-        <di:waypoint x="870" y="120" />
-        <di:waypoint x="956" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="1052" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="1104" y="120" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="673" y="99" width="90" height="12" />
+          <dc:Bounds x="1033" y="99" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="CallActivity_03jkesd_di" bpmnElement="CallActivity_sdncHandler">
-        <dc:Bounds x="639" y="80" width="100" height="80" />
+        <dc:Bounds x="794" y="80" width="100" height="80" />
       </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="SequenceFlow_1a495wm_di" bpmnElement="SequenceFlow_1a495wm">
+        <di:waypoint xsi:type="dc:Point" x="639" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="794" y="120" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="671.5" y="99" width="90" height="12" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_1j4x1ej_di" bpmnElement="SequenceFlow_1j4x1ej">
-        <di:waypoint x="739" y="120" />
-        <di:waypoint x="770" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="894" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="952" y="120" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="878" y="99" width="90" height="12" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0xndboi_di" bpmnElement="SequenceFlow_0xndboi">
+        <di:waypoint xsi:type="dc:Point" x="365" y="256" />
+        <di:waypoint xsi:type="dc:Point" x="452" y="256" />
+        <di:waypoint xsi:type="dc:Point" x="452" y="256" />
+        <di:waypoint xsi:type="dc:Point" x="539" y="256" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="560" y="99" width="0" height="12" />
+          <dc:Bounds x="422" y="249.5" width="90" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNShape id="ServiceTask_0tg4hn9_di" bpmnElement="SetTimerDuration">
-        <dc:Bounds x="274" y="80" width="100" height="80" />
+      <bpmndi:BPMNShape id="ServiceTask_0krf1ur_di" bpmnElement="Setup_AAI_Inventory_Audit">
+        <dc:Bounds x="265" y="216" width="100" height="80" />
       </bpmndi:BPMNShape>
-      <bpmndi:BPMNShape id="IntermediateCatchEvent_17kjdjp_di" bpmnElement="Timer">
-        <dc:Bounds x="417" y="102" width="36" height="36" />
+      <bpmndi:BPMNShape id="ServiceTask_08rxjeb_di" bpmnElement="Audit_AAI_Inventory">
+        <dc:Bounds x="539" y="216" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BoundaryEvent_0s7rszu_di" bpmnElement="BoundaryEvent_1nb1hw4">
+        <dc:Bounds x="575" y="278" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="421" y="145" width="29" height="14" />
+          <dc:Bounds x="548" y="317" width="90" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
-      <bpmndi:BPMNEdge id="SequenceFlow_0qc2sao_di" bpmnElement="SequenceFlow_0qc2sao">
-        <di:waypoint x="374" y="120" />
-        <di:waypoint x="417" y="120" />
+      <bpmndi:BPMNEdge id="SequenceFlow_1t99ceh_di" bpmnElement="SequenceFlow_1t99ceh">
+        <di:waypoint xsi:type="dc:Point" x="593" y="314" />
+        <di:waypoint xsi:type="dc:Point" x="593" y="348" />
+        <di:waypoint xsi:type="dc:Point" x="593" y="348" />
+        <di:waypoint xsi:type="dc:Point" x="593" y="371" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="563" y="341.5" width="90" height="13" />
+        </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge id="SequenceFlow_0e44ywc_di" bpmnElement="SequenceFlow_0e44ywc">
-        <di:waypoint x="453" y="120" />
-        <di:waypoint x="490" y="120" />
+      <bpmndi:BPMNShape id="ServiceTask_0eujimg_di" bpmnElement="Task_0swpw3v">
+        <dc:Bounds x="543" y="371" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ExclusiveGateway_1v8bmbu_di" bpmnElement="ExclusiveGateway_1v8bmbu" isMarkerVisible="true">
+        <dc:Bounds x="290" y="95" width="50" height="50" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="315" y="148" width="0" height="13" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="SequenceFlow_07ybdik_di" bpmnElement="SequenceFlow_07ybdik">
+        <di:waypoint xsi:type="dc:Point" x="340" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="539" y="120" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="439.5" y="98.5" width="0" height="13" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0ghzwlo_di" bpmnElement="SequenceFlow_0ghzwlo">
+        <di:waypoint xsi:type="dc:Point" x="315" y="145" />
+        <di:waypoint xsi:type="dc:Point" x="315" y="216" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="330" y="174" width="0" height="13" />
+        </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
-      <bpmndi:BPMNEdge id="SequenceFlow_1yzril6_di" bpmnElement="SequenceFlow_1yzril6">
-        <di:waypoint x="590" y="120" />
-        <di:waypoint x="639" y="120" />
+      <bpmndi:BPMNEdge id="SequenceFlow_0ee42yq_di" bpmnElement="SequenceFlow_0ee42yq">
+        <di:waypoint xsi:type="dc:Point" x="589" y="216" />
+        <di:waypoint xsi:type="dc:Point" x="589" y="193" />
+        <di:waypoint xsi:type="dc:Point" x="589" y="193" />
+        <di:waypoint xsi:type="dc:Point" x="589" y="160" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="604" y="186.5" width="0" height="13" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="ServiceTask_1eg5ryx_di" bpmnElement="CheckAuditVariable">
+        <dc:Bounds x="161" y="80" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="SequenceFlow_1xqyur9_di" bpmnElement="SequenceFlow_1xqyur9">
+        <di:waypoint xsi:type="dc:Point" x="261" y="120" />
+        <di:waypoint xsi:type="dc:Point" x="290" y="120" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="275.5" y="98.5" width="0" height="13" />
+        </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
     </bpmndi:BPMNPlane>
   </bpmndi:BPMNDiagram>
index bd126de..08252f6 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.10.0">
+<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.7.1">
   <bpmn:process id="CreateVfModuleBB" name="CreateVfModuleBB" isExecutable="true">
     <bpmn:startEvent id="CreateVfModuleBB_Start">
       <bpmn:outgoing>SequenceFlow_1xr6chl</bpmn:outgoing>
@@ -10,7 +10,7 @@
     </bpmn:serviceTask>
     <bpmn:sequenceFlow id="SequenceFlow_1xr6chl" sourceRef="CreateVfModuleBB_Start" targetRef="QueryVnf" />
     <bpmn:endEvent id="CreateVfModuleBB_End">
-      <bpmn:incoming>SequenceFlow_1stomxq</bpmn:incoming>
+      <bpmn:incoming>SequenceFlow_1vbwdaw</bpmn:incoming>
     </bpmn:endEvent>
     <bpmn:serviceTask id="CreateVfModule" name="Create VF Module (VNF)" camunda:expression="${VnfAdapterCreateTasks.createVfModule(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
       <bpmn:incoming>SequenceFlow_15hn8si</bpmn:incoming>
       <bpmn:incoming>SequenceFlow_16g4dz0</bpmn:incoming>
       <bpmn:outgoing>SequenceFlow_0ecr393</bpmn:outgoing>
     </bpmn:callActivity>
-    <bpmn:sequenceFlow id="SequenceFlow_1stomxq" sourceRef="UpdateVfModuleStatus" targetRef="CreateVfModuleBB_End" />
     <bpmn:serviceTask id="UpdateVfModuleStatus" name="&#10;AAI&#10;Update&#10;(vf module)&#10;" camunda:expression="${AAIUpdateTasks.updateOrchestrationStatusCreatedVfModule(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
-      <bpmn:incoming>SequenceFlow_0qqsilv</bpmn:incoming>
-      <bpmn:outgoing>SequenceFlow_1stomxq</bpmn:outgoing>
+      <bpmn:incoming>SequenceFlow_0rds4rj</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_1vbwdaw</bpmn:outgoing>
     </bpmn:serviceTask>
-    <bpmn:sequenceFlow id="SequenceFlow_0qqsilv" sourceRef="UpdateVfModuleHeatStackId" targetRef="UpdateVfModuleStatus" />
     <bpmn:serviceTask id="UpdateVfModuleHeatStackId" name="&#10;AAI&#10;Update&#10;(vf module)&#10;" camunda:expression="${AAIUpdateTasks.updateHeatStackIdVfModule(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
       <bpmn:incoming>SequenceFlow_0ecr393</bpmn:incoming>
-      <bpmn:outgoing>SequenceFlow_0qqsilv</bpmn:outgoing>
+      <bpmn:outgoing>SequenceFlow_0rds4rj</bpmn:outgoing>
     </bpmn:serviceTask>
     <bpmn:subProcess id="SubProcess_1getwnf" name="Error Handling&#10;&#10;" triggeredByEvent="true">
       <bpmn:startEvent id="StartEvent_1c8o652">
@@ -55,6 +53,8 @@
       </bpmn:endEvent>
       <bpmn:sequenceFlow id="SequenceFlow_0gcots6" sourceRef="StartEvent_1c8o652" targetRef="EndEvent_1emam1w" />
     </bpmn:subProcess>
+    <bpmn:sequenceFlow id="SequenceFlow_0rds4rj" sourceRef="UpdateVfModuleHeatStackId" targetRef="UpdateVfModuleStatus" />
+    <bpmn:sequenceFlow id="SequenceFlow_1vbwdaw" sourceRef="UpdateVfModuleStatus" targetRef="CreateVfModuleBB_End" />
   </bpmn:process>
   <bpmndi:BPMNDiagram id="BPMNDiagram_1">
     <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="CreateVfModuleBB">
@@ -75,9 +75,9 @@
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="EndEvent_0qdq7wj_di" bpmnElement="CreateVfModuleBB_End">
-        <dc:Bounds x="1278" y="88" width="36" height="36" />
+        <dc:Bounds x="1299" y="88" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="1286" y="128" width="19" height="12" />
+          <dc:Bounds x="1272" y="128" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="ServiceTask_1dgenhy_di" bpmnElement="CreateVfModule">
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_0ecr393_di" bpmnElement="SequenceFlow_0ecr393">
-        <di:waypoint xsi:type="dc:Point" x="877" y="106" />
-        <di:waypoint xsi:type="dc:Point" x="950" y="106" />
+        <di:waypoint xsi:type="dc:Point" x="877" y="107" />
+        <di:waypoint xsi:type="dc:Point" x="931" y="107" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="869" y="91" width="90" height="0" />
+          <dc:Bounds x="859" y="92" width="90" height="0" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="CallActivity_1i1pfzb_di" bpmnElement="VnfAdapter">
         <dc:Bounds x="777" y="66" width="100" height="80" />
       </bpmndi:BPMNShape>
-      <bpmndi:BPMNEdge id="SequenceFlow_1stomxq_di" bpmnElement="SequenceFlow_1stomxq">
-        <di:waypoint xsi:type="dc:Point" x="1214" y="106" />
-        <di:waypoint xsi:type="dc:Point" x="1278" y="106" />
-        <bpmndi:BPMNLabel>
-          <dc:Bounds x="1201" y="91" width="90" height="0" />
-        </bpmndi:BPMNLabel>
-      </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="ServiceTask_0fpfn71_di" bpmnElement="UpdateVfModuleStatus">
-        <dc:Bounds x="1114" y="66" width="100" height="80" />
+        <dc:Bounds x="1117" y="66" width="100" height="80" />
       </bpmndi:BPMNShape>
-      <bpmndi:BPMNEdge id="SequenceFlow_0qqsilv_di" bpmnElement="SequenceFlow_0qqsilv">
-        <di:waypoint xsi:type="dc:Point" x="1050" y="106" />
-        <di:waypoint xsi:type="dc:Point" x="1114" y="106" />
-        <bpmndi:BPMNLabel>
-          <dc:Bounds x="1037" y="91" width="90" height="0" />
-        </bpmndi:BPMNLabel>
-      </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="ServiceTask_04k1b85_di" bpmnElement="UpdateVfModuleHeatStackId">
-        <dc:Bounds x="950" y="66" width="100" height="80" />
+        <dc:Bounds x="931" y="68" width="100" height="80" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="SubProcess_1getwnf_di" bpmnElement="SubProcess_1getwnf" isExpanded="true">
         <dc:Bounds x="172" y="276" width="231" height="135" />
           <dc:Bounds x="297.5" y="331" width="0" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0rds4rj_di" bpmnElement="SequenceFlow_0rds4rj">
+        <di:waypoint xsi:type="dc:Point" x="1031" y="107" />
+        <di:waypoint xsi:type="dc:Point" x="1117" y="107" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1074" y="85" width="0" height="13" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1vbwdaw_di" bpmnElement="SequenceFlow_1vbwdaw">
+        <di:waypoint xsi:type="dc:Point" x="1217" y="106" />
+        <di:waypoint xsi:type="dc:Point" x="1299" y="106" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1258" y="84" width="0" height="13" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
     </bpmndi:BPMNPlane>
   </bpmndi:BPMNDiagram>
 </bpmn:definitions>
index 9be4cd0..943ce12 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.10.0">
+<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.7.1">
   <bpmn:process id="ExecuteBuildingBlock" name="ExecuteBuildingBlock" isExecutable="true">
     <bpmn:startEvent id="Start_ExecuteBuildingBlock" name="start">
       <bpmn:outgoing>SequenceFlow_0rq4c5r</bpmn:outgoing>
@@ -37,7 +37,7 @@
     <bpmn:subProcess id="SubProcess_0tv8zda" name="Error Handling&#10;&#10;" triggeredByEvent="true">
       <bpmn:startEvent id="StartEvent_0tmcs9g">
         <bpmn:outgoing>SequenceFlow_09synl9</bpmn:outgoing>
-        <bpmn:errorEventDefinition />
+        <bpmn:errorEventDefinition camunda:errorCodeVariable="WorkflowExceptionCode" camunda:errorMessageVariable="WorkflowExceptionMessage" />
       </bpmn:startEvent>
       <bpmn:sequenceFlow id="SequenceFlow_09synl9" sourceRef="StartEvent_0tmcs9g" targetRef="Task_QueryRainyDayTable" />
       <bpmn:serviceTask id="Task_QueryRainyDayTable" name="QueryRainyDayTable" camunda:expression="${ExecuteBuildingBlockRainyDay.queryRainyDayTable(execution,true)}">
   </bpmn:process>
   <bpmn:error id="Error_0tnktdw" name="Error" errorCode="java.lang.Exception" />
   <bpmn:error id="Error_17zcdbk" name="Bpmn Error" />
+  <bpmn:error id="Error_123q3fr" name="Error_1h13m8l" />
+  <bpmn:error id="Error_1ivyybb" name="Error_1e4p3cf" />
+  <bpmn:error id="Error_1c60d7i" name="Error_0qrs661" />
+  <bpmn:error id="Error_1owi18u" name="Error_2eiqdl7" />
+  <bpmn:error id="Error_0snha16" />
   <bpmndi:BPMNDiagram id="BPMNDiagram_1">
     <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="ExecuteBuildingBlock">
       <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="Start_ExecuteBuildingBlock">
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="ExclusiveGateway_0ey4zpt_di" bpmnElement="ExclusiveGateway_0ey4zpt" isMarkerVisible="true">
-        <dc:Bounds x="724" y="367" width="50" height="50" />
+        <dc:Bounds x="721" y="385" width="50" height="50" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="719" y="342" width="62" height="12" />
+          <dc:Bounds x="716" y="360" width="63" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="IntermediateCatchEvent_0qjyidb_di" bpmnElement="IntermediateCatchEvent_RetryTimer">
-        <dc:Bounds x="968" y="374" width="36" height="36" />
+        <dc:Bounds x="965" y="392" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="959" y="349" width="55" height="12" />
+          <dc:Bounds x="956" y="367" width="55" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="ExclusiveGateway_1aonzik_di" bpmnElement="ExclusiveGateway_1aonzik" isMarkerVisible="true">
-        <dc:Bounds x="571" y="367" width="50" height="50" />
+        <dc:Bounds x="568" y="385" width="50" height="50" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="562" y="329" width="68" height="24" />
+          <dc:Bounds x="558" y="347" width="70" height="25" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_1wbevp0_di" bpmnElement="SequenceFlow_1wbevp0">
-        <di:waypoint xsi:type="dc:Point" x="774" y="392" />
-        <di:waypoint xsi:type="dc:Point" x="839" y="392" />
+        <di:waypoint xsi:type="dc:Point" x="771" y="410" />
+        <di:waypoint xsi:type="dc:Point" x="836" y="410" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="790.2777777777778" y="367" width="18" height="12" />
+          <dc:Bounds x="788" y="385" width="18" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_0fwsjva_di" bpmnElement="SequenceFlow_0fwsjva">
-        <di:waypoint xsi:type="dc:Point" x="621" y="392" />
-        <di:waypoint xsi:type="dc:Point" x="724" y="392" />
+        <di:waypoint xsi:type="dc:Point" x="618" y="410" />
+        <di:waypoint xsi:type="dc:Point" x="721" y="410" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="659" y="400" width="27" height="12" />
+          <dc:Bounds x="656" y="418" width="27" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_0h8v45y_di" bpmnElement="SequenceFlow_0h8v45y">
-        <di:waypoint xsi:type="dc:Point" x="596" y="417" />
-        <di:waypoint xsi:type="dc:Point" x="596" y="473" />
+        <di:waypoint xsi:type="dc:Point" x="593" y="435" />
+        <di:waypoint xsi:type="dc:Point" x="593" y="491" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="603" y="438" width="84" height="12" />
+          <dc:Bounds x="600" y="456" width="85" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="ServiceTask_1tifgqh_di" bpmnElement="Task_QueryRainyDayTable">
-        <dc:Bounds x="428" y="352" width="100" height="80" />
+        <dc:Bounds x="425" y="370" width="100" height="80" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_0ndt8ft_di" bpmnElement="SequenceFlow_0ndt8ft">
-        <di:waypoint xsi:type="dc:Point" x="939" y="392" />
-        <di:waypoint xsi:type="dc:Point" x="968" y="392" />
+        <di:waypoint xsi:type="dc:Point" x="936" y="410" />
+        <di:waypoint xsi:type="dc:Point" x="965" y="410" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="908.5" y="371" width="90" height="12" />
+          <dc:Bounds x="906" y="389" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_07a1ytc_di" bpmnElement="SequenceFlow_07a1ytc">
-        <di:waypoint xsi:type="dc:Point" x="1004" y="392" />
-        <di:waypoint xsi:type="dc:Point" x="1042" y="392" />
+        <di:waypoint xsi:type="dc:Point" x="1001" y="410" />
+        <di:waypoint xsi:type="dc:Point" x="1039" y="410" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="978" y="371" width="90" height="12" />
+          <dc:Bounds x="975" y="389" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="ServiceTask_1obvxht_di" bpmnElement="Task_SetRetryTimer">
-        <dc:Bounds x="839" y="352" width="100" height="80" />
+        <dc:Bounds x="836" y="370" width="100" height="80" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_0kdjsnx_di" bpmnElement="Continue">
         <di:waypoint xsi:type="dc:Point" x="508" y="180" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_0a62t4c_di" bpmnElement="SequenceFlow_0a62t4c">
-        <di:waypoint xsi:type="dc:Point" x="528" y="392" />
-        <di:waypoint xsi:type="dc:Point" x="571" y="392" />
+        <di:waypoint xsi:type="dc:Point" x="525" y="410" />
+        <di:waypoint xsi:type="dc:Point" x="568" y="410" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="505" y="371" width="90" height="13" />
+          <dc:Bounds x="502" y="389" width="90" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="SubProcess_0tv8zda_di" bpmnElement="SubProcess_0tv8zda" isExpanded="true">
-        <dc:Bounds x="323" y="276" width="802" height="290" />
+        <dc:Bounds x="320" y="294" width="802" height="290" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="StartEvent_0tmcs9g_di" bpmnElement="StartEvent_0tmcs9g">
-        <dc:Bounds x="343" y="374" width="36" height="36" />
+        <dc:Bounds x="340" y="392" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="226" y="410" width="90" height="12" />
+          <dc:Bounds x="223" y="428" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_09synl9_di" bpmnElement="SequenceFlow_09synl9">
-        <di:waypoint xsi:type="dc:Point" x="379" y="392" />
-        <di:waypoint xsi:type="dc:Point" x="428" y="392" />
+        <di:waypoint xsi:type="dc:Point" x="376" y="410" />
+        <di:waypoint xsi:type="dc:Point" x="425" y="410" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="359" y="371" width="90" height="12" />
+          <dc:Bounds x="356" y="389" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="EndEvent_0mvmk3i_di" bpmnElement="EndEvent_0mvmk3i">
-        <dc:Bounds x="578" y="473" width="36" height="36" />
+        <dc:Bounds x="575" y="491" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="551" y="513" width="90" height="12" />
+          <dc:Bounds x="548" y="531" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="EndEvent_1aww7yx_di" bpmnElement="EndEvent_1sez2lh">
-        <dc:Bounds x="1042" y="374" width="36" height="36" />
+        <dc:Bounds x="1039" y="392" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="1052" y="414" width="18" height="12" />
+          <dc:Bounds x="1049" y="432" width="19" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_16lmcxp_di" bpmnElement="SequenceFlow_16lmcxp">
         <dc:Bounds x="906" y="140" width="100" height="80" />
       </bpmndi:BPMNShape>
       <bpmndi:BPMNEdge id="SequenceFlow_0541bid_di" bpmnElement="SequenceFlow_0541bid">
-        <di:waypoint xsi:type="dc:Point" x="749" y="417" />
-        <di:waypoint xsi:type="dc:Point" x="749" y="441" />
+        <di:waypoint xsi:type="dc:Point" x="746" y="435" />
+        <di:waypoint xsi:type="dc:Point" x="746" y="459" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="760" y="418" width="12" height="12" />
+          <dc:Bounds x="757" y="436" width="13" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge id="SequenceFlow_12ps9at_di" bpmnElement="SequenceFlow_12ps9at">
-        <di:waypoint xsi:type="dc:Point" x="799" y="481" />
-        <di:waypoint xsi:type="dc:Point" x="871" y="481" />
+        <di:waypoint xsi:type="dc:Point" x="796" y="499" />
+        <di:waypoint xsi:type="dc:Point" x="868" y="499" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="835" y="460" width="0" height="12" />
+          <dc:Bounds x="787" y="478" width="90" height="12" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNEdge>
       <bpmndi:BPMNShape id="EndEvent_05vw85n_di" bpmnElement="EndEvent_0ex9298">
-        <dc:Bounds x="871" y="463" width="36" height="36" />
+        <dc:Bounds x="868" y="481" width="36" height="36" />
         <bpmndi:BPMNLabel>
-          <dc:Bounds x="880" y="503" width="18" height="12" />
+          <dc:Bounds x="877" y="521" width="19" height="13" />
         </bpmndi:BPMNLabel>
       </bpmndi:BPMNShape>
       <bpmndi:BPMNShape id="ServiceTask_11f2c91_di" bpmnElement="Task_QuerySecondaryPolicy">
-        <dc:Bounds x="699" y="441" width="100" height="80" />
+        <dc:Bounds x="696" y="459" width="100" height="80" />
       </bpmndi:BPMNShape>
     </bpmndi:BPMNPlane>
   </bpmndi:BPMNDiagram>
index f501151..79bade3 100644 (file)
@@ -23,7 +23,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
+import org.camunda.bpm.engine.ExternalTaskService;
 import org.camunda.bpm.engine.RepositoryService;
 import org.camunda.bpm.engine.RuntimeService;
 import org.camunda.bpm.extension.mockito.mock.FluentJavaDelegateMock;
@@ -50,6 +50,7 @@ import org.onap.so.bpmn.infrastructure.adapter.vnf.tasks.VnfAdapterCreateTasks;
 import org.onap.so.bpmn.infrastructure.adapter.vnf.tasks.VnfAdapterDeleteTasks;
 import org.onap.so.bpmn.infrastructure.adapter.vnf.tasks.VnfAdapterImpl;
 import org.onap.so.bpmn.infrastructure.appc.tasks.AppcRunTasks;
+import org.onap.so.bpmn.infrastructure.audit.AuditTasks;
 import org.onap.so.bpmn.infrastructure.flowspecific.tasks.ActivateVfModule;
 import org.onap.so.bpmn.infrastructure.flowspecific.tasks.AssignNetwork;
 import org.onap.so.bpmn.infrastructure.flowspecific.tasks.AssignNetworkBBUtils;
@@ -93,6 +94,9 @@ public abstract class BaseBPMNTest {
        @Autowired
        protected RuntimeService runtimeService;
 
+       @Autowired
+       protected ExternalTaskService externalTaskService;
+       
        @Autowired
        private RepositoryService repositoryService;
 
@@ -227,6 +231,9 @@ public abstract class BaseBPMNTest {
        
        @MockBean
        protected WorkflowActionBBFailure workflowActionBBFailure;
+       
+       @MockBean
+       protected AuditTasks auditTasks;
 
        @LocalServerPort
        protected int port;
index 1bce605..9ffcd9d 100644 (file)
 package org.onap.so.bpmn.infrastructure.bpmn.subprocess;
 import static org.camunda.bpm.engine.test.assertions.bpmn.BpmnAwareAssertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import java.io.IOException;
+import java.util.List;
+
 import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.externaltask.LockedExternalTask;
 import org.camunda.bpm.engine.runtime.ProcessInstance;
 import org.junit.Before;
 import org.junit.Test;
@@ -35,17 +39,25 @@ public class ActivateVfModuleBBTest extends BaseBPMNTest{
        @Before
        public void before() {
                variables.put("vfModuleActivateTimerDuration", "PT2S");
+               variables.put("auditInventoryNeeded", "true");
        }
 
        @Test
        public void sunnyDay() throws InterruptedException, IOException {
                mockSubprocess("SDNCHandler", "My Mock Process Name", "GenericStub");
                ProcessInstance pi = runtimeService.startProcessInstanceByKey("ActivateVfModuleBB", variables);
-               while(runtimeService.createProcessInstanceQuery().processInstanceId(pi.getId()).singleResult() != null) {
-                       Thread.sleep(1000);
-               }
+               List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(100, "externalWorkerId")
+                .topic("InventoryAudit", 60L * 1000L).execute();
+        while (!tasks.isEmpty()) {
+            for (LockedExternalTask task : tasks) {
+                externalTaskService.complete(task.getId(), "externalWorkerId");
+            }
+            tasks = externalTaskService.fetchAndLock(100, "externalWorkerId")
+                    .topic("InventoryAudit", 60L * 1000L).execute();
+        }
+               
                assertThat(pi).isNotNull();
-               assertThat(pi).isStarted().hasPassedInOrder("ActivateVfModuleBB_Start", "SetTimerDuration", "Timer", "ActivateVfModule", "CallActivity_sdncHandler",
+               assertThat(pi).isStarted().hasPassedInOrder("ActivateVfModuleBB_Start","ExclusiveGateway_1v8bmbu","Setup_AAI_Inventory_Audit", "Audit_AAI_Inventory", "ActivateVfModule", "CallActivity_sdncHandler",
                                "UpdateVfModuleActiveStatus", "ActivateVfModuleBB_End");
                assertThat(pi).isEnded();
        }
@@ -55,11 +67,18 @@ public class ActivateVfModuleBBTest extends BaseBPMNTest{
                mockSubprocess("SDNCHandler", "My Mock Process Name", "GenericStub");
                doThrow(BpmnError.class).when(aaiUpdateTasks).updateOrchestrationStatusActivateVfModule(any(BuildingBlockExecution.class));
                ProcessInstance pi = runtimeService.startProcessInstanceByKey("ActivateVfModuleBB", variables);
-               while(runtimeService.createProcessInstanceQuery().processInstanceId(pi.getId()).singleResult() != null) {
-                       Thread.sleep(1000);
-               }
+               List<LockedExternalTask> tasks = externalTaskService.fetchAndLock(100, "externalWorkerId")
+                .topic("InventoryAudit", 60L * 1000L).execute();
+        while (!tasks.isEmpty()) {
+            for (LockedExternalTask task : tasks) {
+                externalTaskService.complete(task.getId(), "externalWorkerId");
+            }
+            tasks = externalTaskService.fetchAndLock(100, "externalWorkerId")
+                    .topic("InventoryAudit", 60L * 1000L).execute();
+        }
+
                assertThat(pi).isNotNull().isStarted()
-                               .hasPassedInOrder("ActivateVfModuleBB_Start", "SetTimerDuration", "Timer", "ActivateVfModule", "UpdateVfModuleActiveStatus")
+                               .hasPassedInOrder("ActivateVfModuleBB_Start","ExclusiveGateway_1v8bmbu","Setup_AAI_Inventory_Audit", "Audit_AAI_Inventory", "ActivateVfModule", "UpdateVfModuleActiveStatus")
                                .hasNotPassed("ActivateVfModuleBB_End");
        }
 }
index 1090ab7..c36172c 100644 (file)
@@ -31,6 +31,10 @@ log:
     vnfAdapterCreateV1: 'true'
     vnfAdapterRestV1: 'true'
 mso:
+  infra:
+    auditInventory: true
+    customer:
+      id: testCustIdInfra
   adapters:
     completemsoprocess:
       endpoint: http://localhost:28090/CompleteMsoProcess
@@ -96,9 +100,6 @@ mso:
   healthcheck:
     log:
       debug: 'false'
-  infra:
-    customer:
-      id: testCustIdInfra
   logPath: logs
   msoKey: 07a7159d3bf51a0e53be7a8f89699be7
   po:
index 64b6bfc..d8f6ba3 100644 (file)
@@ -26,5 +26,5 @@
   </root>
 
   <logger name="wiremock.org" level="DEBUG" />
-<logger name="org.camunda" level="DEBUG" />
+
 </configuration>
\ No newline at end of file
index becb66a..0243ce8 100644 (file)
                        <artifactId>so-bpmn-infrastructure-common</artifactId>
                        <version>${project.version}</version>
                </dependency>
+               <dependency>
+                       <groupId>org.onap.so.adapters</groupId>
+                       <artifactId>mso-adapter-utils</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
                <dependency>
                        <groupId>org.onap.sdnc.northbound</groupId>
                        <artifactId>generic-resource-api-client</artifactId>
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/audit/AuditTasks.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/audit/AuditTasks.java
new file mode 100644 (file)
index 0000000..aaa9e51
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * ============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.bpmn.infrastructure.audit;
+
+
+import org.onap.so.audit.beans.AuditInventory;
+import org.onap.so.bpmn.common.BuildingBlockExecution;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.CloudRegion;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.VfModule;
+import org.onap.so.bpmn.servicedecomposition.entities.GeneralBuildingBlock;
+import org.onap.so.bpmn.servicedecomposition.entities.ResourceKey;
+import org.onap.so.bpmn.servicedecomposition.tasks.ExtractPojosForBB;
+import org.onap.so.client.exception.BBObjectNotFoundException;
+import org.onap.so.client.exception.ExceptionBuilder;
+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 AuditTasks {
+       
+       private static final Logger logger = LoggerFactory.getLogger(AuditTasks.class);
+
+       @Autowired
+       private ExceptionBuilder exceptionUtil;
+       
+       @Autowired
+       private ExtractPojosForBB extractPojosForBB;
+       
+       @Autowired
+       private Environment env;
+       
+       public void isAuditNeeded(BuildingBlockExecution execution) {
+               try {                   
+                       logger.debug("auditInventoryNeeded Value: {}", env.getProperty("mso.infra.auditInventory"));
+                       execution.setVariable("auditInventoryNeeded",env.getProperty("mso.infra.auditInventory"));
+               } catch (Exception ex) {
+                       exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
+               }
+       }
+
+       public void setupAuditVariable(BuildingBlockExecution execution) {
+               try {
+                       execution.setVariable("auditInventory",createAuditInventory(execution));
+               } catch (Exception ex) {
+                       exceptionUtil.buildAndThrowWorkflowException(execution, 7000, ex);
+               }
+       }
+       
+       private AuditInventory createAuditInventory(BuildingBlockExecution execution) throws BBObjectNotFoundException {
+                       AuditInventory auditInventory = new AuditInventory();
+                       
+                       GeneralBuildingBlock gBBInput = execution.getGeneralBuildingBlock();
+                       VfModule vfModule = extractPojosForBB.extractByKey(execution, ResourceKey.VF_MODULE_ID, execution.getLookupMap().get(ResourceKey.VF_MODULE_ID));
+                       CloudRegion cloudRegion = gBBInput.getCloudRegion();
+                       
+                       auditInventory.setCloudOwner(cloudRegion.getCloudOwner());
+                       auditInventory.setCloudRegion(cloudRegion.getLcpCloudRegionId());
+                       auditInventory.setTenantId(cloudRegion.getTenantId());
+                       auditInventory.setHeatStackName(vfModule.getVfModuleName());
+                       return auditInventory;
+       }
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/audit/AuditTasksTest.java b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/audit/AuditTasksTest.java
new file mode 100644 (file)
index 0000000..7a9e2bb
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * ============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.bpmn.infrastructure.audit;
+
+import static com.shazam.shazamcrest.MatcherAssert.assertThat;
+import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
+import org.onap.so.audit.beans.AuditInventory;
+import org.onap.so.bpmn.BaseTaskTest;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.ServiceInstance;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.VfModule;
+import org.onap.so.bpmn.servicedecomposition.entities.ResourceKey;
+import org.onap.so.client.exception.BBObjectNotFoundException;
+
+public class AuditTasksTest extends BaseTaskTest{
+       
+       @InjectMocks
+       private AuditTasks auditTasks = new AuditTasks();
+       private ServiceInstance serviceInstance;
+       private GenericVnf genericVnf;
+       private VfModule vfModule;
+
+       
+       @Rule
+       public final ExpectedException exception = ExpectedException.none();
+       
+       @Before
+       public void before() throws BBObjectNotFoundException {
+               serviceInstance = setServiceInstance();         
+               genericVnf = setGenericVnf();
+               vfModule = setVfModule();
+               setCloudRegion();
+               when(extractPojosForBB.extractByKey(any(),ArgumentMatchers.eq(ResourceKey.GENERIC_VNF_ID), any())).thenReturn(genericVnf);
+               when(extractPojosForBB.extractByKey(any(),ArgumentMatchers.eq(ResourceKey.VF_MODULE_ID), any())).thenReturn(vfModule);
+               when(extractPojosForBB.extractByKey(any(),ArgumentMatchers.eq(ResourceKey.SERVICE_INSTANCE_ID), any())).thenReturn(serviceInstance);
+       }
+       
+       @Test
+       public void setupAuditVariableTest() throws Exception {
+               AuditInventory expectedAuditInventory = new AuditInventory();
+               expectedAuditInventory.setCloudOwner("testCloudOwner");
+               expectedAuditInventory.setCloudRegion("testLcpCloudRegionId");
+               expectedAuditInventory.setHeatStackName("testVfModuleName1");
+               expectedAuditInventory.setTenantId("testTenantId");
+               auditTasks.setupAuditVariable(execution);
+               assertThat((AuditInventory)execution.getVariable("auditInventory"), sameBeanAs(expectedAuditInventory));
+       }
+}
index 12e0ebe..7eadea0 100644 (file)
@@ -49,6 +49,8 @@ public class AAIObjectPlurals implements GraphInventoryObjectPlurals, Serializab
        public static final AAIObjectPlurals DEFAULT_TENANT = new AAIObjectPlurals(AAINamespaceConstants.CLOUD_INFRASTRUCTURE + "/cloud-regions/cloud-region/" + Defaults.CLOUD_OWNER + "/AAIAIC25", "/tenants", "default-tenant");
        public static final AAIObjectPlurals NETWORK_TECHNOLOGY = new AAIObjectPlurals(AAINamespaceConstants.CLOUD_INFRASTRUCTURE, "/network-technologies", "network-technology");
        public static final AAIObjectPlurals LOGICAL_LINK = new AAIObjectPlurals(AAINamespaceConstants.NETWORK, "/logical-links", "logical-link");
+       public static final AAIObjectPlurals L_INTERFACE = new AAIObjectPlurals(AAIObjectType.VSERVER.uriTemplate(), "/l-interfaces", "l-interface");
+       public static final AAIObjectPlurals SUB_L_INTERFACE = new AAIObjectPlurals(AAIObjectType.L_INTERFACE.uriTemplate(), "/l-interfaces", "l-interface");
 
        private final String uriTemplate;
        private final String partialUri;
index a6a9acf..66ff59d 100644 (file)
@@ -43,6 +43,7 @@ import org.onap.aai.domain.yang.ExtAaiNetwork;
 import org.onap.aai.domain.yang.GenericVnf;
 import org.onap.aai.domain.yang.InstanceGroup;
 import org.onap.aai.domain.yang.L3Network;
+import org.onap.aai.domain.yang.LInterface;
 import org.onap.aai.domain.yang.LineOfBusiness;
 import org.onap.aai.domain.yang.ModelVer;
 import org.onap.aai.domain.yang.NetworkPolicy;
@@ -131,6 +132,7 @@ public class AAIObjectType implements GraphInventoryObjectType, Serializable {
        public static final AAIObjectType DEVICE = new AAIObjectType(AAINamespaceConstants.NETWORK, Device.class);
        public static final AAIObjectType EXT_AAI_NETWORK = new AAIObjectType(AAINamespaceConstants.NETWORK, ExtAaiNetwork.class);
        public static final AAIObjectType AGGREGATE_ROUTE = new AAIObjectType(AAINamespaceConstants.NETWORK, AggregateRoute.class);
+       public static final AAIObjectType L_INTERFACE = new AAIObjectType(AAIObjectType.VSERVER.uriTemplate(), LInterface.class);
        public static final AAIObjectType UNKNOWN = new AAIObjectType("", "", "unknown");
 
        private final String uriTemplate;