Terminate NS Backend Service 48/113148/1
authorAndrewLamb <andrew.a.lamb@est.tech>
Thu, 10 Sep 2020 12:37:31 +0000 (13:37 +0100)
committerAndrewLamb <andrew.a.lamb@est.tech>
Thu, 24 Sep 2020 15:22:13 +0000 (16:22 +0100)
Issue-ID: SO-2869
Change-Id: I9c2b268d4f9aba7179633b71c8994065acacb742
Signed-off-by: AndrewLamb <andrew.a.lamb@est.tech>
29 files changed:
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/CamundaVariableNameConstants.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/Constants.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/extclients/aai/AaiServiceProvider.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/extclients/aai/AaiServiceProviderImpl.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/extclients/vnfm/Sol003AdapterServiceProvider.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/extclients/vnfm/Sol003AdapterServiceProviderImpl.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/extclients/vnfm/Sol003AdapterUrlProvider.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/service/JobExecutorService.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/AbstractNetworkServiceTask.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/CreateInstantiateVnfTask.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/InstantiateNsTask.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterNodeTask.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterTerminateJobTask.java [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterTerminateNodeTask.java [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/TerminateNsTask.java [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/TerminateVnfTask.java [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/MonitorSol003AdapterTerminateJob.bpmn [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/MonitorSol003AdapterTerminateNodeStatus.bpmn [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/TerminateNs.bpmn [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/TerminateVnf.bpmn [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/test/java/org/onap/so/etsi/nfvo/ns/workflow/engine/tasks/MonitorSol003AdapterTerminateJobTaskTest.java [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/test/java/org/onap/so/etsi/nfvo/ns/workflow/engine/tasks/TerminateNsTaskTest.java [new file with mode: 0644]
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-database-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/database/beans/NsLcmOpOcc.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-database-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/database/beans/State.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-database-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/database/service/DatabaseServiceProvider.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/EtsiSoNsLcmManagerUrlProvider.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLifeCycleManager.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementController.java
so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementControllerTest.java

index e90391d..fd51b1a 100644 (file)
@@ -31,7 +31,6 @@ public class CamundaVariableNameConstants {
     public static final String GLOBAL_CUSTOMER_ID_PARAM_NAME = "globalCustomerId";
     public static final String SERVICE_TYPE_PARAM_NAME = "serviceType";
 
-
     public static final String NS_PACKAGE_MODEL_PARAM_NAME = "NSPackageModel";
     public static final String CREATE_NS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME =
             "CreateNsWorkflowProcessingException";
@@ -47,6 +46,11 @@ public class CamundaVariableNameConstants {
     public static final String CREATE_VNF_RESPONSE_PARAM_NAME = "createVnfResponse";
     public static final String OPERATION_STATUS_PARAM_NAME = "operationStatus";
 
+    public static final String TERMINATE_NS_REQUEST_PARAM_NAME = "terminateNsRequest";
+    public static final String NFVO_NF_INST_IDS_PARAM_NAME = "nfvoNfInstIds";
+    public static final String DELETE_VNF_RESPONSE_PARAM_NAME = "deleteVnfResponse";
+    public static final String TERMINATE_VNF_VNFID_PARAM_NAME = "vnfId";
+
     private CamundaVariableNameConstants() {}
 
 }
index a2128fc..14a4f43 100644 (file)
@@ -29,6 +29,7 @@ public class Constants {
     public static final String NS_WORKFLOW_ENGINE = "NS-WORKFLOW-ENGINE";
     public static final String CREATE_NS_WORKFLOW_NAME = "CreateNs";
     public static final String INSTANTIATE_NS_WORKFLOW_NAME = "InstantiateNs";
+    public static final String TERMINATE_NS_WORKFLOW_NAME = "TerminateNs";
     public static final String GET_NS_OCCURRENCE_OPERATION_STATUS_NAME = "GetNsOccurrenceOperationStatus";
 
 
index 049746c..c668709 100644 (file)
@@ -80,4 +80,11 @@ public class AaiServiceProviderImpl implements AaiServiceProvider {
         return aaiClientProvider.getAaiClient().get(GenericVnf.class,
                 AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId));
     }
+
+    @Override
+    public void deleteGenericVnf(final String vnfId) {
+        logger.info("Deleting GenericVnf with id: {} from AAI.", vnfId);
+        final AAIResourceUri aaiResourceUri = AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId);
+        aaiClientProvider.getAaiClient().delete(aaiResourceUri);
+    }
 }
index c053ba9..4f98e2c 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.vnfm;
 import java.util.Optional;
 import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.CreateVnfRequest;
 import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.CreateVnfResponse;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.DeleteVnfResponse;
 import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.QueryJobResponse;
 
 public interface Sol003AdapterServiceProvider {
@@ -31,4 +32,6 @@ public interface Sol003AdapterServiceProvider {
 
     Optional<QueryJobResponse> getInstantiateOperationJobStatus(final String jobId);
 
+    Optional<DeleteVnfResponse> invokeTerminationRequest(final String vnfId);
+
 }
index 09fecc6..a0798f6 100644 (file)
@@ -24,6 +24,7 @@ import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.vnfm.Sol003Adap
 import java.util.Optional;
 import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.CreateVnfRequest;
 import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.CreateVnfResponse;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.DeleteVnfResponse;
 import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.QueryJobResponse;
 import org.onap.so.rest.exceptions.HttpResouceNotFoundException;
 import org.onap.so.rest.exceptions.InvalidRestRequestException;
@@ -114,4 +115,35 @@ public class Sol003AdapterServiceProviderImpl implements Sol003AdapterServicePro
             throw exception;
         }
     }
+
+    @Override
+    public Optional<DeleteVnfResponse> invokeTerminationRequest(final String vnfId) {
+        try {
+            final String url = urlProvider.getTerminateVnfUrl(vnfId);
+
+            final ResponseEntity<DeleteVnfResponse> response =
+                    httpServiceProvider.deleteHttpRequest(url, DeleteVnfResponse.class);
+            final HttpStatus httpStatus = response.getStatusCode();
+            if (!(httpStatus.equals(HttpStatus.ACCEPTED)) && !(httpStatus.equals(HttpStatus.OK))) {
+                LOGGER.error("Unable to invoke HTTP DELETE using URL: {}, Response Code: {}", url, httpStatus.value());
+                return Optional.empty();
+            }
+            if (!response.hasBody()) {
+                LOGGER.error(RECEIVED_RESPONSE_WITHOUT_BODY, response);
+                return Optional.empty();
+            }
+
+            final DeleteVnfResponse deleteVnfResponse = response.getBody();
+            if (deleteVnfResponse.getJobId() == null || deleteVnfResponse.getJobId().isEmpty()) {
+                LOGGER.error("Received invalid terminate response: {}", response);
+                return Optional.empty();
+            }
+
+            return Optional.of(deleteVnfResponse);
+        } catch (final RestProcessingException | InvalidRestRequestException
+                | HttpResouceNotFoundException httpInvocationException) {
+            LOGGER.error("Unexpected error while processing terminate request", httpInvocationException);
+            return Optional.empty();
+        }
+    }
 }
index 351d4bf..e3abc05 100644 (file)
@@ -61,4 +61,14 @@ public class Sol003AdapterUrlProvider {
         return UriComponentsBuilder.fromUri(baseUri).pathSegment("jobs").pathSegment(jobId).build().toString();
     }
 
+    /**
+     * Get VNFM terminate vnf URL
+     *
+     * @param vnfId
+     * @return
+     */
+    public String getTerminateVnfUrl(final String vnfId) {
+        return UriComponentsBuilder.fromUri(baseUri).pathSegment("vnfs").pathSegment(vnfId).build().toString();
+    }
+
 }
index 13cdc60..f240fa3 100644 (file)
@@ -26,9 +26,12 @@ import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstan
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.NS_INSTANCE_ID_PARAM_NAME;
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.OCC_ID_PARAM_NAME;
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.SERVICE_TYPE_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.TERMINATE_NS_REQUEST_PARAM_NAME;
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.Constants.CREATE_NS_WORKFLOW_NAME;
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.Constants.INSTANTIATE_NS_WORKFLOW_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.Constants.TERMINATE_NS_WORKFLOW_NAME;
 import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobAction.INSTANTIATE;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobAction.TERMINATE;
 import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.ERROR;
 import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.FINISHED;
 import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.FINISHED_WITH_ERROR;
@@ -47,14 +50,17 @@ import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.exceptions.NsRequestProcessingExc
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobAction;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoJob;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNsInst;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpOcc;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpType;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.OperationStateEnum;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.State;
 import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider;
 import org.onap.so.etsi.nfvo.ns.lcm.model.CreateNsRequest;
 import org.onap.so.etsi.nfvo.ns.lcm.model.InlineResponse400;
 import org.onap.so.etsi.nfvo.ns.lcm.model.InstantiateNsRequest;
 import org.onap.so.etsi.nfvo.ns.lcm.model.NsInstancesNsInstance;
+import org.onap.so.etsi.nfvo.ns.lcm.model.TerminateNsRequest;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -156,8 +162,8 @@ public class JobExecutorService {
         final LocalDateTime currentDateTime = LocalDateTime.now();
         final NsLcmOpOcc newNsLcmOpOcc = new NsLcmOpOcc().id(nsInstanceId).operation(NsLcmOpType.INSTANTIATE)
                 .operationState(OperationStateEnum.PROCESSING).stateEnteredTime(currentDateTime)
-                .startTime(currentDateTime).isAutoInnovation(false).isCancelPending(false)
-                .operationParams(gson.toJson(instantiateNsRequest));
+                .startTime(currentDateTime).nfvoNsInst(getNfvoNsInst(nsInstanceId)).isAutoInnovation(false)
+                .isCancelPending(false).operationParams(gson.toJson(instantiateNsRequest));
         databaseServiceProvider.addNSLcmOpOcc(newNsLcmOpOcc);
         logger.info("New NSLcmOpOcc created in database :\n{}", newNsLcmOpOcc);
 
@@ -190,6 +196,89 @@ public class JobExecutorService {
         throw new NsRequestProcessingException(message);
     }
 
+    public String runTerminateNsJob(final String nsInstanceId, final TerminateNsRequest terminateNsRequest) {
+        doInitialTerminateChecks(nsInstanceId, terminateNsRequest);
+
+        final NfvoJob nfvoJob = new NfvoJob().startTime(LocalDateTime.now()).jobType("NS").jobAction(TERMINATE)
+                .resourceId(nsInstanceId).status(STARTING).progress(0);
+        databaseServiceProvider.addJob(nfvoJob);
+        logger.info("New job created in database :\n{}", nfvoJob);
+
+        final LocalDateTime currentDateTime = LocalDateTime.now();
+        final NsLcmOpOcc nsLcmOpOcc = new NsLcmOpOcc().id(nsInstanceId).operation(NsLcmOpType.TERMINATE)
+                .operationState(OperationStateEnum.PROCESSING).stateEnteredTime(currentDateTime)
+                .startTime(currentDateTime).nfvoNsInst(getNfvoNsInst(nsInstanceId)).isAutoInnovation(false)
+                .isCancelPending(false).operationParams(gson.toJson(terminateNsRequest));
+        databaseServiceProvider.addNSLcmOpOcc(nsLcmOpOcc);
+        logger.info("New NSLcmOpOcc created in database :\n{}", nsLcmOpOcc);
+
+        workflowExecutorService.executeWorkflow(nfvoJob.getJobId(), TERMINATE_NS_WORKFLOW_NAME,
+                getVariables(nsInstanceId, nfvoJob.getJobId(), nsLcmOpOcc.getId(), terminateNsRequest));
+
+        final ImmutableSet<JobStatusEnum> jobFinishedStates =
+                ImmutableSet.of(FINISHED, ERROR, FINISHED_WITH_ERROR, IN_PROGRESS);
+        final ImmutablePair<String, JobStatusEnum> immutablePair =
+                waitForJobToFinish(nfvoJob.getJobId(), jobFinishedStates);
+
+        if (immutablePair.getRight() == null) {
+            final String message =
+                    "Failed to Terminate NS with id: " + nsInstanceId + " for request: \n" + terminateNsRequest;
+            logger.error(message);
+            throw new NsRequestProcessingException(message);
+        }
+
+        final JobStatusEnum finalJobStatus = immutablePair.getRight();
+
+        if (IN_PROGRESS.equals(finalJobStatus) || FINISHED.equals(finalJobStatus)) {
+            logger.info("Termination Job status: {}", finalJobStatus);
+            return nsLcmOpOcc.getId();
+        }
+
+        final String message = "Received unexpected Job Status: " + finalJobStatus + " Failed to Terminate NS with id: "
+                + nsInstanceId + " for request: \n" + terminateNsRequest;
+        logger.error(message);
+        throw new NsRequestProcessingException(message);
+    }
+
+    private void doInitialTerminateChecks(final String nsInstanceId, final TerminateNsRequest terminateNsRequest) {
+        if (isNotImmediateTerminateRequest(terminateNsRequest)) {
+            final String message = "TerminateNsRequest received with terminateTime: "
+                    + terminateNsRequest.getTerminationTime()
+                    + "\nOnly immediate Terminate requests are currently supported \n(i.e., terminateTime field must not be set).";
+            logger.error(message);
+            throw new NsRequestProcessingException(message);
+        }
+
+        final NfvoNsInst nfvoNsInst = getNfvoNsInst(nsInstanceId);
+        if (isNotInstantiated(nfvoNsInst)) {
+            final String message = "TerminateNsRequest received: " + terminateNsRequest + " for nsInstanceId: "
+                    + nsInstanceId + "\nUnable to terminate.  NS Instance is already in NOT_INSTANTIATED state."
+                    + "\nThis method can only be used with an NS instance in the INSTANTIATED state.";
+            logger.error(message);
+            throw new NsRequestProcessingException(message);
+        }
+    }
+
+    private boolean isNotImmediateTerminateRequest(final TerminateNsRequest terminateNsRequest) {
+        return terminateNsRequest.getTerminationTime() != null;
+    }
+
+    private boolean isNotInstantiated(final NfvoNsInst nfvoNsInst) {
+        return State.NOT_INSTANTIATED.equals(nfvoNsInst.getStatus());
+    }
+
+    private NfvoNsInst getNfvoNsInst(final String nsInstId) {
+        logger.info("Getting NfvoNsInst with nsInstId: {}", nsInstId);
+        final Optional<NfvoNsInst> optionalNfvoNsInst = databaseServiceProvider.getNfvoNsInst(nsInstId);
+
+        if (optionalNfvoNsInst.isEmpty()) {
+            final String message = "No matching NS Instance for id: " + nsInstId + " found in database.";
+            throw new NsRequestProcessingException(message);
+        }
+
+        return optionalNfvoNsInst.get();
+    }
+
     private ImmutablePair<String, JobStatusEnum> waitForJobToFinish(final String jobId,
             final ImmutableSet<JobStatusEnum> jobFinishedStates) {
         try {
@@ -209,7 +298,7 @@ public class JobExecutorService {
 
                 final NfvoJob nfvoJob = optional.get();
                 currentJobStatus = nfvoJob.getStatus();
-                logger.info("Received job status response: \n ", nfvoJob);
+                logger.debug("Received job status response: \n {}", nfvoJob);
                 if (jobFinishedStates.contains(nfvoJob.getStatus())) {
                     logger.info("Job finished \n {}", currentJobStatus);
                     return ImmutablePair.of(nfvoJob.getProcessInstanceId(), currentJobStatus);
@@ -249,4 +338,13 @@ public class JobExecutorService {
         return variables;
     }
 
+    private Map<String, Object> getVariables(final String nsInstanceId, final String jobId, final String occId,
+            final TerminateNsRequest terminateNsRequest) {
+        final Map<String, Object> variables = new HashMap<>();
+        variables.put(NS_INSTANCE_ID_PARAM_NAME, nsInstanceId);
+        variables.put(JOB_ID_PARAM_NAME, jobId);
+        variables.put(OCC_ID_PARAM_NAME, occId);
+        variables.put(TERMINATE_NS_REQUEST_PARAM_NAME, terminateNsRequest);
+        return variables;
+    }
 }
index 99116da..e6905b8 100644 (file)
@@ -21,6 +21,8 @@ package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.tasks;
 
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.CREATE_NS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME;
 import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.JOB_ID_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.NS_INSTANCE_ID_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.OCC_ID_PARAM_NAME;
 import java.time.LocalDateTime;
 import java.util.Optional;
 import org.camunda.bpm.engine.delegate.BpmnError;
@@ -28,6 +30,9 @@ import org.camunda.bpm.engine.delegate.DelegateExecution;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoJob;
 import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoJobStatus;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNsInst;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpOcc;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.OperationStateEnum;
 import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider;
 import org.onap.so.etsi.nfvo.ns.lcm.model.InlineResponse400;
 import org.slf4j.Logger;
@@ -35,6 +40,7 @@ import org.slf4j.LoggerFactory;
 
 /**
  * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
  *
  */
 public abstract class AbstractNetworkServiceTask {
@@ -90,6 +96,49 @@ public abstract class AbstractNetworkServiceTask {
 
     }
 
+    public void updateNsLcmOpOccStatusToCompleted(final DelegateExecution execution) {
+        logger.info("Executing updateNsLcmOpOccStatusToCompleted ...");
+        final String occId = (String) execution.getVariable(OCC_ID_PARAM_NAME);
+
+        final Optional<NsLcmOpOcc> optional = databaseServiceProvider.getNsLcmOpOcc(occId);
+
+        if (optional.isEmpty()) {
+            final String message = "Unable to find record for NSLcmOpOcc in database using id: " + occId;
+            logger.error(message);
+            abortOperation(execution, message);
+        }
+
+        final NsLcmOpOcc nsLcmOpOcc = optional.get();
+        final OperationStateEnum operationStateCompleted = OperationStateEnum.COMPLETED;
+        logger.info("Setting operation state to {} for id: {}", operationStateCompleted, occId);
+        nsLcmOpOcc.setOperationState(operationStateCompleted);
+        databaseServiceProvider.addNSLcmOpOcc(nsLcmOpOcc);
+
+        logger.info("Finished executing updateNsLcmOpOccStatusToCompleted ...");
+
+    }
+
+    public void updateNsLcmOpOccStatusToFailed(final DelegateExecution execution) {
+        logger.info("Executing updateNsLcmOpOccStatusToFailed ...");
+        final String occId = (String) execution.getVariable(OCC_ID_PARAM_NAME);
+
+        final Optional<NsLcmOpOcc> optional = databaseServiceProvider.getNsLcmOpOcc(occId);
+
+        if (optional.isPresent()) {
+            final NsLcmOpOcc nsLcmOpOcc = optional.get();
+            final OperationStateEnum operationStateFailed = OperationStateEnum.FAILED;
+            logger.info("Setting operation state to {} for id: {}", operationStateFailed, occId);
+            nsLcmOpOcc.setOperationState(operationStateFailed);
+
+            databaseServiceProvider.addNSLcmOpOcc(nsLcmOpOcc);
+        } else {
+            logger.error("Unable to find record for NSLcmOpOcc in database using id: {}", occId);
+        }
+
+        logger.info("Finished executing updateNsLcmOpOccStatusToFailed ...");
+
+    }
+
     protected void abortOperation(final DelegateExecution execution, final String message) {
         abortOperation(execution, message, new InlineResponse400().detail(message));
     }
@@ -104,7 +153,7 @@ public abstract class AbstractNetworkServiceTask {
     private NfvoJob getNfvoJob(final DelegateExecution execution) {
         final String jobId = (String) execution.getVariable(JOB_ID_PARAM_NAME);
         final Optional<NfvoJob> optional = databaseServiceProvider.getJob(jobId);
-        if (!optional.isPresent()) {
+        if (optional.isEmpty()) {
             final String message = "Unable to find job using job id: " + jobId;
             logger.error(message);
             execution.setVariable(CREATE_NS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME,
@@ -114,4 +163,22 @@ public abstract class AbstractNetworkServiceTask {
         }
         return optional.get();
     }
+
+    protected NfvoNsInst getNfvoNsInst(final DelegateExecution execution) {
+        final String nsInstId = (String) execution.getVariable(NS_INSTANCE_ID_PARAM_NAME);
+        return getNfvoNsInst(execution, nsInstId);
+    }
+
+    protected NfvoNsInst getNfvoNsInst(final DelegateExecution execution, final String nsInstId) {
+        logger.info("Getting NfvoNsInst to update with nsInstId: {}", nsInstId);
+        final Optional<NfvoNsInst> optionalNfvoNsInst = databaseServiceProvider.getNfvoNsInst(nsInstId);
+
+        if (optionalNfvoNsInst.isEmpty()) {
+            final String message = "Unable to find NS Instance in database using id: " + nsInstId;
+            abortOperation(execution, message);
+        }
+
+        return optionalNfvoNsInst.get();
+    }
+
 }
index c33c67e..251e694 100644 (file)
@@ -219,16 +219,4 @@ public class CreateInstantiateVnfTask extends AbstractNetworkServiceTask {
         databaseServiceProvider.saveNfvoNfInst(nfvoNfInst);
     }
 
-    private NfvoNsInst getNfvoNsInst(final DelegateExecution execution, final String nsInstId) {
-        logger.info("Getting NfvoNsInst to update with nsInstId: {}", nsInstId);
-        final Optional<NfvoNsInst> optionalNfvoNsInst = databaseServiceProvider.getNfvoNsInst(nsInstId);
-
-        if (!optionalNfvoNsInst.isPresent()) {
-            final String message = "Unable to find NS Instance in datababse using id: " + nsInstId;
-            abortOperation(execution, message);
-        }
-
-        return optionalNfvoNsInst.get();
-    }
-
 }
index 8d21204..6774fad 100644 (file)
@@ -55,6 +55,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 /**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
  * @author Andrew Lamb (andrew.a.lamb@est.tech)
  *
  */
@@ -272,50 +273,6 @@ public class InstantiateNsTask extends AbstractNetworkServiceTask {
         setJobStatusToError(execution, "Instantiate NS workflow process failed");
     }
 
-
-    public void updateNsLcmOpOccStatusToCompleted(final DelegateExecution execution) {
-        logger.info("Executing updateNsLcmOpOccStatusToCompleted ...");
-        final String occId = (String) execution.getVariable(OCC_ID_PARAM_NAME);
-
-        final Optional<NsLcmOpOcc> optional = databaseServiceProvider.getNsLcmOpOcc(occId);
-
-        if (!optional.isPresent()) {
-            final String message = "Unable to find record for NSLcmOpOcc in database using id: " + occId;
-            logger.error(message);
-            abortOperation(execution, message);
-        }
-
-        final NsLcmOpOcc nsLcmOpOcc = optional.get();
-        final OperationStateEnum operationStateCompleted = OperationStateEnum.COMPLETED;
-        logger.info("Setting operation state to {} for id: {}", operationStateCompleted, occId);
-        nsLcmOpOcc.setOperationState(operationStateCompleted);
-        databaseServiceProvider.addNSLcmOpOcc(nsLcmOpOcc);
-
-        logger.info("Finished executing updateNsLcmOpOccStatusToCompleted ...");
-
-    }
-
-    public void updateNsLcmOpOccStatusToFailed(final DelegateExecution execution) {
-        logger.info("Executing updateNsLcmOpOccStatusToFailed ...");
-        final String occId = (String) execution.getVariable(OCC_ID_PARAM_NAME);
-
-        final Optional<NsLcmOpOcc> optional = databaseServiceProvider.getNsLcmOpOcc(occId);
-
-        if (optional.isPresent()) {
-            final NsLcmOpOcc nsLcmOpOcc = optional.get();
-            final OperationStateEnum operationStateFailed = OperationStateEnum.FAILED;
-            logger.info("Setting operation state to {} for id: {}", operationStateFailed, occId);
-            nsLcmOpOcc.setOperationState(operationStateFailed);
-
-            databaseServiceProvider.addNSLcmOpOcc(nsLcmOpOcc);
-        } else {
-            logger.error("Unable to find record for NSLcmOpOcc in database using id: {}", occId);
-        }
-
-        logger.info("Finished executing updateNsLcmOpOccStatusToFailed ...");
-
-    }
-
     private NsdInfo getNsdInfo(final DelegateExecution execution, final String nsPackageId) {
         try {
             final Optional<NsdInfo> optional =
@@ -395,22 +352,4 @@ public class InstantiateNsTask extends AbstractNetworkServiceTask {
 
     }
 
-    private NfvoNsInst getNfvoNsInst(final DelegateExecution execution) {
-        final String nsInstId = (String) execution.getVariable(NS_INSTANCE_ID_PARAM_NAME);
-        return getNfvoNsInst(execution, nsInstId);
-    }
-
-    private NfvoNsInst getNfvoNsInst(final DelegateExecution execution, final String nsInstId) {
-        logger.info("Getting NfvoNsInst to update with nsInstId: {}", nsInstId);
-        final Optional<NfvoNsInst> optionalNfvoNsInst = databaseServiceProvider.getNfvoNsInst(nsInstId);
-
-        if (!optionalNfvoNsInst.isPresent()) {
-            final String message = "Unable to find NS Instance in database using id: " + nsInstId;
-            abortOperation(execution, message);
-        }
-
-        return optionalNfvoNsInst.get();
-    }
-
-
 }
index e27e0c1..e4dc3d5 100644 (file)
@@ -57,7 +57,7 @@ public abstract class MonitorSol003AdapterNodeTask extends AbstractNetworkServic
             final Optional<GenericVnf> aaiGenericVnfOptional = aaiServiceProvider.getGenericVnf(vnfId);
 
             if (!aaiGenericVnfOptional.isPresent()) {
-                abortOperation(execution, "Unable to invoke Sol003 adapter for create and instantiate vnfId" + vnfId);
+                abortOperation(execution, "Unable to find generic vnf in A&AI using vnfId" + vnfId);
             }
             final GenericVnf genericVnf = aaiGenericVnfOptional.get();
             final String orchestrationStatus = genericVnf.getOrchestrationStatus();
@@ -89,4 +89,8 @@ public abstract class MonitorSol003AdapterNodeTask extends AbstractNetworkServic
         LOGGER.error(message);
         abortOperation(execution, message);
     }
+
+    AaiServiceProvider getAaiServiceProvider() {
+        return aaiServiceProvider;
+    }
 }
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterTerminateJobTask.java b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterTerminateJobTask.java
new file mode 100644 (file)
index 0000000..d854444
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.tasks;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.DeleteVnfResponse;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStateEnum;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.vnfm.Sol003AdapterServiceProvider;
+import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.OPERATION_STATUS_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.DELETE_VNF_RESPONSE_PARAM_NAME;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+@Component
+public class MonitorSol003AdapterTerminateJobTask extends MonitorSol003AdapterJobTask {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorSol003AdapterTerminateJobTask.class);
+
+    @Autowired
+    public MonitorSol003AdapterTerminateJobTask(final Sol003AdapterServiceProvider sol003AdapterServiceProvider,
+            final DatabaseServiceProvider databaseServiceProvider) {
+        super(sol003AdapterServiceProvider, databaseServiceProvider);
+    }
+
+    public void getCurrentOperationStatus(final DelegateExecution execution) {
+        try {
+            LOGGER.debug("Executing getCurrentOperationStatus  ...");
+            final DeleteVnfResponse deleteVnfResponse =
+                    (DeleteVnfResponse) execution.getVariable(DELETE_VNF_RESPONSE_PARAM_NAME);
+            execution.setVariable(OPERATION_STATUS_PARAM_NAME,
+                    getOperationStatus(execution, deleteVnfResponse.getJobId()));
+            LOGGER.debug("Finished executing getCurrentOperationStatus ...");
+        } catch (final Exception exception) {
+            final String message = "Unable to invoke get current Operation status";
+            LOGGER.error(message, exception);
+            abortOperation(execution, message);
+
+        }
+    }
+
+    /**
+     * Log and throw exception on timeout for job status
+     *
+     * @param execution {@link org.onap.so.bpmn.common.DelegateExecutionImpl}
+     */
+    public void timeOutLogFailure(final DelegateExecution execution) {
+        final String message = "Termination operation time out";
+        LOGGER.error(message);
+        abortOperation(execution, message);
+    }
+
+    /**
+     * Check the final status of termination throw exception if not completed successfully
+     *
+     * @param execution {@link org.onap.so.bpmn.common.DelegateExecutionImpl}
+     */
+    public void checkIfOperationWasSuccessful(final DelegateExecution execution) {
+        LOGGER.debug("Executing checkIfOperationWasSuccessful  ...");
+        final OperationStateEnum operationStatus =
+                (OperationStateEnum) execution.getVariable(OPERATION_STATUS_PARAM_NAME);
+        final DeleteVnfResponse deleteVnfResponse =
+                (DeleteVnfResponse) execution.getVariable(DELETE_VNF_RESPONSE_PARAM_NAME);
+
+        if (operationStatus == null) {
+            final String message =
+                    "Unable to terminate, jobId: " + (deleteVnfResponse != null ? deleteVnfResponse.getJobId() : "null")
+                            + "Unable to retrieve OperationStatus";
+            LOGGER.error(message);
+            abortOperation(execution, message);
+        }
+        if (operationStatus != OperationStateEnum.COMPLETED) {
+            final String message =
+                    "Unable to terminate, jobId: " + (deleteVnfResponse != null ? deleteVnfResponse.getJobId() : "null")
+                            + " OperationStatus: " + operationStatus;
+            LOGGER.error(message);
+            abortOperation(execution, message);
+        }
+
+        LOGGER.debug("Successfully completed termination of job {}", deleteVnfResponse);
+    }
+}
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterTerminateNodeTask.java b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/MonitorSol003AdapterTerminateNodeTask.java
new file mode 100644 (file)
index 0000000..f38bdba
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.tasks;
+
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.aai.AaiServiceProvider;
+import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+@Component
+public class MonitorSol003AdapterTerminateNodeTask extends MonitorSol003AdapterNodeTask {
+
+    public static final String DELETE_VNF_NODE_STATUS = "deleteVnfNodeStatus";
+    public static final String VNF_ASSIGNED = "Assigned";
+
+    @Autowired
+    public MonitorSol003AdapterTerminateNodeTask(final DatabaseServiceProvider databaseServiceProvider,
+            final AaiServiceProvider aaiServiceProvider) {
+        super(databaseServiceProvider, aaiServiceProvider);
+    }
+
+    @Override
+    public String getNodeStatusVariableName() {
+        return DELETE_VNF_NODE_STATUS;
+    }
+
+    @Override
+    public boolean isOrchestrationStatusValid(final String orchestrationStatus) {
+        return VNF_ASSIGNED.equalsIgnoreCase(orchestrationStatus);
+    }
+
+}
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/TerminateNsTask.java b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/TerminateNsTask.java
new file mode 100644 (file)
index 0000000..972e4d6
--- /dev/null
@@ -0,0 +1,145 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.tasks;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNfInst;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNsInst;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.State;
+import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import java.util.ArrayList;
+import java.util.List;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.NS_INSTANCE_ID_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.FINISHED;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.IN_PROGRESS;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.STARTED;
+
+/**
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+@Component
+public class TerminateNsTask extends AbstractNetworkServiceTask {
+
+    private static final String IS_NS_TERMINATION_SUCCESSFUL_PARAM_NAME = "isNsTerminationSuccessful";
+    private static final Logger logger = LoggerFactory.getLogger(TerminateNsTask.class);
+
+    @Autowired
+    public TerminateNsTask(final DatabaseServiceProvider databaseServiceProvider) {
+        super(databaseServiceProvider);
+    }
+
+    public void setJobStatusToStarted(final DelegateExecution execution) {
+        setJobStatus(execution, STARTED, "Terminate NS workflow process started");
+    }
+
+    public void setJobStatusToFinished(final DelegateExecution execution) {
+        setJobStatus(execution, FINISHED, "Terminate NS workflow process finished");
+    }
+
+    public void setJobStatusToError(final DelegateExecution execution) {
+        updateNsInstanceStatus(execution, State.FAILED);
+        setJobStatusToError(execution, "Terminate NS workflow process failed");
+    }
+
+    public void updateNsInstanceStatusToTerminating(final DelegateExecution execution) {
+        logger.info("Executing updateNsInstanceStatusToTerminating");
+        setJobStatus(execution, IN_PROGRESS, "Updating NfvoNsInst Status to " + State.TERMINATING);
+        updateNsInstanceStatus(execution, State.TERMINATING);
+        logger.info("Finished executing updateNsInstanceStatusToTerminating  ...");
+    }
+
+    public void updateNsInstanceStatusToNotInstantiated(final DelegateExecution execution) {
+        logger.info("Executing updateNsInstanceStatusToNotInstantiated");
+        setJobStatus(execution, IN_PROGRESS, "Updating NfvoNsInst Status to " + State.NOT_INSTANTIATED);
+        updateNsInstanceStatus(execution, State.NOT_INSTANTIATED);
+        logger.info("Finished executing updateNsInstanceStatusToNotInstantiated  ...");
+    }
+
+    public void getVnfIdsInNs(final DelegateExecution execution) {
+        logger.info("Executing getVnfIdsInNs ...");
+        setJobStatus(execution, IN_PROGRESS, "Getting Each VnfId In Ns");
+        final List<String> nfvoNfInstIds = getNfvoNfInstIds(execution);
+        execution.setVariable(CamundaVariableNameConstants.NFVO_NF_INST_IDS_PARAM_NAME, nfvoNfInstIds);
+        logger.info("Finished executing getVnfIdsInNs ...");
+    }
+
+    public void checkIfVnfTerminationWasSuccessful(final DelegateExecution execution) {
+        logger.info("Executing checkIfVnfTerminationWasSuccessful");
+
+        final String nsInstId = (String) execution.getVariable(NS_INSTANCE_ID_PARAM_NAME);
+        final List<NfvoNfInst> nfInstances = databaseServiceProvider.getNfvoNfInstByNsInstId(nsInstId);
+
+        if ((nfInstances != null) && !(nfInstances.isEmpty())) {
+            final String message = "Found NF Instances";
+            nfInstances.stream().forEach(instance -> {
+                logger.error("VNF : {} {} termination failed", instance.getNfInstId(), instance.getName());
+                execution.setVariable(IS_NS_TERMINATION_SUCCESSFUL_PARAM_NAME, false);
+            });
+            abortOperation(execution, message);
+        }
+
+        execution.setVariable(IS_NS_TERMINATION_SUCCESSFUL_PARAM_NAME, true);
+        logger.info("Finished executing checkIfVnfTerminationWasSuccessful");
+    }
+
+    public void logTimeOut(final DelegateExecution execution) {
+        logger.error("Vnf termination timedOut ...");
+        final String nsInstId = (String) execution.getVariable(NS_INSTANCE_ID_PARAM_NAME);
+        final List<NfvoNfInst> nfInstances = databaseServiceProvider.getNfvoNfInstByNsInstId(nsInstId);
+        if (nfInstances != null) {
+            nfInstances.stream().forEach(instance -> {
+                logger.info("Current status {} of vnf: {}", instance.getStatus(), instance.getName());
+            });
+        }
+    }
+
+    private void updateNsInstanceStatus(final DelegateExecution execution, final State nsStatus) {
+        final NfvoNsInst nfvoNsInst = getNfvoNsInst(execution);
+        logger.info("Updating NfvoNsInst Status to {} and saving to DB", nsStatus);
+        nfvoNsInst.setStatus(nsStatus);
+        databaseServiceProvider.saveNfvoNsInst(nfvoNsInst);
+    }
+
+    private List<String> getNfvoNfInstIds(final DelegateExecution execution) {
+        final String nsInstId = (String) execution.getVariable(NS_INSTANCE_ID_PARAM_NAME);
+        logger.info("Getting NfvoNfInstList using nsInstId: {}", nsInstId);
+        final List<NfvoNfInst> nfvoNfInstList = databaseServiceProvider.getNfvoNfInstByNsInstId(nsInstId);
+
+        if (nfvoNfInstList.size() == 0) {
+            final String message = "Unable to find NF Instances in database using id: " + nsInstId;
+            abortOperation(execution, message);
+        }
+
+        final List<String> vnfIdsList = new ArrayList<>();
+
+        nfvoNfInstList.stream().forEach(nfvoNfInst -> {
+            vnfIdsList.add(nfvoNfInst.getNfInstId());
+        });
+
+        return vnfIdsList;
+    }
+
+}
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/TerminateVnfTask.java b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/bpmn/flows/tasks/TerminateVnfTask.java
new file mode 100644 (file)
index 0000000..15eee22
--- /dev/null
@@ -0,0 +1,187 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.tasks;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.DeleteVnfResponse;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.aai.AaiServiceProvider;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.vnfm.Sol003AdapterServiceProvider;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNfInst;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.State;
+import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import java.util.Optional;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.NF_INST_ID_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.DELETE_VNF_RESPONSE_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants.TERMINATE_VNF_VNFID_PARAM_NAME;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.ERROR;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.FINISHED;
+import static org.onap.so.etsi.nfvo.ns.lcm.database.beans.JobStatusEnum.IN_PROGRESS;
+
+/**
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ */
+@Component
+public class TerminateVnfTask extends AbstractNetworkServiceTask {
+    private static final Logger logger = LoggerFactory.getLogger(TerminateVnfTask.class);
+    private final AaiServiceProvider aaiServiceProvider;
+    private final Sol003AdapterServiceProvider sol003AdapterServiceProvider;
+
+    @Autowired
+    public TerminateVnfTask(final DatabaseServiceProvider databaseServiceProvider,
+            final AaiServiceProvider aaiServiceProvider,
+            final Sol003AdapterServiceProvider sol003AdapterServiceProvider) {
+        super(databaseServiceProvider);
+        this.aaiServiceProvider = aaiServiceProvider;
+        this.sol003AdapterServiceProvider = sol003AdapterServiceProvider;
+    }
+
+    public void checkIfNfInstanceExistsInDb(final DelegateExecution execution) {
+        logger.info("Executing checkIfNfInstanceInDb");
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+        logger.info("vnfId: {}", vnfId);
+        execution.setVariable(NF_INST_ID_PARAM_NAME, vnfId);
+
+        setJobStatus(execution, JobStatusEnum.IN_PROGRESS,
+                "Checking if VNF Instance with id: " + vnfId + " exists in database.");
+        if (!databaseServiceProvider.isNfInstExists(vnfId)) {
+            abortOperation(execution,
+                    "VNF instance with id: " + vnfId + " does not exist in database, so will not be terminated.");
+        }
+        logger.info("Finished executing checkIfNfInstanceInDb  ...");
+
+    }
+
+    public void invokeTerminateRequest(final DelegateExecution execution) {
+        logger.info("Executing invokeTerminateRequest");
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+
+        try {
+            setJobStatus(execution, IN_PROGRESS, "Invoking SOL003 adapter for terminating VNF with vnfId: " + vnfId);
+
+            final Optional<DeleteVnfResponse> optional = sol003AdapterServiceProvider.invokeTerminationRequest(vnfId);
+
+            if (optional.isEmpty()) {
+                final String errorMessage = "Unexpected error while processing terminate request for vnfId: " + vnfId;
+                logger.error(errorMessage);
+                abortOperation(execution, errorMessage);
+            }
+
+            final DeleteVnfResponse vnfResponse = optional.get();
+
+            logger.info("Vnf delete response: {}", vnfResponse);
+            execution.setVariable(DELETE_VNF_RESPONSE_PARAM_NAME, vnfResponse);
+            setJobStatus(execution, IN_PROGRESS, "Successfully invoked SOL003 adapter terminate VNF with vnfId: "
+                    + vnfId + " DeleteVnfResponse Job Id: " + vnfResponse.getJobId());
+            logger.debug("Finished executing invokeTerminateRequest ...");
+        } catch (final Exception exception) {
+            final String message = "Unable to invoke terminate request for vnfId: " + vnfId;
+            logger.error(message, exception);
+            abortOperation(execution, message);
+        }
+
+    }
+
+    public void deleteGenericVnfFromAai(final DelegateExecution execution) {
+        logger.info("Executing deleteGenericVnfFromAai");
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+
+        try {
+            setJobStatus(execution, IN_PROGRESS, "Deleting GenericVnf record from AAI for vnfId: " + vnfId);
+            aaiServiceProvider.deleteGenericVnf(vnfId);
+
+        } catch (final Exception exception) {
+            final String message = "Unable to Delete GenericVnf from AAI for vnfId: " + vnfId;
+            logger.error(message, exception);
+            abortOperation(execution, message);
+        }
+
+        logger.info("Finished executing deleteGenericVnfFromAai ...");
+    }
+
+    public void deleteNfInstanceFromDb(final DelegateExecution execution) {
+        logger.info("Executing deleteNfInstanceFromDb");
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+
+        setJobStatus(execution, IN_PROGRESS, "Deleting NF Instance record from Database for vnfId: " + vnfId);
+        databaseServiceProvider.deleteNfvoNfInst(vnfId);
+
+        setJobStatus(execution, FINISHED, "Successfully finished terminating VNF with vnfId: " + vnfId);
+        logger.info("Finished executing deleteNfInstanceFromDb ...");
+    }
+
+    public void updateNfInstanceStatusToTerminating(final DelegateExecution execution) {
+        logger.info("Executing updateNfInstanceStatusToTerminating");
+
+        updateNfInstanceStatus(execution, State.TERMINATING);
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+        setJobStatus(execution, IN_PROGRESS,
+                "Terminating VNF with vnfId: " + vnfId + " will set status to " + State.TERMINATING);
+
+        logger.info("Finished executing updateNfInstanceStatusToTerminating  ...");
+
+    }
+
+    public void updateNfInstanceStatusToNotInstantiated(final DelegateExecution execution) {
+        logger.info("Executing updateNfInstanceStatusToNotInstantiated");
+
+        updateNfInstanceStatus(execution, State.NOT_INSTANTIATED);
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+        setJobStatus(execution, IN_PROGRESS,
+                "Successfully terminated VNF with vnfId: " + vnfId + " will set status to " + State.NOT_INSTANTIATED);
+
+        logger.info("Finished executing updateNfInstanceStatusToInstantiated  ...");
+
+    }
+
+    public void updateNfInstanceStatusToFailed(final DelegateExecution execution) {
+        logger.info("Executing updateNfInstanceStatusToFailed");
+
+        updateNfInstanceStatus(execution, State.FAILED);
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+        setJobStatus(execution, ERROR,
+                "Failed to terminate VNF with vnfId: " + vnfId + " will set status to " + State.FAILED);
+
+        logger.info("Finished executing updateNfInstanceStatusToFailed  ...");
+
+    }
+
+    private void updateNfInstanceStatus(final DelegateExecution execution, final State vnfStatus) {
+        final String vnfId = (String) execution.getVariable(TERMINATE_VNF_VNFID_PARAM_NAME);
+
+        final Optional<NfvoNfInst> optional = databaseServiceProvider.getNfvoNfInst(vnfId);
+        if (optional.isEmpty()) {
+            final String message = "Unable to find NfvoNfInst record in database using vnfId: " + vnfId;
+            logger.error(message);
+
+            abortOperation(execution, message);
+
+        }
+
+        final NfvoNfInst nfvoNfInst = optional.get();
+        nfvoNfInst.setStatus(vnfStatus);
+        databaseServiceProvider.saveNfvoNfInst(nfvoNfInst);
+    }
+
+}
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/MonitorSol003AdapterTerminateJob.bpmn b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/MonitorSol003AdapterTerminateJob.bpmn
new file mode 100644 (file)
index 0000000..1181a49
--- /dev/null
@@ -0,0 +1,160 @@
+<?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_12gnsyw" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
+  <bpmn:process id="MonitorSol003AdapterTerminateJob" name="MonitorSol003AdapterTerminateJob" isExecutable="true">
+    <bpmn:startEvent id="StartEvent_1">
+      <bpmn:outgoing>SequenceFlow_1x3tbl0</bpmn:outgoing>
+    </bpmn:startEvent>
+    <bpmn:endEvent id="EndEvent_0rf1gde">
+      <bpmn:incoming>SequenceFlow_1543qy7</bpmn:incoming>
+    </bpmn:endEvent>
+    <bpmn:subProcess id="SubProcess_19j0v63">
+      <bpmn:incoming>SequenceFlow_1x3tbl0</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_1v4yr3f</bpmn:outgoing>
+      <bpmn:startEvent id="StartEvent_01r97z2">
+        <bpmn:outgoing>SequenceFlow_0s1plu9</bpmn:outgoing>
+      </bpmn:startEvent>
+      <bpmn:exclusiveGateway id="ExclusiveGateway_1hkl6yy" default="SequenceFlow_1vmxw9g">
+        <bpmn:incoming>SequenceFlow_153a3kp</bpmn:incoming>
+        <bpmn:outgoing>SequenceFlow_1vmxw9g</bpmn:outgoing>
+        <bpmn:outgoing>SequenceFlow_0is7myf</bpmn:outgoing>
+      </bpmn:exclusiveGateway>
+      <bpmn:intermediateCatchEvent id="IntermediateCatchEvent_1besn3n" name="Wait between checks" camunda:asyncAfter="true">
+        <bpmn:incoming>SequenceFlow_1vmxw9g</bpmn:incoming>
+        <bpmn:outgoing>SequenceFlow_0etw572</bpmn:outgoing>
+        <bpmn:timerEventDefinition id="TimerEventDefinition_0qgh11t">
+          <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT15S</bpmn:timeDuration>
+        </bpmn:timerEventDefinition>
+      </bpmn:intermediateCatchEvent>
+      <bpmn:endEvent id="EndEvent_1ohsce9">
+        <bpmn:incoming>SequenceFlow_0is7myf</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:sequenceFlow id="SequenceFlow_0s1plu9" sourceRef="StartEvent_01r97z2" targetRef="ServiceTask_17jlnng" />
+      <bpmn:sequenceFlow id="SequenceFlow_0etw572" sourceRef="IntermediateCatchEvent_1besn3n" targetRef="ServiceTask_17jlnng" />
+      <bpmn:serviceTask id="ServiceTask_17jlnng" name="&#10;Get Current Operation Status&#10;" camunda:asyncAfter="true" camunda:expression="${MonitorSol003AdapterTerminateJobTask.getCurrentOperationStatus(execution)}">
+        <bpmn:incoming>SequenceFlow_0etw572</bpmn:incoming>
+        <bpmn:incoming>SequenceFlow_0s1plu9</bpmn:incoming>
+        <bpmn:outgoing>SequenceFlow_153a3kp</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="SequenceFlow_1vmxw9g" sourceRef="ExclusiveGateway_1hkl6yy" targetRef="IntermediateCatchEvent_1besn3n" />
+      <bpmn:sequenceFlow id="SequenceFlow_0is7myf" sourceRef="ExclusiveGateway_1hkl6yy" targetRef="EndEvent_1ohsce9">
+        <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${MonitorSol003AdapterCreateJobTask.hasOperationFinished(execution)}</bpmn:conditionExpression>
+      </bpmn:sequenceFlow>
+      <bpmn:sequenceFlow id="SequenceFlow_153a3kp" sourceRef="ServiceTask_17jlnng" targetRef="ExclusiveGateway_1hkl6yy" />
+    </bpmn:subProcess>
+    <bpmn:endEvent id="EndEvent_1w3t3t0" name="Timeout Exception">
+      <bpmn:incoming>SequenceFlow_0bcgtzj</bpmn:incoming>
+      <bpmn:terminateEventDefinition id="TerminateEventDefinition_0fjecl3" />
+    </bpmn:endEvent>
+    <bpmn:boundaryEvent id="BoundaryEvent_0xiabzp" name="Overall Wait" attachedToRef="SubProcess_19j0v63">
+      <bpmn:outgoing>SequenceFlow_1i1o9sh</bpmn:outgoing>
+      <bpmn:timerEventDefinition id="TimerEventDefinition_10kqw61">
+        <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT3H</bpmn:timeDuration>
+      </bpmn:timerEventDefinition>
+    </bpmn:boundaryEvent>
+    <bpmn:sequenceFlow id="SequenceFlow_1v4yr3f" sourceRef="SubProcess_19j0v63" targetRef="ServiceTask_1gms128" />
+    <bpmn:sequenceFlow id="SequenceFlow_1i1o9sh" sourceRef="BoundaryEvent_0xiabzp" targetRef="ServiceTask_1s87b92" />
+    <bpmn:sequenceFlow id="SequenceFlow_1x3tbl0" sourceRef="StartEvent_1" targetRef="SubProcess_19j0v63" />
+    <bpmn:serviceTask id="ServiceTask_1s87b92" name="&#10;Time Out Log Failure&#10;" camunda:asyncAfter="true" camunda:expression="${MonitorSol003AdapterTerminateJobTask.timeOutLogFailure(execution)}">
+      <bpmn:incoming>SequenceFlow_1i1o9sh</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_0bcgtzj</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="SequenceFlow_0bcgtzj" sourceRef="ServiceTask_1s87b92" targetRef="EndEvent_1w3t3t0" />
+    <bpmn:serviceTask id="ServiceTask_1gms128" name="&#10;Check if operation was successful&#10;" camunda:asyncAfter="true" camunda:expression="${MonitorSol003AdapterTerminateJobTask.checkIfOperationWasSuccessful(execution)}">
+      <bpmn:incoming>SequenceFlow_1v4yr3f</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_1543qy7</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="SequenceFlow_1543qy7" sourceRef="ServiceTask_1gms128" targetRef="EndEvent_0rf1gde" />
+  </bpmn:process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="MonitorSol003AdapterTerminateJob">
+      <bpmndi:BPMNEdge id="SequenceFlow_1543qy7_di" bpmnElement="SequenceFlow_1543qy7">
+        <di:waypoint x="1023" y="118" />
+        <di:waypoint x="1102" y="118" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0bcgtzj_di" bpmnElement="SequenceFlow_0bcgtzj">
+        <di:waypoint x="1023" y="340" />
+        <di:waypoint x="1102" y="340" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1x3tbl0_di" bpmnElement="SequenceFlow_1x3tbl0">
+        <di:waypoint x="197" y="348" />
+        <di:waypoint x="301" y="348" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1i1o9sh_di" bpmnElement="SequenceFlow_1i1o9sh">
+        <di:waypoint x="842" y="340" />
+        <di:waypoint x="923" y="340" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1v4yr3f_di" bpmnElement="SequenceFlow_1v4yr3f">
+        <di:waypoint x="563" y="248" />
+        <di:waypoint x="563" y="118" />
+        <di:waypoint x="923" y="118" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
+        <dc:Bounds x="161" y="330" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="EndEvent_0rf1gde_di" bpmnElement="EndEvent_0rf1gde">
+        <dc:Bounds x="1102" y="100" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="SubProcess_19j0v63_di" bpmnElement="SubProcess_19j0v63" isExpanded="true">
+        <dc:Bounds x="301" y="248" width="523" height="200" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="SequenceFlow_153a3kp_di" bpmnElement="SequenceFlow_153a3kp">
+        <di:waypoint x="525" y="324" />
+        <di:waypoint x="609" y="324" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0is7myf_di" bpmnElement="SequenceFlow_0is7myf">
+        <di:waypoint x="659" y="324" />
+        <di:waypoint x="722" y="324" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1vmxw9g_di" bpmnElement="SequenceFlow_1vmxw9g">
+        <di:waypoint x="634" y="349" />
+        <di:waypoint x="634" y="396" />
+        <di:waypoint x="586" y="396" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0etw572_di" bpmnElement="SequenceFlow_0etw572">
+        <di:waypoint x="550" y="396" />
+        <di:waypoint x="486" y="396" />
+        <di:waypoint x="486" y="367" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0s1plu9_di" bpmnElement="SequenceFlow_0s1plu9">
+        <di:waypoint x="366" y="324" />
+        <di:waypoint x="425" y="324" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="StartEvent_01r97z2_di" bpmnElement="StartEvent_01r97z2">
+        <dc:Bounds x="330" y="306" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ExclusiveGateway_1hkl6yy_di" bpmnElement="ExclusiveGateway_1hkl6yy" isMarkerVisible="true">
+        <dc:Bounds x="609" y="299" width="50" height="50" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="IntermediateCatchEvent_1besn3n_di" bpmnElement="IntermediateCatchEvent_1besn3n">
+        <dc:Bounds x="550" y="378" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="537" y="421" width="66" height="27" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="EndEvent_1ohsce9_di" bpmnElement="EndEvent_1ohsce9">
+        <dc:Bounds x="722" y="306" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_17jlnng_di" bpmnElement="ServiceTask_17jlnng">
+        <dc:Bounds x="425" y="284" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="EndEvent_1w3t3t0_di" bpmnElement="EndEvent_1w3t3t0">
+        <dc:Bounds x="1102" y="322" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1095" y="282" width="49" height="27" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_1s87b92_di" bpmnElement="ServiceTask_1s87b92">
+        <dc:Bounds x="923" y="300" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_1gms128_di" bpmnElement="ServiceTask_1gms128">
+        <dc:Bounds x="923" y="78" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BoundaryEvent_0xiabzp_di" bpmnElement="BoundaryEvent_0xiabzp">
+        <dc:Bounds x="806" y="322" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="794" y="361" width="61" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn:definitions>
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/MonitorSol003AdapterTerminateNodeStatus.bpmn b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/MonitorSol003AdapterTerminateNodeStatus.bpmn
new file mode 100644 (file)
index 0000000..5629ce8
--- /dev/null
@@ -0,0 +1,138 @@
+<?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_1ko0frn" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
+  <bpmn:process id="MonitorSol003AdapterTerminateNodeStatus" name="MonitorSol003AdapterTerminateNodeStatus" isExecutable="true">
+    <bpmn:startEvent id="StartEvent_0k0qfjb">
+      <bpmn:outgoing>SequenceFlow_1miob62</bpmn:outgoing>
+    </bpmn:startEvent>
+    <bpmn:subProcess id="SubProcess_10wotbc">
+      <bpmn:incoming>SequenceFlow_1miob62</bpmn:incoming>
+      <bpmn:startEvent id="StartEvent_0r9qf43">
+        <bpmn:outgoing>SequenceFlow_1moaz0q</bpmn:outgoing>
+      </bpmn:startEvent>
+      <bpmn:exclusiveGateway id="ExclusiveGateway_00xtlfj" default="SequenceFlow_1luu31f">
+        <bpmn:incoming>SequenceFlow_0qvy3sn</bpmn:incoming>
+        <bpmn:outgoing>SequenceFlow_1rxbeqi</bpmn:outgoing>
+        <bpmn:outgoing>SequenceFlow_1luu31f</bpmn:outgoing>
+      </bpmn:exclusiveGateway>
+      <bpmn:intermediateCatchEvent id="IntermediateCatchEvent_0xuznv9" name="Wait between checks" camunda:asyncAfter="true">
+        <bpmn:incoming>SequenceFlow_1luu31f</bpmn:incoming>
+        <bpmn:outgoing>SequenceFlow_09t51ao</bpmn:outgoing>
+        <bpmn:timerEventDefinition id="TimerEventDefinition_0vrbrge">
+          <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT15S</bpmn:timeDuration>
+        </bpmn:timerEventDefinition>
+      </bpmn:intermediateCatchEvent>
+      <bpmn:endEvent id="EndEvent_0tei3i9">
+        <bpmn:incoming>SequenceFlow_1rxbeqi</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:serviceTask id="ServiceTask_0y71su8" name="&#10;Get node status &#10;" camunda:asyncAfter="true" camunda:expression="${MonitorSol003AdapterTerminateNodeTask.getNodeStatus(execution)}">
+        <bpmn:incoming>SequenceFlow_1moaz0q</bpmn:incoming>
+        <bpmn:incoming>SequenceFlow_09t51ao</bpmn:incoming>
+        <bpmn:outgoing>SequenceFlow_0qvy3sn</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="SequenceFlow_1rxbeqi" name="&#10;&#10;terminate vnf success&#10;&#10;" sourceRef="ExclusiveGateway_00xtlfj" targetRef="EndEvent_0tei3i9">
+        <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${execution.getVariable("deleteVnfNodeStatus")}</bpmn:conditionExpression>
+      </bpmn:sequenceFlow>
+      <bpmn:sequenceFlow id="SequenceFlow_1luu31f" sourceRef="ExclusiveGateway_00xtlfj" targetRef="IntermediateCatchEvent_0xuznv9" />
+      <bpmn:sequenceFlow id="SequenceFlow_1moaz0q" sourceRef="StartEvent_0r9qf43" targetRef="ServiceTask_0y71su8" />
+      <bpmn:sequenceFlow id="SequenceFlow_0qvy3sn" sourceRef="ServiceTask_0y71su8" targetRef="ExclusiveGateway_00xtlfj" />
+      <bpmn:sequenceFlow id="SequenceFlow_09t51ao" sourceRef="IntermediateCatchEvent_0xuznv9" targetRef="ServiceTask_0y71su8" />
+    </bpmn:subProcess>
+    <bpmn:endEvent id="EndEvent_1b83rci" name="Timeout Exception">
+      <bpmn:incoming>SequenceFlow_0uiqnl8</bpmn:incoming>
+      <bpmn:terminateEventDefinition id="TerminateEventDefinition_12rjfva" />
+    </bpmn:endEvent>
+    <bpmn:serviceTask id="ServiceTask_12qp0ty" name="&#10;Time Out Log Failure&#10;" camunda:asyncAfter="true" camunda:expression="${MonitorSol003AdapterNodeTask.timeOutLogFailue(execution)}">
+      <bpmn:incoming>SequenceFlow_0qcc5x4</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_0uiqnl8</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:boundaryEvent id="BoundaryEvent_1f5o5i9" name="Overall Wait" attachedToRef="SubProcess_10wotbc">
+      <bpmn:outgoing>SequenceFlow_0qcc5x4</bpmn:outgoing>
+      <bpmn:timerEventDefinition id="TimerEventDefinition_1t3ya63">
+        <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT3H</bpmn:timeDuration>
+      </bpmn:timerEventDefinition>
+    </bpmn:boundaryEvent>
+    <bpmn:sequenceFlow id="SequenceFlow_1miob62" sourceRef="StartEvent_0k0qfjb" targetRef="SubProcess_10wotbc" />
+    <bpmn:sequenceFlow id="SequenceFlow_0uiqnl8" sourceRef="ServiceTask_12qp0ty" targetRef="EndEvent_1b83rci" />
+    <bpmn:sequenceFlow id="SequenceFlow_0qcc5x4" sourceRef="BoundaryEvent_1f5o5i9" targetRef="ServiceTask_12qp0ty" />
+  </bpmn:process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="MonitorSol003AdapterTerminateNodeStatus">
+      <bpmndi:BPMNEdge id="SequenceFlow_0qcc5x4_di" bpmnElement="SequenceFlow_0qcc5x4">
+        <di:waypoint x="836" y="169" />
+        <di:waypoint x="917" y="169" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0uiqnl8_di" bpmnElement="SequenceFlow_0uiqnl8">
+        <di:waypoint x="1017" y="169" />
+        <di:waypoint x="1096" y="169" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1miob62_di" bpmnElement="SequenceFlow_1miob62">
+        <di:waypoint x="191" y="177" />
+        <di:waypoint x="293" y="177" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="StartEvent_0k0qfjb_di" bpmnElement="StartEvent_0k0qfjb">
+        <dc:Bounds x="155" y="159" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="SubProcess_10wotbc_di" bpmnElement="SubProcess_10wotbc" isExpanded="true">
+        <dc:Bounds x="293" y="77" width="523" height="200" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="SequenceFlow_09t51ao_di" bpmnElement="SequenceFlow_09t51ao">
+        <di:waypoint x="544" y="225" />
+        <di:waypoint x="451" y="225" />
+        <di:waypoint x="452" y="193" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0qvy3sn_di" bpmnElement="SequenceFlow_0qvy3sn">
+        <di:waypoint x="512" y="153" />
+        <di:waypoint x="603" y="153" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1moaz0q_di" bpmnElement="SequenceFlow_1moaz0q">
+        <di:waypoint x="360" y="153" />
+        <di:waypoint x="412" y="153" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1luu31f_di" bpmnElement="SequenceFlow_1luu31f">
+        <di:waypoint x="628" y="178" />
+        <di:waypoint x="628" y="225" />
+        <di:waypoint x="580" y="225" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_1rxbeqi_di" bpmnElement="SequenceFlow_1rxbeqi">
+        <di:waypoint x="653" y="153" />
+        <di:waypoint x="716" y="153" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="653" y="135" width="65" height="80" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="StartEvent_0r9qf43_di" bpmnElement="StartEvent_0r9qf43">
+        <dc:Bounds x="324" y="135" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ExclusiveGateway_00xtlfj_di" bpmnElement="ExclusiveGateway_00xtlfj" isMarkerVisible="true">
+        <dc:Bounds x="603" y="128" width="50" height="50" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="IntermediateCatchEvent_0xuznv9_di" bpmnElement="IntermediateCatchEvent_0xuznv9">
+        <dc:Bounds x="544" y="207" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="532" y="250" width="66" height="27" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="EndEvent_0tei3i9_di" bpmnElement="EndEvent_0tei3i9">
+        <dc:Bounds x="716" y="135" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_0y71su8_di" bpmnElement="ServiceTask_0y71su8">
+        <dc:Bounds x="412" y="113" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="EndEvent_1b83rci_di" bpmnElement="EndEvent_1b83rci">
+        <dc:Bounds x="1096" y="151" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1089" y="111" width="49" height="27" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_12qp0ty_di" bpmnElement="ServiceTask_12qp0ty">
+        <dc:Bounds x="917" y="129" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="BoundaryEvent_1f5o5i9_di" bpmnElement="BoundaryEvent_1f5o5i9">
+        <dc:Bounds x="800" y="151" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="788" y="190" width="61" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn:definitions>
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/TerminateNs.bpmn b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/TerminateNs.bpmn
new file mode 100644 (file)
index 0000000..36c52c8
--- /dev/null
@@ -0,0 +1,307 @@
+<?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:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_0mdda96" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
+  <bpmn:process id="TerminateNs" name="TerminateNs" isExecutable="true">
+    <bpmn:startEvent id="StartEvent_1" name="Start Process">
+      <bpmn:outgoing>SequenceFlow_16k0f61</bpmn:outgoing>
+    </bpmn:startEvent>
+    <bpmn:sequenceFlow id="SequenceFlow_16k0f61" sourceRef="StartEvent_1" targetRef="Activity_194tqy0" />
+    <bpmn:serviceTask id="Task_0opnwx0" name="Update NS Instance status to TERMINATING" camunda:expression="${TerminateNsTask.updateNsInstanceStatusToTerminating(execution)}">
+      <bpmn:incoming>Flow_04pxtdd</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_0bdznyp</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:endEvent id="EndEvent_0szswbo" name="End Process">
+      <bpmn:incoming>Flow_1pcu8aa</bpmn:incoming>
+    </bpmn:endEvent>
+    <bpmn:sequenceFlow id="SequenceFlow_0bdznyp" sourceRef="Task_0opnwx0" targetRef="Activity_1kikjaf" />
+    <bpmn:serviceTask id="Activity_194tqy0" name="Set Job Status to STARTED" camunda:asyncBefore="true" camunda:expression="${TerminateNsTask.setJobStatusToStarted(execution)}">
+      <bpmn:incoming>SequenceFlow_16k0f61</bpmn:incoming>
+      <bpmn:outgoing>Flow_04pxtdd</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_04pxtdd" sourceRef="Activity_194tqy0" targetRef="Task_0opnwx0" />
+    <bpmn:subProcess id="Activity_0pjxszh" name="Error Handling" triggeredByEvent="true">
+      <bpmn:startEvent id="Event_1rpzcl3" name="error">
+        <bpmn:outgoing>Flow_07bh7l7</bpmn:outgoing>
+        <bpmn:errorEventDefinition id="ErrorEventDefinition_0m2e0oa" />
+      </bpmn:startEvent>
+      <bpmn:endEvent id="Event_1fcw3ei" name="end">
+        <bpmn:incoming>Flow_1wa1jpl</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:serviceTask id="Activity_0ddja9m" name="Set Job Status to ERROR" camunda:asyncBefore="true" camunda:expression="${TerminateNsTask.setJobStatusToError(execution)}">
+        <bpmn:incoming>Flow_0n3dai5</bpmn:incoming>
+        <bpmn:outgoing>Flow_1wa1jpl</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_1wa1jpl" sourceRef="Activity_0ddja9m" targetRef="Event_1fcw3ei" />
+      <bpmn:sequenceFlow id="Flow_07bh7l7" sourceRef="Event_1rpzcl3" targetRef="Activity_1miy3hw" />
+      <bpmn:serviceTask id="Activity_1miy3hw" name="Update NSLcmOpOcc operation status to FAILED" camunda:asyncBefore="true" camunda:expression="${TerminateNsTask.updateNsLcmOpOccStatusToFailed(execution)}">
+        <bpmn:incoming>Flow_07bh7l7</bpmn:incoming>
+        <bpmn:outgoing>Flow_0n3dai5</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_0n3dai5" sourceRef="Activity_1miy3hw" targetRef="Activity_0ddja9m" />
+    </bpmn:subProcess>
+    <bpmn:subProcess id="Activity_0mtscwq" name="Java Exception Handling" triggeredByEvent="true">
+      <bpmn:startEvent id="Event_0lqr6al" name="error">
+        <bpmn:outgoing>Flow_05lo00r</bpmn:outgoing>
+        <bpmn:errorEventDefinition id="ErrorEventDefinition_02lwl19" errorRef="Error_0jsct8p" camunda:errorCodeVariable="BPMN_javaExpCode" camunda:errorMessageVariable="BPMN_javaExpMsg" />
+      </bpmn:startEvent>
+      <bpmn:endEvent id="Event_05ty7c4">
+        <bpmn:incoming>Flow_16aryg5</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:serviceTask id="Activity_1ezu7d4" name="Set Job Status to ERROR" camunda:asyncBefore="true" camunda:expression="${TerminateNsTask.setJobStatusToError(execution)}">
+        <bpmn:incoming>Flow_09zcw2a</bpmn:incoming>
+        <bpmn:outgoing>Flow_16aryg5</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_16aryg5" sourceRef="Activity_1ezu7d4" targetRef="Event_05ty7c4" />
+      <bpmn:sequenceFlow id="Flow_05lo00r" sourceRef="Event_0lqr6al" targetRef="Activity_17leldb" />
+      <bpmn:serviceTask id="Activity_17leldb" name="Update NSLcmOpOcc operation status to FAILED" camunda:asyncBefore="true" camunda:expression="${TerminateNsTask.updateNsLcmOpOccStatusToFailed(execution)}">
+        <bpmn:incoming>Flow_05lo00r</bpmn:incoming>
+        <bpmn:outgoing>Flow_09zcw2a</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_09zcw2a" sourceRef="Activity_17leldb" targetRef="Activity_1ezu7d4" />
+    </bpmn:subProcess>
+    <bpmn:serviceTask id="Activity_1w09i1k" name="Set Job Status to FINISHED" camunda:expression="${TerminateNsTask.setJobStatusToFinished(execution)}">
+      <bpmn:incoming>Flow_1i36dw4</bpmn:incoming>
+      <bpmn:outgoing>Flow_1pcu8aa</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_1pcu8aa" sourceRef="Activity_1w09i1k" targetRef="EndEvent_0szswbo" />
+    <bpmn:callActivity id="Activity_1b2s2wr" name="Terminate Vnfs" calledElement="TerminateVnf">
+      <bpmn:extensionElements>
+        <camunda:in source="jobId" target="jobId" />
+        <camunda:in source="NsInstanceId" target="NsInstanceId" />
+        <camunda:in source="vnfId" target="vnfId" />
+      </bpmn:extensionElements>
+      <bpmn:incoming>Flow_01ju1mj</bpmn:incoming>
+      <bpmn:outgoing>Flow_0mi4nqa</bpmn:outgoing>
+      <bpmn:multiInstanceLoopCharacteristics camunda:asyncAfter="true" camunda:collection="${nfvoNfInstIds}" camunda:elementVariable="vnfId" />
+    </bpmn:callActivity>
+    <bpmn:boundaryEvent id="Event_0rbb817" name="Overall Wait" attachedToRef="Activity_1b2s2wr">
+      <bpmn:outgoing>Flow_17zn7we</bpmn:outgoing>
+      <bpmn:timerEventDefinition id="TimerEventDefinition_13ud1f4">
+        <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">PT3H</bpmn:timeDuration>
+      </bpmn:timerEventDefinition>
+    </bpmn:boundaryEvent>
+    <bpmn:sequenceFlow id="Flow_17zn7we" sourceRef="Event_0rbb817" targetRef="Activity_16z66xm" />
+    <bpmn:serviceTask id="Activity_1kikjaf" name="Get Vnf IDs in NS" camunda:expression="${TerminateNsTask.getVnfIdsInNs(execution)}">
+      <bpmn:incoming>SequenceFlow_0bdznyp</bpmn:incoming>
+      <bpmn:outgoing>Flow_01ju1mj</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_01ju1mj" sourceRef="Activity_1kikjaf" targetRef="Activity_1b2s2wr" />
+    <bpmn:serviceTask id="Activity_16cvdbw" name="Update NS Instance status to NOT_INSTANTIATED" camunda:expression="${TerminateNsTask.updateNsInstanceStatusToNotInstantiated(execution)}">
+      <bpmn:incoming>Flow_1nieng0</bpmn:incoming>
+      <bpmn:outgoing>Flow_0xptc0r</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0xptc0r" sourceRef="Activity_16cvdbw" targetRef="Activity_0gkpdft" />
+    <bpmn:endEvent id="Event_1e4bwip">
+      <bpmn:incoming>Flow_10oprxr</bpmn:incoming>
+      <bpmn:incoming>Flow_1p21p1m</bpmn:incoming>
+      <bpmn:errorEventDefinition id="ErrorEventDefinition_0vg6v5r" errorRef="Error_0jsct8p" />
+    </bpmn:endEvent>
+    <bpmn:exclusiveGateway id="Gateway_0nxf0rv" name="is Successful?">
+      <bpmn:incoming>Flow_15m4nm1</bpmn:incoming>
+      <bpmn:outgoing>Flow_1nieng0</bpmn:outgoing>
+      <bpmn:outgoing>Flow_10oprxr</bpmn:outgoing>
+    </bpmn:exclusiveGateway>
+    <bpmn:sequenceFlow id="Flow_1nieng0" name="Yes" sourceRef="Gateway_0nxf0rv" targetRef="Activity_16cvdbw">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{isNsTerminationSuccessful}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:serviceTask id="Activity_14iwa8x" name="Check if VNF Termination was Successful" camunda:expression="${TerminateNsTask.checkIfVnfTerminationWasSuccessful(execution)}">
+      <bpmn:incoming>Flow_0mi4nqa</bpmn:incoming>
+      <bpmn:outgoing>Flow_15m4nm1</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0mi4nqa" sourceRef="Activity_1b2s2wr" targetRef="Activity_14iwa8x" />
+    <bpmn:sequenceFlow id="Flow_15m4nm1" sourceRef="Activity_14iwa8x" targetRef="Gateway_0nxf0rv" />
+    <bpmn:serviceTask id="Activity_16z66xm" name="Log TimeOut" camunda:expression="${TerminateNsTask.logTimeOut(execution)}">
+      <bpmn:incoming>Flow_17zn7we</bpmn:incoming>
+      <bpmn:outgoing>Flow_1p21p1m</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_10oprxr" name="No" sourceRef="Gateway_0nxf0rv" targetRef="Event_1e4bwip">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{not isNsTerminationSuccessful}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:sequenceFlow id="Flow_1p21p1m" sourceRef="Activity_16z66xm" targetRef="Event_1e4bwip" />
+    <bpmn:serviceTask id="Activity_0gkpdft" name="Update NSLcmOpOcc operation status to COMPLETED" camunda:expression="${TerminateNsTask.updateNsLcmOpOccStatusToCompleted(execution)}">
+      <bpmn:incoming>Flow_0xptc0r</bpmn:incoming>
+      <bpmn:outgoing>Flow_1i36dw4</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_1i36dw4" sourceRef="Activity_0gkpdft" targetRef="Activity_1w09i1k" />
+  </bpmn:process>
+  <bpmn:error id="Error_0jsct8p" name="TerminateNsProcessingException" errorCode="TERMINATE_NS_PROCESSING_EXCEPTION" />
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="TerminateNs">
+      <bpmndi:BPMNEdge id="Flow_1i36dw4_di" bpmnElement="Flow_1i36dw4">
+        <di:waypoint x="1680" y="121" />
+        <di:waypoint x="1720" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1p21p1m_di" bpmnElement="Flow_1p21p1m">
+        <di:waypoint x="1110" y="270" />
+        <di:waypoint x="1332" y="270" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_10oprxr_di" bpmnElement="Flow_10oprxr">
+        <di:waypoint x="1350" y="146" />
+        <di:waypoint x="1350" y="252" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1358" y="196" width="14" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_15m4nm1_di" bpmnElement="Flow_15m4nm1">
+        <di:waypoint x="1110" y="121" />
+        <di:waypoint x="1325" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0mi4nqa_di" bpmnElement="Flow_0mi4nqa">
+        <di:waypoint x="790" y="121" />
+        <di:waypoint x="1010" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1nieng0_di" bpmnElement="Flow_1nieng0">
+        <di:waypoint x="1375" y="121" />
+        <di:waypoint x="1430" y="121" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1393" y="103" width="19" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0xptc0r_di" bpmnElement="Flow_0xptc0r">
+        <di:waypoint x="1530" y="121" />
+        <di:waypoint x="1580" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_01ju1mj_di" bpmnElement="Flow_01ju1mj">
+        <di:waypoint x="650" y="121" />
+        <di:waypoint x="690" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_17zn7we_di" bpmnElement="Flow_17zn7we">
+        <di:waypoint x="770" y="179" />
+        <di:waypoint x="770" y="270" />
+        <di:waypoint x="1010" y="270" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1pcu8aa_di" bpmnElement="Flow_1pcu8aa">
+        <di:waypoint x="1820" y="121" />
+        <di:waypoint x="1862" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_04pxtdd_di" bpmnElement="Flow_04pxtdd">
+        <di:waypoint x="360" y="121" />
+        <di:waypoint x="410" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0bdznyp_di" bpmnElement="SequenceFlow_0bdznyp">
+        <di:waypoint x="510" y="121" />
+        <di:waypoint x="550" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_16k0f61_di" bpmnElement="SequenceFlow_16k0f61">
+        <di:waypoint x="208" y="121" />
+        <di:waypoint x="260" y="121" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
+        <dc:Bounds x="172" y="103" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="157" y="146" width="67" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_1y7xfqt_di" bpmnElement="Task_0opnwx0">
+        <dc:Bounds x="410" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="EndEvent_0szswbo_di" bpmnElement="EndEvent_0szswbo">
+        <dc:Bounds x="1862" y="103" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1848" y="79" width="63" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_194tqy0_di" bpmnElement="Activity_194tqy0">
+        <dc:Bounds x="260" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0pjxszh_di" bpmnElement="Activity_0pjxszh" isExpanded="true">
+        <dc:Bounds x="380" y="310" width="510" height="130" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="Flow_0n3dai5_di" bpmnElement="Flow_0n3dai5">
+        <di:waypoint x="600" y="373" />
+        <di:waypoint x="660" y="373" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_07bh7l7_di" bpmnElement="Flow_07bh7l7">
+        <di:waypoint x="438" y="373" />
+        <di:waypoint x="500" y="373" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1wa1jpl_di" bpmnElement="Flow_1wa1jpl">
+        <di:waypoint x="760" y="373" />
+        <di:waypoint x="822" y="373" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="Event_1rpzcl3_di" bpmnElement="Event_1rpzcl3">
+        <dc:Bounds x="402" y="355" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="408" y="398" width="24" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_1fcw3ei_di" bpmnElement="Event_1fcw3ei">
+        <dc:Bounds x="822" y="355" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="832" y="397" width="19" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0ddja9m_di" bpmnElement="Activity_0ddja9m">
+        <dc:Bounds x="660" y="333" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1miy3hw_di" bpmnElement="Activity_1miy3hw">
+        <dc:Bounds x="500" y="333" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0mtscwq_di" bpmnElement="Activity_0mtscwq" isExpanded="true">
+        <dc:Bounds x="380" y="480" width="510" height="130" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="Flow_09zcw2a_di" bpmnElement="Flow_09zcw2a">
+        <di:waypoint x="600" y="543" />
+        <di:waypoint x="660" y="543" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_05lo00r_di" bpmnElement="Flow_05lo00r">
+        <di:waypoint x="438" y="543" />
+        <di:waypoint x="500" y="543" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_16aryg5_di" bpmnElement="Flow_16aryg5">
+        <di:waypoint x="760" y="543" />
+        <di:waypoint x="822" y="543" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="Event_0lqr6al_di" bpmnElement="Event_0lqr6al">
+        <dc:Bounds x="402" y="525" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="409" y="568" width="24" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_05ty7c4_di" bpmnElement="Event_05ty7c4">
+        <dc:Bounds x="822" y="525" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1ezu7d4_di" bpmnElement="Activity_1ezu7d4">
+        <dc:Bounds x="660" y="503" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_17leldb_di" bpmnElement="Activity_17leldb">
+        <dc:Bounds x="500" y="503" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1w09i1k_di" bpmnElement="Activity_1w09i1k">
+        <dc:Bounds x="1720" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1xjmizv_di" bpmnElement="Activity_1b2s2wr">
+        <dc:Bounds x="690" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1kikjaf_di" bpmnElement="Activity_1kikjaf">
+        <dc:Bounds x="550" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_16cvdbw_di" bpmnElement="Activity_16cvdbw">
+        <dc:Bounds x="1430" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_16umj30_di" bpmnElement="Event_1e4bwip">
+        <dc:Bounds x="1332" y="252" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Gateway_0nxf0rv_di" bpmnElement="Gateway_0nxf0rv" isMarkerVisible="true">
+        <dc:Bounds x="1325" y="96" width="50" height="50" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1320" y="66" width="71" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_14iwa8x_di" bpmnElement="Activity_14iwa8x">
+        <dc:Bounds x="1010" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_16z66xm_di" bpmnElement="Activity_16z66xm">
+        <dc:Bounds x="1010" y="230" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0gkpdft_di" bpmnElement="Activity_0gkpdft">
+        <dc:Bounds x="1580" y="81" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_0rbb817_di" bpmnElement="Event_0rbb817">
+        <dc:Bounds x="752" y="143" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="700" y="183" width="60" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn:definitions>
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/TerminateVnf.bpmn b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/main/resources/TerminateVnf.bpmn
new file mode 100644 (file)
index 0000000..994933f
--- /dev/null
@@ -0,0 +1,171 @@
+<?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:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1uf6nd9" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.2.0">
+  <bpmn:process id="TerminateVnf" name="TerminateVnf" isExecutable="true">
+    <bpmn:startEvent id="StartEvent_1">
+      <bpmn:outgoing>Flow_02bjz2v</bpmn:outgoing>
+    </bpmn:startEvent>
+    <bpmn:sequenceFlow id="Flow_02bjz2v" sourceRef="StartEvent_1" targetRef="Activity_1cluqgp" />
+    <bpmn:endEvent id="Event_14qdixj">
+      <bpmn:incoming>Flow_1egtf3w</bpmn:incoming>
+    </bpmn:endEvent>
+    <bpmn:serviceTask id="Activity_1cluqgp" name="Check If NF Instance (VNF) exists in DB" camunda:expression="${TerminateVnfTask.checkIfNfInstanceExistsInDb(execution)}">
+      <bpmn:incoming>Flow_02bjz2v</bpmn:incoming>
+      <bpmn:outgoing>Flow_123uagz</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_123uagz" sourceRef="Activity_1cluqgp" targetRef="Activity_17vixcx" />
+    <bpmn:serviceTask id="ServiceTask_0iry5yw" name="&#10;Invoke VNFM Adapter&#10;" camunda:asyncAfter="true" camunda:expression="${TerminateVnfTask.invokeTerminateRequest(execution)}">
+      <bpmn:incoming>Flow_0in3hgl</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_0xzptc2</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:callActivity id="CallActivity_1yilxx3" name="Monitor Sol003 Adapter Terminate Job" calledElement="MonitorSol003AdapterTerminateJob">
+      <bpmn:extensionElements>
+        <camunda:in source="jobId" target="jobId" />
+        <camunda:in source="deleteVnfResponse" target="deleteVnfResponse" />
+      </bpmn:extensionElements>
+      <bpmn:incoming>SequenceFlow_0xzptc2</bpmn:incoming>
+      <bpmn:outgoing>SequenceFlow_053tvct</bpmn:outgoing>
+    </bpmn:callActivity>
+    <bpmn:sequenceFlow id="SequenceFlow_0xzptc2" sourceRef="ServiceTask_0iry5yw" targetRef="CallActivity_1yilxx3" />
+    <bpmn:sequenceFlow id="SequenceFlow_053tvct" sourceRef="CallActivity_1yilxx3" targetRef="Activity_0wgjtoy" />
+    <bpmn:serviceTask id="Activity_0g3dip7" name="Update NF Instance (VNF) Status to NOT_INSTANTIATED" camunda:expression="${TerminateVnfTask.updateNfInstanceStatusToNotInstantiated(execution)}">
+      <bpmn:incoming>Flow_1rw8pwu</bpmn:incoming>
+      <bpmn:outgoing>Flow_0srinh7</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0srinh7" sourceRef="Activity_0g3dip7" targetRef="Activity_1vptrrr" />
+    <bpmn:subProcess id="Activity_0qtgdm9" name="Error Handling" triggeredByEvent="true">
+      <bpmn:startEvent id="Event_08zcwc2" name="error">
+        <bpmn:outgoing>Flow_06q1m6i</bpmn:outgoing>
+        <bpmn:errorEventDefinition id="ErrorEventDefinition_1ppvn77" />
+      </bpmn:startEvent>
+      <bpmn:endEvent id="Event_1wkm29u" name="end">
+        <bpmn:incoming>Flow_0anjylz</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:serviceTask id="Activity_0ltxcii" name="Update NF Instance (VNF) Status to FAILED" camunda:asyncBefore="true" camunda:expression="${TerminateVnfTask.updateNfInstanceStatusToFailed(execution)}">
+        <bpmn:incoming>Flow_06q1m6i</bpmn:incoming>
+        <bpmn:outgoing>Flow_0anjylz</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_06q1m6i" sourceRef="Event_08zcwc2" targetRef="Activity_0ltxcii" />
+      <bpmn:sequenceFlow id="Flow_0anjylz" sourceRef="Activity_0ltxcii" targetRef="Event_1wkm29u" />
+    </bpmn:subProcess>
+    <bpmn:callActivity id="Activity_0wgjtoy" name="Monitor Sol003 Adapter Terminate Node Status" calledElement="MonitorSol003AdapterTerminateNodeStatus">
+      <bpmn:extensionElements>
+        <camunda:in source="NF_INST_ID" target="NF_INST_ID" />
+        <camunda:in source="deleteVnfResponse" target="deleteVnfResponse" />
+      </bpmn:extensionElements>
+      <bpmn:incoming>SequenceFlow_053tvct</bpmn:incoming>
+      <bpmn:outgoing>Flow_1wfvdmt</bpmn:outgoing>
+    </bpmn:callActivity>
+    <bpmn:sequenceFlow id="Flow_1wfvdmt" sourceRef="Activity_0wgjtoy" targetRef="Activity_0lulaof" />
+    <bpmn:sequenceFlow id="Flow_1egtf3w" sourceRef="Activity_1vptrrr" targetRef="Event_14qdixj" />
+    <bpmn:serviceTask id="Activity_1vptrrr" name="Delete NF Instance (VNF) record from DB" camunda:expression="${TerminateVnfTask.deleteNfInstanceFromDb(execution)}">
+      <bpmn:incoming>Flow_0srinh7</bpmn:incoming>
+      <bpmn:outgoing>Flow_1egtf3w</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0in3hgl" sourceRef="Activity_17vixcx" targetRef="ServiceTask_0iry5yw" />
+    <bpmn:serviceTask id="Activity_17vixcx" name="Update NF Instance (VNF) Status to TERMINATING" camunda:expression="${TerminateVnfTask.updateNfInstanceStatusToTerminating(execution)}">
+      <bpmn:incoming>Flow_123uagz</bpmn:incoming>
+      <bpmn:outgoing>Flow_0in3hgl</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:serviceTask id="Activity_0lulaof" name="Delete Generic VNF From AAI" camunda:expression="${TerminateVnfTask.deleteGenericVnfFromAai(execution)}">
+      <bpmn:incoming>Flow_1wfvdmt</bpmn:incoming>
+      <bpmn:outgoing>Flow_1rw8pwu</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_1rw8pwu" sourceRef="Activity_0lulaof" targetRef="Activity_0g3dip7" />
+  </bpmn:process>
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="TerminateVnf">
+      <bpmndi:BPMNEdge id="Flow_0in3hgl_di" bpmnElement="Flow_0in3hgl">
+        <di:waypoint x="490" y="117" />
+        <di:waypoint x="540" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1egtf3w_di" bpmnElement="Flow_1egtf3w">
+        <di:waypoint x="1370" y="117" />
+        <di:waypoint x="1432" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1wfvdmt_di" bpmnElement="Flow_1wfvdmt">
+        <di:waypoint x="940" y="117" />
+        <di:waypoint x="990" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0srinh7_di" bpmnElement="Flow_0srinh7">
+        <di:waypoint x="1230" y="117" />
+        <di:waypoint x="1270" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_053tvct_di" bpmnElement="SequenceFlow_053tvct">
+        <di:waypoint x="790" y="117" />
+        <di:waypoint x="840" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="SequenceFlow_0xzptc2_di" bpmnElement="SequenceFlow_0xzptc2">
+        <di:waypoint x="640" y="117" />
+        <di:waypoint x="690" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_123uagz_di" bpmnElement="Flow_123uagz">
+        <di:waypoint x="350" y="117" />
+        <di:waypoint x="390" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_02bjz2v_di" bpmnElement="Flow_02bjz2v">
+        <di:waypoint x="215" y="117" />
+        <di:waypoint x="250" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1rw8pwu_di" bpmnElement="Flow_1rw8pwu">
+        <di:waypoint x="1090" y="117" />
+        <di:waypoint x="1130" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
+        <dc:Bounds x="179" y="99" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1cluqgp_di" bpmnElement="Activity_1cluqgp">
+        <dc:Bounds x="250" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="ServiceTask_0iry5yw_di" bpmnElement="ServiceTask_0iry5yw">
+        <dc:Bounds x="540" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="CallActivity_1yilxx3_di" bpmnElement="CallActivity_1yilxx3">
+        <dc:Bounds x="690" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0wgjtoy_di" bpmnElement="Activity_0wgjtoy">
+        <dc:Bounds x="840" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0lulaof_di" bpmnElement="Activity_0lulaof">
+        <dc:Bounds x="990" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0g3dip7_di" bpmnElement="Activity_0g3dip7">
+        <dc:Bounds x="1130" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0fsaanz_di" bpmnElement="Activity_1vptrrr">
+        <dc:Bounds x="1270" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_14qdixj_di" bpmnElement="Event_14qdixj">
+        <dc:Bounds x="1432" y="99" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0qtgdm9_di" bpmnElement="Activity_0qtgdm9" isExpanded="true">
+        <dc:Bounds x="430" y="270" width="438" height="130" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="Flow_0anjylz_di" bpmnElement="Flow_0anjylz">
+        <di:waypoint x="680" y="333" />
+        <di:waypoint x="812" y="333" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_06q1m6i_di" bpmnElement="Flow_06q1m6i">
+        <di:waypoint x="488" y="333" />
+        <di:waypoint x="580" y="333" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="Event_08zcwc2_di" bpmnElement="Event_08zcwc2">
+        <dc:Bounds x="452" y="315" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="458" y="358" width="24" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_1wkm29u_di" bpmnElement="Event_1wkm29u">
+        <dc:Bounds x="812" y="315" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="822" y="357" width="19" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0ltxcii_di" bpmnElement="Activity_0ltxcii">
+        <dc:Bounds x="580" y="293" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_08pcuhq_di" bpmnElement="Activity_17vixcx">
+        <dc:Bounds x="390" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn:definitions>
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/test/java/org/onap/so/etsi/nfvo/ns/workflow/engine/tasks/MonitorSol003AdapterTerminateJobTaskTest.java b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/test/java/org/onap/so/etsi/nfvo/ns/workflow/engine/tasks/MonitorSol003AdapterTerminateJobTaskTest.java
new file mode 100644 (file)
index 0000000..13fff6d
--- /dev/null
@@ -0,0 +1,148 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.etsi.nfvo.ns.workflow.engine.tasks;
+
+import com.google.gson.Gson;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
+import org.camunda.bpm.engine.history.HistoricVariableInstance;
+import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.DeleteVnfResponse;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStateEnum;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.QueryJobResponse;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.BaseTest;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.CamundaVariableNameConstants;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.GsonProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.GsonHttpMessageConverter;
+import org.springframework.test.web.client.MockRestServiceServer;
+import org.springframework.web.client.RestTemplate;
+import java.util.HashMap;
+import java.util.Map;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStateEnum.COMPLETED;
+import static org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStateEnum.PROCESSING;
+import static org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStatusRetrievalStatusEnum.STATUS_FOUND;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.vnfm.Sol003AdapterConfiguration.SOL003_ADAPTER_REST_TEMPLATE_BEAN;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+public class MonitorSol003AdapterTerminateJobTaskTest extends BaseTest {
+
+    private static final String MONITOR_SOL003_ADAPTER_TERMINATE_JOB_WORKFLOW = "MonitorSol003AdapterTerminateJob";
+
+    @Autowired
+    @Qualifier(SOL003_ADAPTER_REST_TEMPLATE_BEAN)
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private GsonProvider gsonProvider;
+
+    private MockRestServiceServer mockRestServiceServer;
+    private Gson gson;
+
+    @Before
+    public void before() {
+        wireMockServer.resetAll();
+
+        final MockRestServiceServer.MockRestServiceServerBuilder builder = MockRestServiceServer.bindTo(restTemplate);
+        builder.ignoreExpectOrder(true);
+        mockRestServiceServer = builder.build();
+
+        gson = gsonProvider.getGson();
+        restTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gson));
+    }
+
+
+    @Test
+    public void testMonitorSol003AdapterTerminateJobTaskWorkflow_SuccessfulCase() throws InterruptedException {
+        mockRestServiceServer.expect(requestTo(SOL003_ADAPTER_ENDPOINT_URL + "/jobs/" + RANDOM_JOB_ID))
+                .andExpect(method(HttpMethod.GET))
+                .andRespond(withSuccess(gson.toJson(getQueryJobResponse(COMPLETED)), MediaType.APPLICATION_JSON));
+
+        final ProcessInstance processInstance = executeWorkflow(MONITOR_SOL003_ADAPTER_TERMINATE_JOB_WORKFLOW,
+                RANDOM_JOB_ID, getVariables(RANDOM_JOB_ID, new DeleteVnfResponse().jobId(RANDOM_JOB_ID)));
+        assertTrue(waitForProcessInstanceToFinish(processInstance.getProcessInstanceId()));
+
+        final HistoricProcessInstance historicProcessInstance =
+                getHistoricProcessInstance(processInstance.getProcessInstanceId());
+        assertNotNull(historicProcessInstance);
+        assertEquals(HistoricProcessInstance.STATE_COMPLETED, historicProcessInstance.getState());
+
+        final HistoricVariableInstance nsResponseVariable = getVariable(processInstance.getProcessInstanceId(),
+                CamundaVariableNameConstants.OPERATION_STATUS_PARAM_NAME);
+        assertNotNull(nsResponseVariable);
+        assertEquals(COMPLETED, nsResponseVariable.getValue());
+    }
+
+    @Test
+    public void testMonitorSol003AdapterTerminateJobTaskWorkflow_SuccessfulCaseFollowingProcessingDelay()
+            throws InterruptedException {
+        mockRestServiceServer.expect(requestTo(SOL003_ADAPTER_ENDPOINT_URL + "/jobs/" + RANDOM_JOB_ID))
+                .andExpect(method(HttpMethod.GET))
+                .andRespond(withSuccess(gson.toJson(getQueryJobResponse(PROCESSING)), MediaType.APPLICATION_JSON));
+        mockRestServiceServer.expect(requestTo(SOL003_ADAPTER_ENDPOINT_URL + "/jobs/" + RANDOM_JOB_ID))
+                .andExpect(method(HttpMethod.GET))
+                .andRespond(withSuccess(gson.toJson(getQueryJobResponse(PROCESSING)), MediaType.APPLICATION_JSON));
+        mockRestServiceServer.expect(requestTo(SOL003_ADAPTER_ENDPOINT_URL + "/jobs/" + RANDOM_JOB_ID))
+                .andExpect(method(HttpMethod.GET))
+                .andRespond(withSuccess(gson.toJson(getQueryJobResponse(COMPLETED)), MediaType.APPLICATION_JSON));
+
+        final ProcessInstance processInstance = executeWorkflow(MONITOR_SOL003_ADAPTER_TERMINATE_JOB_WORKFLOW,
+                RANDOM_JOB_ID, getVariables(RANDOM_JOB_ID, new DeleteVnfResponse().jobId(RANDOM_JOB_ID)));
+        assertTrue(waitForProcessInstanceToFinish(processInstance.getProcessInstanceId()));
+
+        final HistoricProcessInstance historicProcessInstance =
+                getHistoricProcessInstance(processInstance.getProcessInstanceId());
+        assertNotNull(historicProcessInstance);
+        assertEquals(HistoricProcessInstance.STATE_COMPLETED, historicProcessInstance.getState());
+
+        final HistoricVariableInstance nsResponseVariable = getVariable(processInstance.getProcessInstanceId(),
+                CamundaVariableNameConstants.OPERATION_STATUS_PARAM_NAME);
+        assertNotNull(nsResponseVariable);
+        assertEquals(COMPLETED, nsResponseVariable.getValue());
+    }
+
+    private QueryJobResponse getQueryJobResponse(final OperationStateEnum operationState) {
+        return new QueryJobResponse().id(RANDOM_JOB_ID).operationState(operationState)
+                .operationStatusRetrievalStatus(STATUS_FOUND);
+    }
+
+    private Map<String, Object> getVariables(final String jobId, final DeleteVnfResponse deleteVnfResponse) {
+        final Map<String, Object> variables = new HashMap<>();
+        variables.put(CamundaVariableNameConstants.JOB_ID_PARAM_NAME, jobId);
+        variables.put(CamundaVariableNameConstants.DELETE_VNF_RESPONSE_PARAM_NAME, deleteVnfResponse);
+
+        return variables;
+    }
+
+}
diff --git a/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/test/java/org/onap/so/etsi/nfvo/ns/workflow/engine/tasks/TerminateNsTaskTest.java b/so-etsi-nfvo/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/src/test/java/org/onap/so/etsi/nfvo/ns/workflow/engine/tasks/TerminateNsTaskTest.java
new file mode 100644 (file)
index 0000000..14e5b1c
--- /dev/null
@@ -0,0 +1,232 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2020 Nordix Foundation.
+ * ================================================================================
+ * 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.etsi.nfvo.ns.workflow.engine.tasks;
+
+import com.google.gson.Gson;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
+import org.hamcrest.text.MatchesPattern;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.DeleteVnfResponse;
+import org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStatusRetrievalStatusEnum;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.BaseTest;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.GsonProvider;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.exceptions.NsRequestProcessingException;
+import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.service.JobExecutorService;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoJob;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNfInst;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNsInst;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpOcc;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.OperationStateEnum;
+import org.onap.so.etsi.nfvo.ns.lcm.database.beans.State;
+import org.onap.so.etsi.nfvo.ns.lcm.model.TerminateNsRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.GsonHttpMessageConverter;
+import org.springframework.test.web.client.MockRestServiceServer;
+import org.springframework.web.client.RestTemplate;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import static com.github.tomakehurst.wiremock.client.WireMock.delete;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.ok;
+import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.etsicatalog.EtsiCatalogServiceProviderConfiguration.ETSI_CATALOG_REST_TEMPLATE_BEAN;
+import static org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.extclients.vnfm.Sol003AdapterConfiguration.SOL003_ADAPTER_REST_TEMPLATE_BEAN;
+import static org.springframework.test.web.client.ExpectedCount.times;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
+import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
+
+/**
+ * @author Andrew Lamb (andrew.a.lamb@est.tech)
+ *
+ */
+public class TerminateNsTaskTest extends BaseTest {
+
+    @Autowired
+    @Qualifier(ETSI_CATALOG_REST_TEMPLATE_BEAN)
+    private RestTemplate etsiCatalogRestTemplate;
+
+    @Autowired
+    @Qualifier(SOL003_ADAPTER_REST_TEMPLATE_BEAN)
+    private RestTemplate sol003AdapterRestTemplate;
+
+    private MockRestServiceServer mockEtsiCatalogRestServiceServer;
+
+    private MockRestServiceServer mockSol003AdapterRestServiceServer;
+
+    @Autowired
+    private JobExecutorService objUnderTest;
+
+    @Autowired
+    private GsonProvider gsonProvider;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    private Gson gson;
+
+    @Before
+    public void before() {
+        wireMockServer.resetAll();
+        gson = gsonProvider.getGson();
+
+        mockEtsiCatalogRestServiceServer =
+                MockRestServiceServer.bindTo(etsiCatalogRestTemplate).ignoreExpectOrder(true).build();
+        mockSol003AdapterRestServiceServer =
+                MockRestServiceServer.bindTo(sol003AdapterRestTemplate).ignoreExpectOrder(true).build();
+
+        etsiCatalogRestTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gson));
+        sol003AdapterRestTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gson));
+
+    }
+
+    @After
+    public void after() {
+        wireMockServer.resetAll();
+        mockEtsiCatalogRestServiceServer.reset();
+    }
+
+    @Test
+    public void testRunTerminateNsJob_timeSetInTerminateRequest_throwsNsRequestProcessingException() {
+        final String nsInstanceId = UUID.randomUUID().toString();
+        final TerminateNsRequest terminateNsRequest = new TerminateNsRequest().terminationTime(LocalDateTime.now());
+        final String message = "TerminateNsRequest received with terminateTime: "
+                + terminateNsRequest.getTerminationTime()
+                + "\nOnly immediate Terminate requests are currently supported \n(i.e., terminateTime field must not be set).";
+        expectedException.expect(NsRequestProcessingException.class);
+        expectedException.expectMessage(message);
+        objUnderTest.runTerminateNsJob(nsInstanceId, terminateNsRequest);
+    }
+
+    @Test
+    public void testRunTerminateNsJob_NsInstNotInDb_throwsNsRequestProcessingException() {
+        final String nsInstanceId = UUID.randomUUID().toString();
+        final TerminateNsRequest terminateNsRequest = new TerminateNsRequest();
+        final String message = "No matching NS Instance for id: " + nsInstanceId + " found in database.";
+        assertThat(databaseServiceProvider.getNfvoNsInst(nsInstanceId)).isEmpty();
+        expectedException.expect(NsRequestProcessingException.class);
+        expectedException.expectMessage(message);
+        objUnderTest.runTerminateNsJob(nsInstanceId, terminateNsRequest);
+    }
+
+    @Test
+    public void testTerminateNsTask_SuccessfulCase() throws InterruptedException, IOException {
+        final String nsInstanceId = UUID.randomUUID().toString();
+        addDummyNsToDatabase(nsInstanceId);
+        mockSol003AdapterEndpoints();
+        mockAAIEndpoints();
+
+        final String nsLcmOpOccId = objUnderTest.runTerminateNsJob(nsInstanceId, new TerminateNsRequest());
+
+        final Optional<NfvoJob> optional = getJobByResourceId(nsInstanceId);
+        assertTrue(optional.isPresent());
+        final NfvoJob nfvoJob = optional.get();
+
+        // Confirm Process finishes in STATE_COMPLETED
+        assertTrue(waitForProcessInstanceToFinish(nfvoJob.getProcessInstanceId()));
+        final HistoricProcessInstance historicProcessInstance =
+                getHistoricProcessInstance(nfvoJob.getProcessInstanceId());
+        assertNotNull(historicProcessInstance);
+        assertEquals(HistoricProcessInstance.STATE_COMPLETED, historicProcessInstance.getState());
+
+        // Confirm NS Instance set to NOT_INSTANTIATED and related NF Instances Deleted
+        final Optional<NfvoNsInst> optionalNfvoNsInst = databaseServiceProvider.getNfvoNsInst(nsInstanceId);
+        assertTrue(optionalNfvoNsInst.isPresent());
+        final NfvoNsInst nfvoNsInst = optionalNfvoNsInst.get();
+        assertEquals(State.NOT_INSTANTIATED, nfvoNsInst.getStatus());
+        final List<NfvoNfInst> nfvoNfInsts = databaseServiceProvider.getNfvoNfInstByNsInstId(nsInstanceId);
+        assertTrue(nfvoNfInsts.isEmpty());
+
+        // Confirm NS LCM OP OCC Job set to Completed
+        final Optional<NsLcmOpOcc> optionalNsLcmOpOcc = databaseServiceProvider.getNsLcmOpOcc(nsLcmOpOccId);
+        assertTrue(optionalNsLcmOpOcc.isPresent());
+        final NsLcmOpOcc nsLcmOpOcc = optionalNsLcmOpOcc.get();
+        assertEquals(OperationStateEnum.COMPLETED, nsLcmOpOcc.getOperationState());
+    }
+
+    private void addDummyNsToDatabase(final String nsInstanceId) {
+        final String nsPackageId = UUID.randomUUID().toString();
+        final NfvoNsInst nfvoNsInst =
+                new NfvoNsInst().nsInstId(nsInstanceId).name("nsName").nsPackageId(nsPackageId).nsdId("nsdId")
+                        .nsdInvariantId("nsdId").status(State.INSTANTIATED).statusUpdatedTime(LocalDateTime.now());
+        databaseServiceProvider.saveNfvoNsInst(nfvoNsInst);
+        addDummyNfToDatabase(nfvoNsInst);
+        addDummyNfToDatabase(nfvoNsInst);
+        addDummyNfToDatabase(nfvoNsInst);
+    }
+
+    private void addDummyNfToDatabase(final NfvoNsInst nfvoNsInst) {
+        final LocalDateTime localDateTime = LocalDateTime.now();
+        final String nfPackageId = UUID.randomUUID().toString();
+        final NfvoNfInst nfvoNfInst =
+                new NfvoNfInst().status(State.INSTANTIATED).createTime(localDateTime).lastUpdateTime(localDateTime)
+                        .name("nfName").vnfdId("vnfdId").packageId(nfPackageId).nfvoNsInst(nfvoNsInst);
+        databaseServiceProvider.saveNfvoNfInst(nfvoNfInst);
+    }
+
+    private void mockSol003AdapterEndpoints() {
+        final int numTimes = 3;
+
+        mockSol003AdapterRestServiceServer
+                .expect(times(numTimes),
+                        requestTo(MatchesPattern.matchesPattern(SOL003_ADAPTER_ENDPOINT_URL + "/vnfs/.*")))
+                .andExpect(method(HttpMethod.DELETE))
+                .andRespond(withSuccess(gson.toJson(new DeleteVnfResponse().jobId(UUID.randomUUID().toString())),
+                        MediaType.APPLICATION_JSON));
+
+        mockSol003AdapterRestServiceServer
+                .expect(times(numTimes),
+                        requestTo(MatchesPattern.matchesPattern(SOL003_ADAPTER_ENDPOINT_URL + "/jobs/.*")))
+                .andExpect(method(HttpMethod.GET))
+                .andRespond(withSuccess(gson.toJson(
+                        new org.onap.so.adapters.etsisol003adapter.lcm.v1.model.QueryJobResponse().operationState(
+                                org.onap.so.adapters.etsisol003adapter.lcm.v1.model.OperationStateEnum.COMPLETED)
+                                .operationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND)),
+                        MediaType.APPLICATION_JSON));
+    }
+
+    private void mockAAIEndpoints() {
+        final String modelEndpoint = "/aai/v[0-9]+/network/generic-vnfs/generic-vnf/" + UUID_REGEX;
+        final String resourceVersion = "12345";
+
+        final String body =
+                "{\"resource-version\": \"" + resourceVersion + "\",\n\"orchestration-status\": \"Assigned\"}";
+        wireMockServer.stubFor(get(urlMatching(modelEndpoint)).willReturn(ok()).willReturn(okJson(body)));
+
+        wireMockServer.stubFor(
+                delete(urlMatching(modelEndpoint + "\\?resource-version=" + resourceVersion)).willReturn(ok()));
+    }
+
+}
index cb8f920..c47bbdb 100644 (file)
@@ -216,7 +216,7 @@ public class NsLcmOpOcc {
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder();
-        sb.append("class NfvoNsInst {\n");
+        sb.append("class NsLcmOpOcc {\n");
         sb.append("    id: ").append(toIndentedString(id)).append("\n");
         sb.append("    operationState: ").append(toIndentedString(operationState)).append("\n");
         sb.append("    stateEnteredTime: ").append(toIndentedString(stateEnteredTime)).append("\n");
index 3682425..762408a 100644 (file)
@@ -127,6 +127,16 @@ public class DatabaseServiceProvider {
         return nfvoNfInstRepository.findByNfInstId(nfInstId);
     }
 
+    public boolean isNfInstExists(final String nfInstId) {
+        logger.info("Checking if NfvoNfInst entry exists in database using nfInstId: {}", nfInstId);
+        return nfvoNfInstRepository.findByNfInstId(nfInstId).isPresent();
+    }
+
+    public void deleteNfvoNfInst(final String nfInstId) {
+        logger.info("Deleting NfvoNfInst with nfInstId: {} from database", nfInstId);
+        nfvoNfInstRepository.deleteById(nfInstId);
+    }
+
     public boolean addNSLcmOpOcc(final NsLcmOpOcc nsLcmOpOcc) {
         logger.info("Adding NSLcmOpOcc: {} to database", nsLcmOpOcc);
         return nsLcmOpOccRepository.save(nsLcmOpOcc) != null;
index da1649d..80ec604 100644 (file)
@@ -45,7 +45,7 @@ public class EtsiSoNsLcmManagerUrlProvider {
                 + nsInstanceId);
     }
 
-    public URI getInstantiatedOccUri(final String nsLcmOpOccId) {
+    public URI getNsLcmOpOccUri(final String nsLcmOpOccId) {
         return URI.create(etsiNsLcmManagerEndpoint + Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL + "/ns_lcm_op_occs/"
                 + nsLcmOpOccId);
     }
index 792ffdd..2ebf55f 100644 (file)
@@ -27,6 +27,7 @@ import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.service.JobExecutorService;
 import org.onap.so.etsi.nfvo.ns.lcm.model.CreateNsRequest;
 import org.onap.so.etsi.nfvo.ns.lcm.model.InstantiateNsRequest;
 import org.onap.so.etsi.nfvo.ns.lcm.model.NsInstancesNsInstance;
+import org.onap.so.etsi.nfvo.ns.lcm.model.TerminateNsRequest;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -70,8 +71,15 @@ public class NsLifeCycleManager {
                 instantiateNsRequest, nsInstanceId);
         final String nsLcmOpOccId = jobExecutorService.runInstantiateNsJob(nsInstanceId, instantiateNsRequest);
 
-        return etsiSoNsLcmManagerUrlProvider.getInstantiatedOccUri(nsLcmOpOccId);
+        return etsiSoNsLcmManagerUrlProvider.getNsLcmOpOccUri(nsLcmOpOccId);
 
     }
 
+    public URI terminateNs(final String nsInstanceId, final TerminateNsRequest terminateNsRequest) {
+        logger.info("Will execute Terminate Ns for TerminateNsRequest: {} and nsInstanceId: {}", terminateNsRequest,
+                nsInstanceId);
+        final String nsLcmOpOccId = jobExecutorService.runTerminateNsJob(nsInstanceId, terminateNsRequest);
+
+        return etsiSoNsLcmManagerUrlProvider.getNsLcmOpOccUri(nsLcmOpOccId);
+    }
 }
index 87ec842..cfda89f 100644 (file)
@@ -72,8 +72,9 @@ public class NsLifecycleManagementController {
      * @param globalCustomerId The global customer ID
      * @param serviceType The service type
      * @param createNsRequest create network service request (see clause 6.5.2.9)
-     * @return "201 Created" response containing a representation of the NS instance resource {@link NsInstance} just
-     *         created by the NFVO, and provides the URI of the newly-created resource in the "Location:" HTTP header
+     * @return "201 Created" response containing a representation of the NS instance resource
+     *         {@link NsInstancesNsInstance} just created by the NFVO, and provides the URI of the newly-created
+     *         resource in the "Location:" HTTP header
      */
     @PostMapping(value = "/ns_instances", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML},
             consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@@ -145,7 +146,10 @@ public class NsLifecycleManagementController {
     public ResponseEntity<?> terminateNs(@PathVariable("nsInstanceId") final String nsInstanceId,
             @RequestBody final TerminateNsRequest terminateNsRequest) {
         logger.debug("Received terminate NS request: {}\n with nsInstanceId: {}", terminateNsRequest, nsInstanceId);
-        return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).body("Operation is not supported yet");
+        final URI resourceUri = nsLifeCycleManager.terminateNs(nsInstanceId, terminateNsRequest);
+        logger.info("{} Ns Terminate started successfully. Resource Operation Occurrence uri: {}", nsInstanceId,
+                resourceUri);
+        return ResponseEntity.accepted().location(resourceUri).build();
     }
 
 }
index 81c4e8f..4b11952 100644 (file)
@@ -77,7 +77,7 @@ public class NsLifecycleManagementControllerTest {
     private static final String GLOBAL_CUSTOMER_ID = UUID.randomUUID().toString();
     private static final String EXPECTED_CREATE_REQ_LOCATION_URL =
             EXPECTED_BASE_URL + "/ns_instances/" + RANDOM_NS_INST_ID;
-    private static final String EXPECTED_INSTANTIATE_REQ_LOCATION_URL =
+    private static final String EXPECTED_NS_LCM_OP_OCC_REQ_LOCATION_URL =
             EXPECTED_BASE_URL + "/ns_lcm_op_occs/" + RANDOM_NS_LCM_OP_OCC_ID;
 
     @LocalServerPort
@@ -197,7 +197,7 @@ public class NsLifecycleManagementControllerTest {
         assertTrue(httpHeaders.containsKey(HttpHeaders.LOCATION));
         final List<String> actual = httpHeaders.get(HttpHeaders.LOCATION);
         assertEquals(1, actual.size());
-        assertEquals(EXPECTED_INSTANTIATE_REQ_LOCATION_URL, actual.get(0));
+        assertEquals(EXPECTED_NS_LCM_OP_OCC_REQ_LOCATION_URL, actual.get(0));
     }
 
     @Test
@@ -218,17 +218,43 @@ public class NsLifecycleManagementControllerTest {
     }
 
     @Test
-    public void testTerminateNs_ValidInstantiateNsRequest() {
-        final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + UUID.randomUUID().toString() + "/terminate";
-        final HttpEntity<?> request = new HttpEntity<>(getTerminateNsRequest());
+    public void testTerminateNs_ValidTerminateNsRequest_Success() {
+        final TerminateNsRequest terminateNsRequest = getTerminateNsRequest();
+        when(mockedJobExecutorService.runTerminateNsJob(eq(RANDOM_NS_INST_ID), eq(terminateNsRequest)))
+                .thenReturn(RANDOM_NS_LCM_OP_OCC_ID);
+
+        final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + RANDOM_NS_INST_ID + "/terminate";
+        final HttpEntity<?> request = new HttpEntity<>(terminateNsRequest);
         final ResponseEntity<Void> responseEntity =
                 testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, Void.class);
-        assertEquals(HttpStatus.NOT_IMPLEMENTED, responseEntity.getStatusCode());
+        assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode());
+
+        final HttpHeaders httpHeaders = responseEntity.getHeaders();
+        assertTrue(httpHeaders.containsKey(HttpHeaders.LOCATION));
+        final List<String> actual = httpHeaders.get(HttpHeaders.LOCATION);
+        assertEquals(1, actual.size());
+        assertEquals(EXPECTED_NS_LCM_OP_OCC_REQ_LOCATION_URL, actual.get(0));
     }
 
+    @Test
+    public void testTerminateNs_ValidTerminateNsRequest_nsRequestProcessingExceptionThrown_returnInlineResponse400() {
+        final String errorMessage = "ERROR MESSAGE";
+        final TerminateNsRequest terminateNsRequest = getTerminateNsRequest();
+        when(mockedJobExecutorService.runTerminateNsJob(eq(RANDOM_NS_INST_ID), eq(terminateNsRequest)))
+                .thenThrow(new NsRequestProcessingException(errorMessage));
+
+        final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + RANDOM_NS_INST_ID + "/terminate";
+        final HttpEntity<?> request = new HttpEntity<>(terminateNsRequest);
+        final ResponseEntity<InlineResponse400> responseEntity =
+                testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, InlineResponse400.class);
+        assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode());
+        assertTrue(responseEntity.hasBody());
+        assertNotNull(responseEntity.getBody());
+    }
 
     private TerminateNsRequest getTerminateNsRequest() {
-        return new TerminateNsRequest().terminationTime(LocalDateTime.now());
+        // Only support for the immediate Terminate request; i.e., terminateTime field is empty (not set)
+        return new TerminateNsRequest();
     }
 
     private InstantiateNsRequest getInstantiateNsRequest() {