Adding Create AS support 86/132986/1
authorwaqas.ikram <waqas.ikram@est.tech>
Mon, 23 Jan 2023 14:59:18 +0000 (14:59 +0000)
committerwaqas.ikram <waqas.ikram@est.tech>
Mon, 23 Jan 2023 14:59:29 +0000 (14:59 +0000)
Change-Id: I4b1d417c7f20d67d5fb0d05718819186f8dd3bea
Issue-ID: SO-4068
Signed-off-by: waqas.ikram <waqas.ikram@est.tech>
20 files changed:
so-cnfm/so-cnfm-lcm/pom.xml
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/AbstractServiceTask.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/CreateAs.bpmn [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/DefaultToShortClassNameBeanNameGenerator.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/TestApplication.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTaskTest.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/pom.xml [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/Constants.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/GsonSerializerConfiguration.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/SoCnfmAsLcmManagerUrlProvider.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLcmOperationOccurrenceManager.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLifeCycleManager.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesController.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLifecycleManagementController.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/TestApplication.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesControllerTest.java [new file with mode: 0644]
so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/resources/application.yaml [new file with mode: 0644]

index ad758d1..0b1dd81 100644 (file)
@@ -15,5 +15,6 @@
         <module>so-cnfm-lcm-api</module>
         <module>so-cnfm-lcm-database-service</module>
         <module>so-cnfm-lcm-bpmn-flows</module>
+        <module>so-cnfm-lcm-service</module>
     </modules>
 </project>
\ No newline at end of file
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/AbstractServiceTask.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/AbstractServiceTask.java
new file mode 100644 (file)
index 0000000..45d7806
--- /dev/null
@@ -0,0 +1,208 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.bpmn.flows.tasks;
+
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_INSTANCE_ID_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.JOB_ID_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.OCC_ID_PARAM_NAME;
+
+import static org.onap.so.cnfm.lcm.database.beans.JobStatusEnum.IN_PROGRESS;
+
+import java.time.LocalDateTime;
+import java.util.Optional;
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.onap.so.cnfm.lcm.database.beans.AsInst;
+import org.onap.so.cnfm.lcm.database.beans.Job;
+import org.onap.so.cnfm.lcm.database.beans.JobStatus;
+import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum;
+import org.onap.so.cnfm.lcm.database.beans.OperationStateEnum;
+import org.onap.so.cnfm.lcm.database.beans.State;
+import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider;
+import org.onap.so.cnfm.lcm.model.ErrorDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public abstract class AbstractServiceTask {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+    protected final DatabaseServiceProvider databaseServiceProvider;
+
+    protected AbstractServiceTask(final DatabaseServiceProvider databaseServiceProvider) {
+        this.databaseServiceProvider = databaseServiceProvider;
+    }
+
+    public void addJobStatus(final DelegateExecution execution, final JobStatusEnum jobStatusEnum,
+            final String description) {
+        final JobStatus jobStatus =
+                new JobStatus().status(jobStatusEnum).description(description).updatedTime(LocalDateTime.now());
+        logger.info("Adding JobStatus {}", jobStatus);
+        final Job job = getJob(execution);
+        job.jobStatus(jobStatus);
+        databaseServiceProvider.addJob(job);
+    }
+
+    public void setJobStatus(final DelegateExecution execution, final JobStatusEnum jobStatus,
+            final String description) {
+        logger.info("Setting Job Status to {}", jobStatus);
+        final Job job = getJob(execution);
+        job.status(jobStatus);
+        if (JobStatusEnum.STARTED.equals(jobStatus)) {
+            job.processInstanceId(execution.getProcessInstanceId());
+        }
+
+        if (JobStatusEnum.FINISHED.equals(jobStatus)) {
+            job.endTime(LocalDateTime.now());
+        }
+
+        job.jobStatus(new JobStatus().status(jobStatus).description(description).updatedTime(LocalDateTime.now()));
+        databaseServiceProvider.addJob(job);
+
+    }
+
+    public void setAsInstanceStatusToFailed(final DelegateExecution execution) {
+        logger.info("Setting As Instance Status to {}", State.FAILED);
+        updateAsInstanceStatus(execution, State.FAILED);
+    }
+
+    public void setJobStatusToError(final DelegateExecution execution, final String description) {
+        logger.info("Setting Job Status to {}", JobStatusEnum.ERROR);
+
+        final String jobId = (String) execution.getVariable(JOB_ID_PARAM_NAME);
+        final Optional<Job> optional = databaseServiceProvider.getJob(jobId);
+        if (optional.isPresent()) {
+            final ErrorDetails errorDetails =
+                    (ErrorDetails) execution.getVariable(AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME);
+
+            final Job job = optional.get();
+            job.status(JobStatusEnum.ERROR).endTime(LocalDateTime.now());
+
+            if (errorDetails != null) {
+                logger.error("Found failed reason: {}", errorDetails);
+                job.jobStatus(new JobStatus().status(JobStatusEnum.ERROR).description(errorDetails.getDetail())
+                        .updatedTime(LocalDateTime.now()));
+            }
+            job.jobStatus(new JobStatus().status(JobStatusEnum.ERROR).description(description)
+                    .updatedTime(LocalDateTime.now()));
+
+            databaseServiceProvider.addJob(job);
+        }
+        logger.info("Finished setting Job Status to {}", JobStatusEnum.ERROR);
+
+    }
+
+    protected void abortOperation(final DelegateExecution execution, final String message) {
+        abortOperation(execution, message, new ErrorDetails().detail(message));
+    }
+
+    protected void abortOperation(final DelegateExecution execution, final String message,
+            final ErrorDetails problemDetails) {
+        logger.error(message);
+        execution.setVariable(AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME, problemDetails);
+        throw new BpmnError("WORKFLOW_FAILED", message);
+    }
+
+    private Job getJob(final DelegateExecution execution) {
+        final String jobId = (String) execution.getVariable(JOB_ID_PARAM_NAME);
+        final Optional<Job> optional = databaseServiceProvider.getJob(jobId);
+        if (optional.isEmpty()) {
+            final String message = "Unable to find job using job id: " + jobId;
+            logger.error(message);
+            abortOperation(execution, message);
+        }
+
+        return optional.get();
+    }
+
+    protected void updateAsInstanceStatus(final DelegateExecution execution, final State nsStatus) {
+        final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
+
+        logger.info("Updating AsInst Status to {} and saving to DB", nsStatus);
+        databaseServiceProvider.updateAsInstState(asInstId, nsStatus);
+    }
+
+    protected AsInst getAsInst(final DelegateExecution execution) {
+        final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
+        return getAsInst(execution, asInstId);
+    }
+
+    protected AsInst getAsInst(final DelegateExecution execution, final String asInstId) {
+        logger.info("Getting AsInst to update with asInstId: {}", asInstId);
+        final Optional<AsInst> optionalAsInst = databaseServiceProvider.getAsInst(asInstId);
+
+        if (optionalAsInst.isEmpty()) {
+            final String message = "Unable to find AS Instance in database using id: " + asInstId;
+            abortOperation(execution, message);
+        }
+
+        return optionalAsInst.get();
+    }
+
+    public void updateAsLcmOpOccStatusToCompleted(final DelegateExecution execution) {
+        logger.info("Executing updateAsLcmOpOccStatusToCompleted ...");
+
+        addJobStatus(execution, IN_PROGRESS, "Updating AsLcmOpOcc Status to " + OperationStateEnum.COMPLETED);
+        updateAsLcmOpOccOperationState(execution, OperationStateEnum.COMPLETED);
+
+        logger.info("Finished executing updateAsLcmOpOccStatusToCompleted ...");
+
+    }
+
+    public void updateAsLcmOpOccStatusToFailed(final DelegateExecution execution) {
+        logger.info("Executing updateAsLcmOpOccStatusToFailed ...");
+
+        updateAsLcmOpOccOperationState(execution, OperationStateEnum.FAILED);
+
+        logger.info("Finished executing updateAsLcmOpOccStatusToFailed ...");
+
+    }
+
+    private void updateAsLcmOpOccOperationState(final DelegateExecution execution,
+            final OperationStateEnum operationState) {
+        final String occId = (String) execution.getVariable(OCC_ID_PARAM_NAME);
+
+        final boolean isSuccessful = databaseServiceProvider.updateAsLcmOpOccOperationState(occId, operationState);
+        if (!isSuccessful) {
+            final String message =
+                    "Unable to update AsLcmOpOcc " + occId + " operationState to" + operationState + " in database";
+            logger.error(message);
+            abortOperation(execution, message);
+        }
+    }
+
+
+    public void updateDeploymentItemStatus(final DelegateExecution execution, final String asDeploymentItemInstId,
+            final State state) {
+        logger.debug("updateDeploymentItemStatus to status: {}", state);
+        final boolean isSuccessful = databaseServiceProvider.updateAsDeploymentItemState(asDeploymentItemInstId, state);
+        if (!isSuccessful) {
+            final String message = "Unable to update AsDeploymentItem " + asDeploymentItemInstId + " status to" + state
+                    + " in database";
+            logger.error(message);
+            abortOperation(execution, message);
+        }
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java
new file mode 100644 (file)
index 0000000..85af369
--- /dev/null
@@ -0,0 +1,342 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.bpmn.flows.tasks;
+
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_INSTANCE_ID_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.CREATE_AS_REQUEST_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.CamundaVariableNameConstants.CREATE_AS_RESPONSE_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.APPLICATION_NAME_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.APPLICATION_VERSION_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DEPLOYMENT_ITEMS_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DESCRIPTOR_ID_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.DESCRIPTOR_INVARIANT_ID_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPropertiesConstants.PROVIDER_PARAM_NAME;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.CLOUD_OWNER_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.CLOUD_REGION_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.RESOURCE_ID_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.SERVICE_INSTANCE_ID_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.SERVICE_INSTANCE_NAME_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.TENANT_ID_PARAM_KEY;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.time.LocalDateTime;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.so.cnfm.lcm.bpmn.flows.extclients.aai.AaiServiceProvider;
+import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.DeploymentItem;
+import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcCsarPackageParser;
+import org.onap.so.cnfm.lcm.bpmn.flows.extclients.sdc.SdcPackageProvider;
+import org.onap.so.cnfm.lcm.database.beans.AsDeploymentItem;
+import org.onap.so.cnfm.lcm.database.beans.AsInst;
+import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum;
+import org.onap.so.cnfm.lcm.database.beans.State;
+import org.onap.so.cnfm.lcm.database.beans.AsLifecycleParam;
+import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider;
+import org.onap.so.cnfm.lcm.model.AsInstance;
+import org.onap.so.cnfm.lcm.model.AsInstance.InstantiationStateEnum;
+import org.onap.so.cnfm.lcm.model.CreateAsRequest;
+import org.onap.so.cnfm.lcm.model.ErrorDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Component
+public class CreateAsTask extends AbstractServiceTask {
+    private static final String ASD_PROPERTIES_PARAM_NAME = "asdProperties";
+    private static final String DOES_AS_PACKAGE_EXISTS_PARAM_NAME = "doesAsPackageExists";
+    private static final String DOES_AS_INSTANCE_EXISTS_PARAM_NAME = "doesAsInstanceExists";
+    private static final Logger logger = LoggerFactory.getLogger(CreateAsTask.class);
+
+    private final AaiServiceProvider aaiServiceProvider;
+    private final SdcPackageProvider sdcPackageProvider;
+    private final SdcCsarPackageParser sdcParser;
+
+
+    @Autowired
+    public CreateAsTask(final DatabaseServiceProvider databaseServiceProvider,
+            final AaiServiceProvider aaiServiceProvider, final SdcPackageProvider sdcPackageProvider,
+            final SdcCsarPackageParser sdcParser) {
+        super(databaseServiceProvider);
+        this.aaiServiceProvider = aaiServiceProvider;
+        this.sdcPackageProvider = sdcPackageProvider;
+        this.sdcParser = sdcParser;
+    }
+
+    public void setJobStatusToStarted(final DelegateExecution execution) {
+        setJobStatus(execution, JobStatusEnum.STARTED, "Create AS workflow process started");
+    }
+
+    public void setJobStatusToFinished(final DelegateExecution execution) {
+        setJobStatus(execution, JobStatusEnum.FINISHED, "Create AS workflow process finished");
+    }
+
+    public void setJobStatusToError(final DelegateExecution execution) {
+        setJobStatusToError(execution, "Create AS workflow process failed");
+    }
+
+    public void getAsPackage(final DelegateExecution execution) {
+        logger.info("Retrieving AS package from SDC ...");
+        setJobStatus(execution, JobStatusEnum.IN_PROGRESS, "Retrieving AS package from SDC");
+
+        final CreateAsRequest createAsRequest = (CreateAsRequest) execution.getVariable(CREATE_AS_REQUEST_PARAM_NAME);
+
+        logger.info("Retrieving AS package from SDC using asdId: {}", createAsRequest.getAsdId());
+
+        try {
+
+            final Optional<byte[]> optional = sdcPackageProvider.getSdcResourcePackage(createAsRequest.getAsdId());
+
+            if (optional.isPresent()) {
+                logger.info("ASD Package exists for asdId {}", createAsRequest.getAsdId());
+
+                final Map<String, Object> asdProperties = sdcParser.getAsdProperties(optional.get());
+                logger.info("ASD Package properties fields {}", asdProperties);
+
+                execution.setVariable(ASD_PROPERTIES_PARAM_NAME, asdProperties);
+                execution.setVariable(DOES_AS_PACKAGE_EXISTS_PARAM_NAME, true);
+            } else {
+
+                final String message = "Unable to find ASD package using asdId: " + createAsRequest.getAsdId();
+                logger.error(message);
+                execution.setVariable(DOES_AS_PACKAGE_EXISTS_PARAM_NAME, false);
+                abortOperation(execution, message);
+            }
+        } catch (final Exception failureException) {
+            final String message =
+                    "Unexpected exception occured while getting asd package using asdId: " + createAsRequest.getAsdId();
+            logger.error(message, failureException);
+
+            execution.setVariable(DOES_AS_PACKAGE_EXISTS_PARAM_NAME, false);
+            execution.setVariable(AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME,
+                    new ErrorDetails().title(message).detail(message));
+        }
+
+    }
+
+    public void doesAsInstanceExistsInDb(final DelegateExecution execution) {
+        logger.info("Executing doesAsInstanceExistsInDb  ...");
+
+        setJobStatus(execution, JobStatusEnum.IN_PROGRESS, "Checking if AS Instance exists in database");
+
+        final CreateAsRequest createAsRequest =
+                (CreateAsRequest) execution.getVariables().get(CREATE_AS_REQUEST_PARAM_NAME);
+
+        final boolean exists = databaseServiceProvider.isAsInstExists(createAsRequest.getAsInstanceName());
+        logger.info("As Instance entry {} exists in database", exists ? "does" : "doesn't");
+        execution.setVariable(DOES_AS_INSTANCE_EXISTS_PARAM_NAME, exists);
+
+        if (exists) {
+            final Optional<AsInst> optional =
+                    databaseServiceProvider.getAsInstByName(createAsRequest.getAsInstanceName());
+            final AsInst asInst = optional.get();
+            execution.setVariable(AS_WORKFLOW_PROCESSING_EXCEPTION_PARAM_NAME,
+                    new ErrorDetails().detail("As Instance already exists in database : " + asInst.toString()));
+        }
+
+        logger.info("Finished executing doesAsInstanceExistsInDb  ...");
+
+    }
+
+    public void createAsInstanceInDb(final DelegateExecution execution) {
+        try {
+            logger.info("Executing createAsInstanceInDb  ...");
+
+            setJobStatus(execution, JobStatusEnum.IN_PROGRESS, "Creating AS Instance entry in database");
+
+            final CreateAsRequest createAsRequest =
+                    (CreateAsRequest) execution.getVariable(CREATE_AS_REQUEST_PARAM_NAME);
+
+            final Map<String, Object> additionalParams = createAsRequest.getAdditionalParams();
+
+            if (additionalParams == null) {
+                abortOperation(execution, "Missing 'additionalParams' mandatory field");
+            }
+
+            final String cloudOwner = getMandatoryValue(additionalParams, CLOUD_OWNER_PARAM_KEY, execution);
+            final String cloudRegion = getMandatoryValue(additionalParams, CLOUD_REGION_PARAM_KEY, execution);
+            final String tenantId = getMandatoryValue(additionalParams, TENANT_ID_PARAM_KEY, execution);
+            final String resourceId = (String) additionalParams.get(RESOURCE_ID_KEY);
+
+            final String serviceInstanceName =
+                    getMandatoryValue(additionalParams, SERVICE_INSTANCE_NAME_PARAM_KEY, execution);
+            final String serviceInstanceId =
+                    getMandatoryValue(additionalParams, SERVICE_INSTANCE_ID_PARAM_KEY, execution);
+
+            final String asInstId = getAsInstId(resourceId);
+            execution.setVariable(AS_INSTANCE_ID_PARAM_NAME, asInstId);
+
+            @SuppressWarnings("unchecked")
+            final Map<String, Object> asdProperties =
+                    (Map<String, Object>) execution.getVariable(ASD_PROPERTIES_PARAM_NAME);
+
+            final AsInst asInst = new AsInst().asInstId(asInstId).name(createAsRequest.getAsInstanceName())
+                    .asdId(createAsRequest.getAsdId())
+                    .asPackageId(getParamValue(asdProperties, DESCRIPTOR_ID_PARAM_NAME))
+                    .asdInvariantId(getParamValue(asdProperties, DESCRIPTOR_INVARIANT_ID_PARAM_NAME))
+                    .asProvider(getParamValue(asdProperties, PROVIDER_PARAM_NAME))
+                    .asApplicationName(getParamValue(asdProperties, APPLICATION_NAME_PARAM_NAME))
+                    .asApplicationVersion(getParamValue(asdProperties, APPLICATION_VERSION_PARAM_NAME))
+                    .description(createAsRequest.getAsInstanceDescription()).serviceInstanceId(serviceInstanceId)
+                    .serviceInstanceName(serviceInstanceName).cloudOwner(cloudOwner).cloudRegion(cloudRegion)
+                    .tenantId(tenantId).status(State.NOT_INSTANTIATED).statusUpdatedTime(LocalDateTime.now());
+
+            @SuppressWarnings("unchecked")
+            final List<DeploymentItem> deploymentItems =
+                    (List<DeploymentItem>) asdProperties.get(DEPLOYMENT_ITEMS_PARAM_NAME);
+
+            if (deploymentItems != null) {
+                deploymentItems.forEach(item -> {
+                    final AsDeploymentItem asDeploymentItem =
+                            new AsDeploymentItem().itemId(item.getItemId()).name(item.getName())
+                                    .deploymentOrder(item.getDeploymentOrder() != null
+                                            ? Integer.parseInt(item.getDeploymentOrder())
+                                            : null)
+                                    .artifactFilePath(item.getFile()).status(State.NOT_INSTANTIATED)
+                                    .createTime(LocalDateTime.now()).lastUpdateTime(LocalDateTime.now())
+                                    .releaseName(generateReleaseName(asInst, item));
+                    final List<AsLifecycleParam> lifecycleParams = getLifeCycleParams(asDeploymentItem, item);
+                    asDeploymentItem.setAsLifecycleParams(lifecycleParams);
+                    asInst.asdeploymentItems(asDeploymentItem);
+                });
+            }
+
+            databaseServiceProvider.saveAsInst(asInst);
+            logger.info("Finished executing createAsInstanceInDb  ...");
+        } catch (final Exception exception) {
+            logger.error("Unable to create AsInst object in database", exception);
+            throw exception;
+        }
+
+    }
+
+    private List<AsLifecycleParam> getLifeCycleParams(final AsDeploymentItem asDeploymentItem,
+            final DeploymentItem deploymentItem) {
+        final List<AsLifecycleParam> asLifecycleParams = new ArrayList<>();
+        if (deploymentItem.getLifecycleParameters() != null) {
+            for (final String lifecycleParam : deploymentItem.getLifecycleParameters()) {
+                asLifecycleParams.add(
+                        new AsLifecycleParam().asDeploymentItemInst(asDeploymentItem).asLifecycleParam(lifecycleParam));
+            }
+
+
+        }
+        return asLifecycleParams;
+    }
+
+    private String generateReleaseName(final AsInst asInst, final DeploymentItem item) {
+        return String.join("-", Arrays.asList(asInst.getName(), item.getName(), item.getItemId())).toLowerCase()
+                .replaceAll("[\\s\\_]", "-");
+    }
+
+    public void createGenericVnfInstanceInAai(final DelegateExecution execution) {
+        logger.info("Executing createAsInstanceInAai  ...");
+        try {
+            setJobStatus(execution, JobStatusEnum.IN_PROGRESS, "Creating Generic Vnf Instance in AAI");
+
+            final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
+            final AsInst asInst = getAsInst(execution, asInstId);
+
+            final GenericVnf genericVnf = new GenericVnf();
+            genericVnf.setVnfId(asInstId);
+            genericVnf.setVnfName(asInst.getName());
+            genericVnf.setVnfType(asInst.getServiceInstanceName() + "/" + asInst.getName());
+            genericVnf.setServiceId(asInst.getServiceInstanceId());
+            genericVnf.setOperationalStatus("Created");
+            genericVnf.setOrchestrationStatus("Created");
+            genericVnf.setIsClosedLoopDisabled(false);
+            aaiServiceProvider.createGenericVnfAndConnectServiceInstance(asInst.getServiceInstanceId(), asInstId,
+                    genericVnf);
+
+            aaiServiceProvider.connectGenericVnfToTenant(asInstId, asInst.getCloudOwner(), asInst.getCloudRegion(),
+                    asInst.getTenantId());
+
+        } catch (final Exception exception) {
+            final String message = "Unable to Create Generic Vnf Instance in AAI";
+            logger.error(message, exception);
+            abortOperation(execution, message);
+        }
+        logger.info("Finished executing createNsInstanceInAai  ...");
+
+    }
+
+    public void setCreateAsResponse(final DelegateExecution execution) {
+        logger.info("Executing setCreateAsResponse  ...");
+        final String asInstId = (String) execution.getVariable(AS_INSTANCE_ID_PARAM_NAME);
+        final Optional<AsInst> optional = databaseServiceProvider.getAsInst(asInstId);
+
+        if (optional.isPresent()) {
+            final AsInst asInst = optional.get();
+            final AsInstance response =
+                    new AsInstance().asInstanceid(asInst.getAsInstId()).asInstanceName(asInst.getName())
+                            .asdId(asInst.getAsdId()).asInstanceDescription(asInst.getDescription())
+                            .instantiationState(InstantiationStateEnum.fromValue(asInst.getStatus().toString()))
+                            .asProvider(asInst.getAsProvider()).asApplicationName(asInst.getAsApplicationName())
+                            .asApplicationVersion(asInst.getAsApplicationVersion());
+            logger.info("Saving CreateNsResponse: {} in Execution ...", response);
+            execution.setVariable(CREATE_AS_RESPONSE_PARAM_NAME, response);
+        } else {
+            final String message = "Unable to find AS Instance in datababse using id: " + asInstId;
+            logger.error(message);
+            abortOperation(execution, message);
+        }
+
+        logger.info("Finished executing setCreateNsResponse  ...");
+
+    }
+
+    private String getMandatoryValue(final Map<String, Object> additionalParams, final String key,
+            final DelegateExecution execution) {
+        final Object value = additionalParams.get(key);
+        if (value == null) {
+            abortOperation(execution, "Missing '" + key + "' mandatory field");
+        }
+        return value.toString();
+    }
+
+    private String getAsInstId(final String resourceId) {
+        if ((resourceId != null) && !(resourceId.isBlank())) {
+            logger.debug("Will use resourceId as asInstId: {}", resourceId);
+            return resourceId;
+        }
+        final String asInstId = UUID.randomUUID().toString();
+        logger.debug("Creating random UUID for asInstId: {}", asInstId);
+        return asInstId;
+    }
+
+    private String getParamValue(final Map<String, Object> properties, final String key) {
+        final Object object = properties.get(key);
+        if (object != null) {
+            return object.toString();
+        }
+        logger.warn("Unable to final property value for key {}", key);
+        return null;
+    }
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/CreateAs.bpmn b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/CreateAs.bpmn
new file mode 100644 (file)
index 0000000..f828e6d
--- /dev/null
@@ -0,0 +1,266 @@
+<?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_1l4zor5" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.0.0">
+  <bpmn:process id="CreateAs" name="&#10;CreateAs" isExecutable="true">
+    <bpmn:startEvent id="StartEvent_1" name="Start Process">
+      <bpmn:outgoing>Flow_1tqn5q5</bpmn:outgoing>
+    </bpmn:startEvent>
+    <bpmn:endEvent id="EndEvent_1" name="End Process">
+      <bpmn:incoming>Flow_0t87ov3</bpmn:incoming>
+    </bpmn:endEvent>
+    <bpmn:sequenceFlow id="Flow_1tqn5q5" sourceRef="StartEvent_1" targetRef="Activity_15ksfz6" />
+    <bpmn:serviceTask id="Activity_15ksfz6" name="Set Job Status to STARTED" camunda:asyncBefore="true" camunda:expression="${CreateAsTask.setJobStatusToStarted(execution)}">
+      <bpmn:incoming>Flow_1tqn5q5</bpmn:incoming>
+      <bpmn:outgoing>Flow_0y07mxe</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0y07mxe" sourceRef="Activity_15ksfz6" targetRef="Activity_12yonzp" />
+    <bpmn:serviceTask id="Activity_1r4l8w8" name="Set Job Status to FINISHED" camunda:expression="${CreateAsTask.setJobStatusToFinished(execution)}">
+      <bpmn:incoming>Flow_1rtsvpm</bpmn:incoming>
+      <bpmn:outgoing>Flow_0t87ov3</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0t87ov3" sourceRef="Activity_1r4l8w8" targetRef="EndEvent_1" />
+    <bpmn:exclusiveGateway id="Gateway_0fuwzjj" name="Does Asd Package exists?">
+      <bpmn:incoming>Flow_09582uw</bpmn:incoming>
+      <bpmn:outgoing>Flow_1f4vi10</bpmn:outgoing>
+      <bpmn:outgoing>Flow_0qabgp7</bpmn:outgoing>
+    </bpmn:exclusiveGateway>
+    <bpmn:serviceTask id="Activity_12yonzp" name="Get As Package from SDC" camunda:expression="${CreateAsTask.getAsPackage(execution)}">
+      <bpmn:incoming>Flow_0y07mxe</bpmn:incoming>
+      <bpmn:outgoing>Flow_09582uw</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_09582uw" sourceRef="Activity_12yonzp" targetRef="Gateway_0fuwzjj" />
+    <bpmn:subProcess id="Activity_06ko4e2" name="Error Handling" triggeredByEvent="true">
+      <bpmn:startEvent id="Event_1ibvrn2" name="error">
+        <bpmn:outgoing>Flow_0554tjv</bpmn:outgoing>
+        <bpmn:errorEventDefinition id="ErrorEventDefinition_0lc46mh" />
+      </bpmn:startEvent>
+      <bpmn:endEvent id="Event_02f7sr1" name="end">
+        <bpmn:incoming>Flow_04xvpee</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:sequenceFlow id="Flow_0554tjv" sourceRef="Event_1ibvrn2" targetRef="Activity_1sj0nvr" />
+      <bpmn:serviceTask id="Activity_1sj0nvr" name="Set Job Status to ERROR" camunda:asyncBefore="true" camunda:expression="${CreateAsTask.setJobStatusToError(execution)}">
+        <bpmn:incoming>Flow_0554tjv</bpmn:incoming>
+        <bpmn:outgoing>Flow_04xvpee</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_04xvpee" sourceRef="Activity_1sj0nvr" targetRef="Event_02f7sr1" />
+    </bpmn:subProcess>
+    <bpmn:subProcess id="Activity_1dx9fz6" name="Java Exception Handling" triggeredByEvent="true">
+      <bpmn:startEvent id="Event_0zne7ch" name="error">
+        <bpmn:outgoing>Flow_0j1otrx</bpmn:outgoing>
+        <bpmn:errorEventDefinition id="ErrorEventDefinition_1p3h4ta" errorRef="Error_0s855yd" camunda:errorCodeVariable="BPMN_javaExpCode" camunda:errorMessageVariable="BPMN_javaExpMsg" />
+      </bpmn:startEvent>
+      <bpmn:endEvent id="Event_0bcyh7u">
+        <bpmn:incoming>Flow_0oqv7vl</bpmn:incoming>
+      </bpmn:endEvent>
+      <bpmn:sequenceFlow id="Flow_0j1otrx" sourceRef="Event_0zne7ch" targetRef="Activity_15uwy90" />
+      <bpmn:serviceTask id="Activity_15uwy90" name="Set Job Status to ERROR" camunda:asyncBefore="true" camunda:expression="${CreateAsTask.setJobStatusToError(execution)}">
+        <bpmn:incoming>Flow_0j1otrx</bpmn:incoming>
+        <bpmn:outgoing>Flow_0oqv7vl</bpmn:outgoing>
+      </bpmn:serviceTask>
+      <bpmn:sequenceFlow id="Flow_0oqv7vl" sourceRef="Activity_15uwy90" targetRef="Event_0bcyh7u" />
+    </bpmn:subProcess>
+    <bpmn:sequenceFlow id="Flow_1f4vi10" name="No" sourceRef="Gateway_0fuwzjj" targetRef="Event_016q8gu">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{not doesAsPackageExists}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:endEvent id="Event_016q8gu">
+      <bpmn:incoming>Flow_1f4vi10</bpmn:incoming>
+      <bpmn:incoming>Flow_1yql1cm</bpmn:incoming>
+      <bpmn:errorEventDefinition id="ErrorEventDefinition_1ugx52k" errorRef="Error_0rqvnym" />
+    </bpmn:endEvent>
+    <bpmn:sequenceFlow id="Flow_0qabgp7" name="Yes" sourceRef="Gateway_0fuwzjj" targetRef="Activity_0vlb2nk">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{doesAsPackageExists}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:serviceTask id="Activity_0vlb2nk" name="Check AS Instance exists In DB " camunda:expression="${CreateAsTask.doesAsInstanceExistsInDb(execution)}">
+      <bpmn:incoming>Flow_0qabgp7</bpmn:incoming>
+      <bpmn:outgoing>Flow_1exrj2b</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_1exrj2b" sourceRef="Activity_0vlb2nk" targetRef="Gateway_0d7n517" />
+    <bpmn:exclusiveGateway id="Gateway_0d7n517">
+      <bpmn:incoming>Flow_1exrj2b</bpmn:incoming>
+      <bpmn:outgoing>Flow_1rkg44s</bpmn:outgoing>
+      <bpmn:outgoing>Flow_1yql1cm</bpmn:outgoing>
+    </bpmn:exclusiveGateway>
+    <bpmn:sequenceFlow id="Flow_1rkg44s" name="No" sourceRef="Gateway_0d7n517" targetRef="Activity_09tqz8x">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{not doesAsInstanceExists}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:sequenceFlow id="Flow_1yql1cm" name="Yes" sourceRef="Gateway_0d7n517" targetRef="Event_016q8gu">
+      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">#{doesAsInstanceExists}</bpmn:conditionExpression>
+    </bpmn:sequenceFlow>
+    <bpmn:serviceTask id="Activity_09tqz8x" name="Create AS Instance record in DB" camunda:expression="${CreateAsTask.createAsInstanceInDb(execution)}">
+      <bpmn:incoming>Flow_1rkg44s</bpmn:incoming>
+      <bpmn:outgoing>Flow_1jvfwd2</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_1jvfwd2" sourceRef="Activity_09tqz8x" targetRef="Activity_1akc79d" />
+    <bpmn:serviceTask id="Activity_1akc79d" name="Create Generic Vnf Instance in AAI" camunda:expression="${CreateAsTask.createGenericVnfInstanceInAai(execution)}">
+      <bpmn:incoming>Flow_1jvfwd2</bpmn:incoming>
+      <bpmn:outgoing>Flow_0e5hvno</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_0e5hvno" sourceRef="Activity_1akc79d" targetRef="Activity_03ht66t" />
+    <bpmn:serviceTask id="Activity_03ht66t" name="Set Create AS Response" camunda:expression="${CreateAsTask.setCreateAsResponse(execution)}">
+      <bpmn:incoming>Flow_0e5hvno</bpmn:incoming>
+      <bpmn:outgoing>Flow_1rtsvpm</bpmn:outgoing>
+    </bpmn:serviceTask>
+    <bpmn:sequenceFlow id="Flow_1rtsvpm" sourceRef="Activity_03ht66t" targetRef="Activity_1r4l8w8" />
+  </bpmn:process>
+  <bpmn:error id="Error_0s855yd" name="java.lang.Exception" errorCode="java.lang.Exception" />
+  <bpmn:error id="Error_0rqvnym" name="NsWorkflowProcessingException" errorCode="CREATE_AS_WORKFLOW_PROCESSING_EXCEPTION" />
+  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="CreateAs">
+      <bpmndi:BPMNEdge id="Flow_1rtsvpm_di" bpmnElement="Flow_1rtsvpm">
+        <di:waypoint x="1160" y="157" />
+        <di:waypoint x="1160" y="230" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0e5hvno_di" bpmnElement="Flow_0e5hvno">
+        <di:waypoint x="1070" y="117" />
+        <di:waypoint x="1110" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1jvfwd2_di" bpmnElement="Flow_1jvfwd2">
+        <di:waypoint x="930" y="117" />
+        <di:waypoint x="970" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1yql1cm_di" bpmnElement="Flow_1yql1cm">
+        <di:waypoint x="760" y="142" />
+        <di:waypoint x="760" y="230" />
+        <di:waypoint x="668" y="230" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="766" y="183" width="19" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1rkg44s_di" bpmnElement="Flow_1rkg44s">
+        <di:waypoint x="785" y="117" />
+        <di:waypoint x="830" y="117" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="799" y="99" width="14" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1exrj2b_di" bpmnElement="Flow_1exrj2b">
+        <di:waypoint x="700" y="117" />
+        <di:waypoint x="735" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0qabgp7_di" bpmnElement="Flow_0qabgp7">
+        <di:waypoint x="565" y="117" />
+        <di:waypoint x="600" y="117" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="579" y="99" width="19" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1f4vi10_di" bpmnElement="Flow_1f4vi10">
+        <di:waypoint x="540" y="142" />
+        <di:waypoint x="540" y="230" />
+        <di:waypoint x="632" y="230" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="548" y="183" width="14" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_09582uw_di" bpmnElement="Flow_09582uw">
+        <di:waypoint x="480" y="117" />
+        <di:waypoint x="515" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0t87ov3_di" bpmnElement="Flow_0t87ov3">
+        <di:waypoint x="1160" y="310" />
+        <di:waypoint x="1160" y="357" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0y07mxe_di" bpmnElement="Flow_0y07mxe">
+        <di:waypoint x="350" y="117" />
+        <di:waypoint x="380" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_1tqn5q5_di" bpmnElement="Flow_1tqn5q5">
+        <di:waypoint x="208" y="117" />
+        <di:waypoint x="250" y="117" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
+        <dc:Bounds x="172" y="99" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="158" y="142" width="67" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_0db1w1a_di" bpmnElement="EndEvent_1">
+        <dc:Bounds x="1142" y="357" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="1129" y="400" width="63" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_15ksfz6_di" bpmnElement="Activity_15ksfz6">
+        <dc:Bounds x="250" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1r4l8w8_di" bpmnElement="Activity_1r4l8w8">
+        <dc:Bounds x="1110" y="230" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Gateway_0fuwzjj_di" bpmnElement="Gateway_0fuwzjj" isMarkerVisible="true">
+        <dc:Bounds x="515" y="92" width="50" height="50" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="502" y="62" width="80" height="27" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_12yonzp_di" bpmnElement="Activity_12yonzp">
+        <dc:Bounds x="380" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_06ko4e2_di" bpmnElement="Activity_06ko4e2" isExpanded="true">
+        <dc:Bounds x="431" y="310" width="438" height="130" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="Flow_04xvpee_di" bpmnElement="Flow_04xvpee">
+        <di:waypoint x="681" y="373" />
+        <di:waypoint x="813" y="373" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0554tjv_di" bpmnElement="Flow_0554tjv">
+        <di:waypoint x="489" y="373" />
+        <di:waypoint x="581" y="373" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="Event_1ibvrn2_di" bpmnElement="Event_1ibvrn2">
+        <dc:Bounds x="453" y="355" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="459" y="398" width="24" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_02f7sr1_di" bpmnElement="Event_02f7sr1">
+        <dc:Bounds x="813" y="355" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="823" y="397" width="19" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1sj0nvr_di" bpmnElement="Activity_1sj0nvr">
+        <dc:Bounds x="581" y="333" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1dx9fz6_di" bpmnElement="Activity_1dx9fz6" isExpanded="true">
+        <dc:Bounds x="431" y="470" width="438" height="130" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge id="Flow_0oqv7vl_di" bpmnElement="Flow_0oqv7vl">
+        <di:waypoint x="680" y="533" />
+        <di:waypoint x="772" y="533" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge id="Flow_0j1otrx_di" bpmnElement="Flow_0j1otrx">
+        <di:waypoint x="522" y="533" />
+        <di:waypoint x="580" y="533" />
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="Event_0zne7ch_di" bpmnElement="Event_0zne7ch">
+        <dc:Bounds x="486" y="515" width="36" height="36" />
+        <bpmndi:BPMNLabel>
+          <dc:Bounds x="493" y="558" width="24" height="14" />
+        </bpmndi:BPMNLabel>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_0bcyh7u_di" bpmnElement="Event_0bcyh7u">
+        <dc:Bounds x="772" y="515" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_15uwy90_di" bpmnElement="Activity_15uwy90">
+        <dc:Bounds x="580" y="493" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Event_0spfqz1_di" bpmnElement="Event_016q8gu">
+        <dc:Bounds x="632" y="212" width="36" height="36" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_0vlb2nk_di" bpmnElement="Activity_0vlb2nk">
+        <dc:Bounds x="600" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Gateway_0d7n517_di" bpmnElement="Gateway_0d7n517" isMarkerVisible="true">
+        <dc:Bounds x="735" y="92" width="50" height="50" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_09tqz8x_di" bpmnElement="Activity_09tqz8x">
+        <dc:Bounds x="830" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_1akc79d_di" bpmnElement="Activity_1akc79d">
+        <dc:Bounds x="970" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="Activity_03ht66t_di" bpmnElement="Activity_03ht66t">
+        <dc:Bounds x="1110" y="77" width="100" height="80" />
+      </bpmndi:BPMNShape>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+</bpmn:definitions>
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java
new file mode 100644 (file)
index 0000000..9920ab9
--- /dev/null
@@ -0,0 +1,181 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.bpmn.flows;
+
+import static org.camunda.bpm.engine.history.HistoricProcessInstance.STATE_ACTIVE;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import org.camunda.bpm.engine.HistoryService;
+import org.camunda.bpm.engine.RuntimeService;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
+import org.camunda.bpm.engine.history.HistoricVariableInstance;
+import org.camunda.bpm.engine.runtime.ProcessInstance;
+import org.junit.runner.RunWith;
+//import org.onap.so.cnfm.lcm.bpmn.flows.service.KubConfigProvider;
+//import org.onap.so.cnfm.lcm.bpmn.flows.tasks.MockedHelmClientConfiguration;
+//import org.onap.so.cnfm.lcm.bpmn.flows.tasks.MockedKubernetesClientProviderConfiguration;
+import org.onap.so.cnfm.lcm.database.beans.AsInst;
+import org.onap.so.cnfm.lcm.database.beans.Job;
+import org.onap.so.cnfm.lcm.database.beans.JobAction;
+import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum;
+import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
+//import org.springframework.context.annotation.Import;
+//import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.util.FileSystemUtils;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+@ContextConfiguration
+@AutoConfigureWireMock(port = 0)
+//@Import({MockedHelmClientConfiguration.class, MockedKubernetesClientProviderConfiguration.class})
+public abstract class BaseTest {
+    protected static final String SERVICE_INSTANCE_ID = UUID.randomUUID().toString();
+    protected static final String SERVICE_INSTANCE_NAME = "ServiceName";
+//    private static final String KUBE_CONFIG_EMPTY_FILE_NAME = "kube-config-empty-file";
+//    private static final String EMPTY = "";
+
+    protected static final String UUID_REGEX =
+            "[0-9a-zA-Z]{8}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{12}";
+    protected static final String RANDOM_JOB_ID = UUID.randomUUID().toString();
+    protected static final Logger logger = getLogger(BaseTest.class);
+
+    private static final long TIME_OUT_IN_SECONDS = 120;
+    private static final int SLEEP_TIME_IN_SECONDS = 5;
+
+    @Autowired
+    private HistoryService historyService;
+
+    @Autowired
+    private RuntimeService runtimeService;
+
+//    @Autowired
+//    private KubConfigProvider kubConfigProvider;
+
+    @Autowired
+    protected DatabaseServiceProvider databaseServiceProvider;
+
+    @Autowired
+    protected WireMockServer wireMockServer;
+
+    public Job createNewJob(final String jobAction, final String nsdId, final String nsName) {
+        final Job newJob = new Job().startTime(LocalDateTime.now()).jobType("AS").jobAction(JobAction.CREATE)
+                .status(JobStatusEnum.STARTING).resourceId(nsdId).resourceName(nsName);
+        databaseServiceProvider.addJob(newJob);
+        return newJob;
+    }
+
+    public Optional<Job> getJob(final String jobId) {
+        return databaseServiceProvider.getJob(jobId);
+    }
+
+    public Optional<Job> getJobByResourceId(final String resourceId) {
+        return databaseServiceProvider.getJobByResourceId(resourceId);
+    }
+
+    public ProcessInstance executeWorkflow(final String processDefinitionKey, final String businessKey,
+            final Map<String, Object> variables) {
+        return runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
+    }
+
+    public HistoricProcessInstance getHistoricProcessInstance(final String processInstanceId) {
+        return historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+    }
+
+    public HistoricVariableInstance getVariable(final String processInstanceId, final String name) {
+        return historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId)
+                .variableName(name).singleResult();
+    }
+
+    public List<HistoricVariableInstance> getVariables(final String processInstanceId) {
+        return historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list();
+    }
+
+    public boolean waitForProcessInstanceToFinish(final String processInstanceId) throws InterruptedException {
+        final long startTimeInMillis = System.currentTimeMillis();
+        final long timeOutTime = startTimeInMillis + TimeUnit.SECONDS.toMillis(TIME_OUT_IN_SECONDS);
+        while (timeOutTime > System.currentTimeMillis()) {
+
+            if (isProcessEndedByProcessInstanceId(processInstanceId)) {
+                logger.info("processInstanceId: {} is finished", processInstanceId);
+                return true;
+            }
+            logger.info("processInstanceId: {} is still running", processInstanceId);
+            logger.info("Process instance {} not finished yet, will try again in {} seconds", processInstanceId,
+                    SLEEP_TIME_IN_SECONDS);
+            TimeUnit.SECONDS.sleep(SLEEP_TIME_IN_SECONDS);
+        }
+        logger.warn("Timeout {} process didn't finished ", processInstanceId);
+        return false;
+    }
+
+
+    public boolean isProcessEndedByProcessInstanceId(final String processInstanceId) {
+        return !isProcessInstanceActive(processInstanceId) && isProcessInstanceEnded(processInstanceId)
+                && isProcessInstanceCompleted(processInstanceId);
+    }
+
+    private boolean isProcessInstanceActive(final String processInstanceId) {
+        final HistoricProcessInstance processInstance = getHistoricProcessInstance(processInstanceId);
+        return processInstance != null && STATE_ACTIVE.equalsIgnoreCase(processInstance.getState());
+    }
+
+    private boolean isProcessInstanceEnded(final String processInstanceId) {
+        return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult() == null;
+    }
+
+    private boolean isProcessInstanceCompleted(final String processInstanceId) {
+        final HistoricProcessInstance result =
+                historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+        return result == null ? false : HistoricProcessInstance.STATE_COMPLETED.equalsIgnoreCase(result.getState());
+    }
+
+    public void createKubeConfigFile(final AsInst asInst) throws IOException {
+//        final MockMultipartFile file = new MockMultipartFile(KUBE_CONFIG_EMPTY_FILE_NAME, EMPTY.getBytes());
+//        kubConfigProvider.addKubeConfigFile(file, asInst.getCloudOwner(), asInst.getCloudRegion(),
+//                asInst.getTenantId());
+    }
+
+    public void deleteFoldersAndFiles(final Path path) throws IOException {
+        FileSystemUtils.deleteRecursively(path);
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/DefaultToShortClassNameBeanNameGenerator.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/DefaultToShortClassNameBeanNameGenerator.java
new file mode 100644 (file)
index 0000000..3ae5cac
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.bpmn.flows;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.AnnotationBeanNameGenerator;
+import org.springframework.util.ClassUtils;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class DefaultToShortClassNameBeanNameGenerator extends AnnotationBeanNameGenerator {
+
+    @Override
+    protected String buildDefaultBeanName(final BeanDefinition definition) {
+        return ClassUtils.getShortName(definition.getBeanClassName());
+    }
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/TestApplication.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/TestApplication.java
new file mode 100644 (file)
index 0000000..40868ab
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.bpmn.flows;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.context.annotation.ComponentScan.Filter;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@SpringBootApplication(scanBasePackages = {"org.onap.so"})
+@EnableAutoConfiguration(exclude = {JacksonAutoConfiguration.class})
+@ComponentScan(basePackages = {"org.onap"}, nameGenerator = DefaultToShortClassNameBeanNameGenerator.class,
+        excludeFilters = {@Filter(type = FilterType.ANNOTATION, classes = SpringBootApplication.class)})
+public class TestApplication {
+
+    public static void main(final String[] args) {
+        new SpringApplication(TestApplication.class).run(args);
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTaskTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTaskTest.java
new file mode 100644 (file)
index 0000000..bd0afe9
--- /dev/null
@@ -0,0 +1,191 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.bpmn.flows.tasks;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.notFound;
+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.put;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.onap.aaiclient.client.aai.AAIVersion.V19;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.CLOUD_OWNER_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.CLOUD_REGION_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.SERVICE_INSTANCE_ID_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.SERVICE_INSTANCE_NAME_PARAM_KEY;
+import static org.onap.so.cnfm.lcm.model.utils.AdditionalParamsConstants.TENANT_ID_PARAM_KEY;
+import static org.springframework.http.HttpHeaders.ACCEPT;
+import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import org.camunda.bpm.engine.history.HistoricProcessInstance;
+import org.camunda.bpm.engine.history.HistoricVariableInstance;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.aaiclient.client.aai.entities.Results;
+import org.onap.aaiclient.client.graphinventory.entities.Resource;
+import org.onap.so.cnfm.lcm.bpmn.flows.BaseTest;
+import org.onap.so.cnfm.lcm.bpmn.flows.service.JobExecutorService;
+import org.onap.so.cnfm.lcm.database.beans.Job;
+import org.onap.so.cnfm.lcm.database.beans.JobStatusEnum;
+import org.onap.so.cnfm.lcm.model.AsInstance;
+import org.onap.so.cnfm.lcm.model.AsInstance.InstantiationStateEnum;
+import org.onap.so.cnfm.lcm.model.CreateAsRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class CreateAsTaskTest extends BaseTest {
+    private static final String SRC_TEST_DIR = "src/test/resources";
+    private static final String TENAT_ID = UUID.randomUUID().toString();
+    private static final String CLOUD_OWNER = "CloudOwner";
+    private static final String CLOUD_REGION = "CloudRegion";
+    private static final String ASD_ID = UUID.randomUUID().toString();
+    private static final String AS_NAME = "CreateAsService-" + ASD_ID;
+    private static final String SDC_GET_RESOURCE_URL = "/sdc/v1/catalog/resources/" + ASD_ID + "/toscaModel";
+    private static final String RESOURCE_ASD_PACKAGE_CSAR_PATH =
+            SRC_TEST_DIR + "/resource-Generatedasdpackage-csar.csar";
+
+    @Autowired
+    private JobExecutorService objUnderTest;
+
+    @Before
+    public void before() {
+        wireMockServer.resetAll();
+    }
+
+    @After
+    public void after() {
+        wireMockServer.resetAll();
+    }
+
+    @Test
+    public void testCreateAsWorkflow_SuccessfullCase() throws InterruptedException, IOException {
+
+        wireMockServer.stubFor(get(SDC_GET_RESOURCE_URL)
+                .willReturn(aResponse().withBody(getFileContent(getAbsolutePath(RESOURCE_ASD_PACKAGE_CSAR_PATH)))
+                        .withHeader(ACCEPT, APPLICATION_OCTET_STREAM_VALUE)));
+
+        final CreateAsRequest createAsRequest = getCreateAsRequest();
+
+        mockAAIEndpoints();
+
+        final AsInstance nsResponse = objUnderTest.runCreateAsJob(createAsRequest);
+        assertNotNull(nsResponse);
+        assertNotNull(nsResponse.getAsInstanceid());
+
+        final Optional<Job> optional = getJobByResourceId(createAsRequest.getAsdId());
+        assertTrue(optional.isPresent());
+        final Job job = optional.get();
+
+        assertTrue(waitForProcessInstanceToFinish(job.getProcessInstanceId()));
+
+        final HistoricProcessInstance historicProcessInstance = getHistoricProcessInstance(job.getProcessInstanceId());
+        assertNotNull(historicProcessInstance);
+
+        assertEquals(HistoricProcessInstance.STATE_COMPLETED, historicProcessInstance.getState());
+        assertTrue(databaseServiceProvider.isAsInstExists(createAsRequest.getAsInstanceName()));
+
+        final Job actualJob = optional.get();
+        assertEquals(JobStatusEnum.FINISHED, actualJob.getStatus());
+
+        assertEquals(AS_NAME, nsResponse.getAsInstanceName());
+        assertEquals(InstantiationStateEnum.NOT_INSTANTIATED, nsResponse.getInstantiationState());
+
+        final HistoricVariableInstance doesNsPackageExistsVar =
+                getVariable(job.getProcessInstanceId(), "doesAsPackageExists");
+        assertNotNull(doesNsPackageExistsVar);
+        assertTrue((boolean) doesNsPackageExistsVar.getValue());
+
+        final HistoricVariableInstance doesNsInstanceExistsVar =
+                getVariable(job.getProcessInstanceId(), "doesAsInstanceExists");
+        assertNotNull(doesNsInstanceExistsVar);
+        assertFalse((boolean) doesNsInstanceExistsVar.getValue());
+
+    }
+
+    private CreateAsRequest getCreateAsRequest() {
+        return getCreateAsRequest(ASD_ID, AS_NAME);
+    }
+
+    private CreateAsRequest getCreateAsRequest(final String asdId, final String asName) {
+        final Map<String, Object> additionalParams = Map.of(SERVICE_INSTANCE_ID_PARAM_KEY, SERVICE_INSTANCE_ID,
+                SERVICE_INSTANCE_NAME_PARAM_KEY, SERVICE_INSTANCE_NAME, CLOUD_OWNER_PARAM_KEY, CLOUD_OWNER,
+                CLOUD_REGION_PARAM_KEY, CLOUD_REGION, TENANT_ID_PARAM_KEY, TENAT_ID);
+
+        return new CreateAsRequest().asdId(asdId).asInstanceName(asName).additionalParams(additionalParams);
+    }
+
+    private void mockAAIEndpoints() throws JsonProcessingException {
+        final String modelEndpoint = "/aai/" + V19 + "/network/generic-vnfs/generic-vnf/" + UUID_REGEX;
+
+        wireMockServer.stubFor(
+                get(urlMatching(modelEndpoint + "\\?resultIndex=0&resultSize=1&format=count")).willReturn(notFound()));
+
+        wireMockServer.stubFor(put(urlMatching(modelEndpoint)).willReturn(ok()));
+        wireMockServer.stubFor(put(urlMatching(modelEndpoint + "/relationship-list/relationship")).willReturn(ok()));
+
+        wireMockServer.stubFor(get(urlMatching(modelEndpoint)).willReturn(ok())
+                .willReturn(okJson("{\"orchestration-status\": \"Created\"}")));
+
+        wireMockServer.stubFor(get(urlMatching("/aai/" + V19 + "/nodes/service-instances/service-instance/.*"))
+                .willReturn(okJson(getResourceResultsResponseAsJson(SERVICE_INSTANCE_ID))));
+
+        wireMockServer.stubFor(put(urlMatching("/aai/" + V19 + "/cloud-infrastructure/cloud-regions/cloud-region/"
+                + CLOUD_OWNER + "/" + CLOUD_REGION + "/tenants/tenant/" + TENAT_ID + "/relationship-list/relationship"))
+                        .willReturn(ok()));
+
+    }
+
+    private String getResourceResultsResponseAsJson(final String nsdId) throws JsonProcessingException {
+        final Resource resource = new Resource();
+        resource.setResourceType("service-instance");
+        resource.setResourceLink("/aai/" + V19 + "/business/customers/customer/GLOBAL_CUSTOMER_ID"
+                + "/service-subscriptions/service-subscription/NetworkService/service-instances/service-instance/"
+                + nsdId);
+        final Results<Resource> results = new Results<>();
+        results.getResult().add(resource);
+        return new ObjectMapper().writeValueAsString(results);
+    }
+
+    private Path getAbsolutePath(final String path) {
+        final File file = new File(path);
+        return file.toPath();
+    }
+
+    private byte[] getFileContent(final Path path) throws IOException {
+        return Files.readAllBytes(path);
+    }
+}
index 404bbdb..72bc80f 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright © 2022 Nordix Foundation
+# Copyright © 2023 Nordix Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/pom.xml b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/pom.xml
new file mode 100644 (file)
index 0000000..b025d73
--- /dev/null
@@ -0,0 +1,69 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm</groupId>
+        <artifactId>so-cnfm-lcm</artifactId>
+        <version>1.9.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>so-cnfm-lcm-service</artifactId>
+    <name>SO CNFM LCM Service</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm</groupId>
+            <artifactId>so-cnfm-lcm-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm</groupId>
+            <artifactId>so-cnfm-lcm-bpmn-flows</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.so</groupId>
+            <artifactId>common</artifactId>
+            <version>${so-core-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/Constants.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/Constants.java
new file mode 100644 (file)
index 0000000..d7237c9
--- /dev/null
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+public class Constants {
+
+    public static final String SERVICE_NAME = "so-cnfm";
+    public static final String SERVICE_VERSION = "v1";
+    public static final String BASE_URL = "/so/" + SERVICE_NAME + "/" + SERVICE_VERSION + "/api";
+    public static final String AS_LIFE_CYCLE_MANAGEMENT_BASE_URL = BASE_URL + "/aslcm/v1";
+
+    private Constants() {}
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/GsonSerializerConfiguration.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/GsonSerializerConfiguration.java
new file mode 100644 (file)
index 0000000..f979f99
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm;
+
+import java.time.LocalDateTime;
+import org.onap.so.cnfm.lcm.bpmn.flows.utils.LocalDateTimeTypeAdapter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.google.gson.GsonBuilder;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Configuration
+public class GsonSerializerConfiguration {
+
+    @Bean
+    public GsonBuilder gsonBuilder() {
+        return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter());
+    }
+
+}
+
+
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/SoCnfmAsLcmManagerUrlProvider.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/SoCnfmAsLcmManagerUrlProvider.java
new file mode 100644 (file)
index 0000000..2e8aa05
--- /dev/null
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm;
+
+import java.net.URI;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Configuration
+public class SoCnfmAsLcmManagerUrlProvider {
+
+    private final String soCnfmLcmManagerEndpoint;
+
+    @Autowired
+    public SoCnfmAsLcmManagerUrlProvider(
+            @Value("${so-cnfm-lcm.endpoint:http://so-cnfm-lcm.onap:9888}") final String soCnfmLcmManagerEndpoint) {
+        this.soCnfmLcmManagerEndpoint = soCnfmLcmManagerEndpoint;
+    }
+
+    public URI getCreatedAsResourceUri(final String asInstanceId) {
+        return URI.create(soCnfmLcmManagerEndpoint + Constants.AS_LIFE_CYCLE_MANAGEMENT_BASE_URL + "/as_instances/"
+                + asInstanceId);
+    }
+
+    public URI getAsLcmOpOccUri(final String asLcmOpOccId) {
+        return URI.create(soCnfmLcmManagerEndpoint + Constants.AS_LIFE_CYCLE_MANAGEMENT_BASE_URL + "/as_lcm_op_occs/"
+                + asLcmOpOccId);
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLcmOperationOccurrenceManager.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLcmOperationOccurrenceManager.java
new file mode 100644 (file)
index 0000000..8bb1c6b
--- /dev/null
@@ -0,0 +1,125 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.lifecycle;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.util.Optional;
+import org.onap.so.cnfm.lcm.SoCnfmAsLcmManagerUrlProvider;
+import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider;
+import org.onap.so.cnfm.lcm.model.AsInstanceLinksSelf;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOcc;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOcc.CancelModeEnum;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOcc.OperationEnum;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOcc.OperationStateEnum;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOccLinks;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Service
+public class AsLcmOperationOccurrenceManager {
+    private static final Logger logger = getLogger(AsLcmOperationOccurrenceManager.class);
+    private final DatabaseServiceProvider databaseServiceProvider;
+    private final SoCnfmAsLcmManagerUrlProvider cnfmAsLcmManagerUrlProvider;
+
+    @Autowired
+    public AsLcmOperationOccurrenceManager(final DatabaseServiceProvider databaseServiceProvider,
+            final SoCnfmAsLcmManagerUrlProvider cnfmAsLcmManagerUrlProvider) {
+        this.databaseServiceProvider = databaseServiceProvider;
+        this.cnfmAsLcmManagerUrlProvider = cnfmAsLcmManagerUrlProvider;
+    }
+
+    public Optional<AsLcmOpOcc> getAsLcmOperationOccurrence(final String asLcmOpOccId) {
+        logger.info("Getting AS LCM Operation Occurrence Operation for id: {}", asLcmOpOccId);
+
+        final Optional<org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc> optionalDatabaseEntry =
+                databaseServiceProvider.getAsLcmOpOcc(asLcmOpOccId);
+
+        if (optionalDatabaseEntry.isEmpty()) {
+            logger.info("No AS LCM Operation Occurrence found for id: {}", asLcmOpOccId);
+            return Optional.empty();
+        }
+        logger.info("Found AS LCM Operation Occurrence for id: {}", asLcmOpOccId);
+        final org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc asLcmOpOccDatabaseEntry = optionalDatabaseEntry.get();
+        final AsLcmOpOcc asLcmOpOcc = convertToAsLcmOpOccsAsLcmOpOcc(asLcmOpOccDatabaseEntry);
+        return Optional.of(asLcmOpOcc);
+    }
+
+    private AsLcmOpOcc convertToAsLcmOpOccsAsLcmOpOcc(
+            final org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc databaseEntry) {
+
+        final AsLcmOpOcc asLcmOpOcc = new AsLcmOpOcc().id(databaseEntry.getId())
+                .stateEnteredTime(databaseEntry.getStateEnteredTime()).startTime(databaseEntry.getStartTime())
+                .isAutomaticInvocation(databaseEntry.getIsAutoInvocation())
+                .isCancelPending(databaseEntry.getIsCancelPending());
+
+        if (databaseEntry.getAsInst() != null) {
+            asLcmOpOcc.setAsInstanceId(databaseEntry.getAsInst().getAsInstId());
+        }
+
+        if (databaseEntry.getOperationState() != null) {
+            asLcmOpOcc.setOperationState(OperationStateEnum.fromValue(databaseEntry.getOperationState().toString()));
+        }
+
+        if (databaseEntry.getOperation() != null) {
+            asLcmOpOcc.setOperation(OperationEnum.fromValue(databaseEntry.getOperation().toString()));
+        }
+
+        if (databaseEntry.getOperationParams() != null) {
+            asLcmOpOcc.setOperationParams(databaseEntry.getOperationParams());
+        }
+
+        if (databaseEntry.getCancelMode() != null) {
+            asLcmOpOcc.setCancelMode(CancelModeEnum.fromValue(databaseEntry.getCancelMode().toString()));
+        }
+
+        asLcmOpOcc.setLinks(generateLinks(databaseEntry));
+
+        logger.info("Database AsLcmOpOcc converted to API AsLcmOpOcc successfully... {}", asLcmOpOcc);
+
+        return asLcmOpOcc;
+    }
+
+    private AsLcmOpOccLinks generateLinks(final org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc databaseEntry) {
+        logger.info("Generating links...");
+        final String asLcmOpOccId = databaseEntry.getId();
+
+        final AsInstanceLinksSelf asLcmOpOccLinksSelf =
+                new AsInstanceLinksSelf().href(cnfmAsLcmManagerUrlProvider.getAsLcmOpOccUri(asLcmOpOccId).toString());
+
+        final AsLcmOpOccLinks links = new AsLcmOpOccLinks().self(asLcmOpOccLinksSelf);
+
+        if (databaseEntry.getAsInst() != null) {
+            final String asInstId = databaseEntry.getAsInst().getAsInstId();
+            final AsInstanceLinksSelf asInstanceLinksSelf = new AsInstanceLinksSelf()
+                    .href(cnfmAsLcmManagerUrlProvider.getCreatedAsResourceUri(asInstId).toString());
+            links.setAsInstance(asInstanceLinksSelf);
+        }
+
+        return links;
+
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLifeCycleManager.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLifeCycleManager.java
new file mode 100644 (file)
index 0000000..7ba8f8b
--- /dev/null
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.lifecycle;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.net.URI;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.onap.so.cnfm.lcm.SoCnfmAsLcmManagerUrlProvider;
+import org.onap.so.cnfm.lcm.bpmn.flows.service.JobExecutorService;
+import org.onap.so.cnfm.lcm.model.AsInstance;
+import org.onap.so.cnfm.lcm.model.CreateAsRequest;
+import org.onap.so.cnfm.lcm.model.InstantiateAsRequest;
+import org.onap.so.cnfm.lcm.model.TerminateAsRequest;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Service
+public class AsLifeCycleManager {
+    private static final Logger logger = getLogger(AsLifeCycleManager.class);
+
+    private final JobExecutorService jobExecutorService;
+
+    private final SoCnfmAsLcmManagerUrlProvider cnfmAsLcmManagerUrlProvider;
+
+    @Autowired
+    public AsLifeCycleManager(final JobExecutorService jobExecutorService,
+            final SoCnfmAsLcmManagerUrlProvider cnfmAsLcmManagerUrlProvider) {
+        this.jobExecutorService = jobExecutorService;
+        this.cnfmAsLcmManagerUrlProvider = cnfmAsLcmManagerUrlProvider;
+    }
+
+    public ImmutablePair<URI, AsInstance> createAs(final CreateAsRequest createAsRequest) {
+        logger.info("Will execute Create AS for CreateAsRequest: {}", createAsRequest);
+
+        final AsInstance nsInstanceResponse = jobExecutorService.runCreateAsJob(createAsRequest);
+
+        return ImmutablePair.of(
+                cnfmAsLcmManagerUrlProvider.getCreatedAsResourceUri(nsInstanceResponse.getAsInstanceid()),
+                nsInstanceResponse);
+    }
+
+    public URI instantiateAs(final String asInstanceId, final InstantiateAsRequest instantiateAsRequest) {
+        logger.info("Will execute Instantiate AS for InstantiateAsRequest: {} and asInstanceId: {}",
+                instantiateAsRequest, asInstanceId);
+
+        final String asLcmOpOccId = jobExecutorService.runInstantiateAsJob(asInstanceId, instantiateAsRequest);
+        return cnfmAsLcmManagerUrlProvider.getAsLcmOpOccUri(asLcmOpOccId);
+
+    }
+
+    public URI terminateAs(final String asInstanceId, final TerminateAsRequest terminateAsRequest) {
+        logger.info("Will execute Terminate AS for TerminateAsRequest: {} and asInstanceId: {}", terminateAsRequest,
+                asInstanceId);
+
+        final String asLcmOpOccId = jobExecutorService.runTerminateAsJob(asInstanceId, terminateAsRequest);
+        return cnfmAsLcmManagerUrlProvider.getAsLcmOpOccUri(asLcmOpOccId);
+    }
+
+    public void deleteAs(final String asInstanceId) {
+        logger.info("Will execute Delete AS for asInstanceId: {}", asInstanceId);
+        jobExecutorService.runDeleteAsJob(asInstanceId);
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesController.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesController.java
new file mode 100644 (file)
index 0000000..8c25d20
--- /dev/null
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.rest;
+
+import static org.onap.so.cnfm.lcm.Constants.AS_LIFE_CYCLE_MANAGEMENT_BASE_URL;
+import static org.slf4j.LoggerFactory.getLogger;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import org.onap.so.cnfm.lcm.lifecycle.AsLcmOperationOccurrenceManager;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOcc;
+import org.onap.so.cnfm.lcm.model.ErrorDetails;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Controller
+@RequestMapping(value = AS_LIFE_CYCLE_MANAGEMENT_BASE_URL)
+public class AsLcmOperationOccurrencesController {
+    private static final Logger logger = getLogger(AsLcmOperationOccurrencesController.class);
+    private final AsLcmOperationOccurrenceManager asLcmOperationOccurrenceManager;
+
+    @Autowired
+    public AsLcmOperationOccurrencesController(final AsLcmOperationOccurrenceManager asLcmOperationOccurrenceManager) {
+        this.asLcmOperationOccurrenceManager = asLcmOperationOccurrenceManager;
+    }
+
+    @GetMapping(value = "/as_lcm_op_occs/{asLcmOpOccId}",
+            produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public ResponseEntity<?> getOperationStatus(@PathVariable("asLcmOpOccId") final String asLcmOpOccId) {
+        logger.info("Received request to retrieve operation status for asLcmOpOccId: {}", asLcmOpOccId);
+        final Optional<AsLcmOpOcc> optionalAsLcmOpOccs =
+                asLcmOperationOccurrenceManager.getAsLcmOperationOccurrence(asLcmOpOccId);
+
+        if (optionalAsLcmOpOccs.isPresent()) {
+            final AsLcmOpOcc asLcmOpOcc = optionalAsLcmOpOccs.get();
+            logger.info("Sending back AsLcmOpOcc: {}", asLcmOpOcc);
+            return ResponseEntity.ok().body(asLcmOpOcc);
+        }
+
+        final String errorMessage = "Unable to retrieve operation occurrence status for asLcmOpOccId: " + asLcmOpOccId;
+        logger.error(errorMessage);
+        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorDetails().detail(errorMessage));
+    }
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLifecycleManagementController.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLifecycleManagementController.java
new file mode 100644 (file)
index 0000000..698ef7c
--- /dev/null
@@ -0,0 +1,107 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.rest;
+
+import static org.onap.so.cnfm.lcm.Constants.AS_LIFE_CYCLE_MANAGEMENT_BASE_URL;
+import static org.slf4j.LoggerFactory.getLogger;
+import java.net.URI;
+import javax.ws.rs.core.MediaType;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.onap.so.cnfm.lcm.lifecycle.AsLifeCycleManager;
+import org.onap.so.cnfm.lcm.model.AsInstance;
+import org.onap.so.cnfm.lcm.model.CreateAsRequest;
+import org.onap.so.cnfm.lcm.model.InstantiateAsRequest;
+import org.onap.so.cnfm.lcm.model.TerminateAsRequest;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@Controller
+@RequestMapping(value = AS_LIFE_CYCLE_MANAGEMENT_BASE_URL)
+public class AsLifecycleManagementController {
+    private static final Logger logger = getLogger(AsLifecycleManagementController.class);
+
+    private final AsLifeCycleManager asLifeCycleManager;
+
+    @Autowired
+    public AsLifecycleManagementController(final AsLifeCycleManager asLifeCycleManager) {
+        this.asLifeCycleManager = asLifeCycleManager;
+    }
+
+    @PostMapping(value = "/as_instances", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML},
+            consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public ResponseEntity<AsInstance> createAs(@RequestBody final CreateAsRequest createAsRequest) {
+        logger.info("Received Create AS Request: {}n", createAsRequest);
+
+        final ImmutablePair<URI, AsInstance> nsInstance = asLifeCycleManager.createAs(createAsRequest);
+
+        final URI resourceUri = nsInstance.getLeft();
+        final AsInstance createdAsresponse = nsInstance.getRight();
+
+        logger.info("AS resource created successfully. Resource location: {}, response: {}", resourceUri,
+                createdAsresponse);
+
+        return ResponseEntity.created(resourceUri).body(createdAsresponse);
+    }
+
+    @PostMapping(value = "/as_instances/{asInstanceId}/instantiate",
+            produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML},
+            consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public ResponseEntity<Void> instantiateAs(@PathVariable("asInstanceId") final String asInstanceId,
+            @RequestBody final InstantiateAsRequest instantiateAsRequest) {
+        logger.debug("Received instantiate AS request: {}\n with asInstanceId: {}", instantiateAsRequest, asInstanceId);
+        final URI resourceUri = asLifeCycleManager.instantiateAs(asInstanceId, instantiateAsRequest);
+        logger.info("{} AS Instantiation started successfully. Resource Operation Occurrence uri: {}", asInstanceId,
+                resourceUri);
+        return ResponseEntity.accepted().location(resourceUri).build();
+    }
+
+    @PostMapping(value = "/as_instances/{asInstanceId}/terminate",
+            produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML},
+            consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public ResponseEntity<Void> terminateAs(@PathVariable("asInstanceId") final String asInstanceId,
+            @RequestBody(required = false) final TerminateAsRequest terminateAsRequest) {
+        logger.debug("Received terminate AS request: {}\n with asInstanceId: {}", terminateAsRequest, asInstanceId);
+        final URI resourceUri = asLifeCycleManager.terminateAs(asInstanceId, terminateAsRequest);
+        logger.info("{} As Terminate started successfully. Resource Operation Occurrence uri: {}", asInstanceId,
+                resourceUri);
+        return ResponseEntity.accepted().location(resourceUri).build();
+    }
+
+    @DeleteMapping(value = "/as_instances/{asInstanceId}",
+            produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    public ResponseEntity<Void> deleteAs(@PathVariable("asInstanceId") final String asInstanceId) {
+        logger.debug("Received delete AS request for asInstanceId: {}", asInstanceId);
+        asLifeCycleManager.deleteAs(asInstanceId);
+        logger.info("Successfully deleted AS for asInstanceId: {}", asInstanceId);
+        return ResponseEntity.noContent().build();
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/TestApplication.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/TestApplication.java
new file mode 100644 (file)
index 0000000..c2775fb
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+
+/**
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@SpringBootApplication(scanBasePackages = {"org.onap.so"})
+@EnableAutoConfiguration(exclude = {JacksonAutoConfiguration.class})
+public class TestApplication {
+    public static void main(final String[] args) {
+        new SpringApplication(TestApplication.class).run(args);
+    }
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesControllerTest.java b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesControllerTest.java
new file mode 100644 (file)
index 0000000..c3dd4d0
--- /dev/null
@@ -0,0 +1,125 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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.cnfm.lcm.rest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import java.time.LocalDateTime;
+import java.util.UUID;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.so.cnfm.lcm.Constants;
+import org.onap.so.cnfm.lcm.TestApplication;
+import org.onap.so.cnfm.lcm.bpmn.flows.GsonProvider;
+import org.onap.so.cnfm.lcm.database.beans.AsInst;
+import org.onap.so.cnfm.lcm.database.beans.AsLcmOpType;
+import org.onap.so.cnfm.lcm.database.beans.OperationStateEnum;
+import org.onap.so.cnfm.lcm.database.beans.State;
+import org.onap.so.cnfm.lcm.database.service.DatabaseServiceProvider;
+import org.onap.so.cnfm.lcm.model.AsLcmOpOcc;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.json.GsonHttpMessageConverter;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import com.google.gson.Gson;
+
+/**
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ *
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+public class AsLcmOperationOccurrencesControllerTest {
+
+    private static final String AS_LCM_OP_OCCS = "/as_lcm_op_occs/";
+
+    @LocalServerPort
+    private int port;
+
+    @Autowired
+    private DatabaseServiceProvider databaseServiceProvider;
+
+    @Autowired
+    private GsonProvider gsonProvider;
+
+    private TestRestTemplate testRestTemplate;
+
+    @Before
+    public void setUp() {
+        final Gson gson = gsonProvider.getGson();
+        testRestTemplate = new TestRestTemplate(
+                new RestTemplateBuilder().additionalMessageConverters(new GsonHttpMessageConverter(gson)));
+    }
+
+    @Test
+    public void testGetOperationStatus_validAsLcmOpOccId_returnsAsLcmOpOcc() {
+        final String asLcmOpOccId = addDummyAsLcmOpOccToDatabase();
+        final String baseUrl = getAsLcmBaseUrl() + AS_LCM_OP_OCCS + asLcmOpOccId;
+        final HttpEntity<?> request = new HttpEntity<>(new HttpHeaders());
+        final ResponseEntity<AsLcmOpOcc> responseEntity =
+                testRestTemplate.exchange(baseUrl, HttpMethod.GET, request, AsLcmOpOcc.class);
+        assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
+        assertTrue(responseEntity.hasBody());
+        assertNotNull(responseEntity.getBody());
+    }
+
+
+    private String getAsLcmBaseUrl() {
+        return "http://localhost:" + port + Constants.AS_LIFE_CYCLE_MANAGEMENT_BASE_URL;
+    }
+
+
+    private String addDummyAsLcmOpOccToDatabase() {
+        final LocalDateTime now = LocalDateTime.now();
+        final AsInst asInst = new AsInst().name("name").asdId(UUID.randomUUID().toString())
+                .status(State.NOT_INSTANTIATED).asdInvariantId(UUID.randomUUID().toString()).statusUpdatedTime(now)
+                .asApplicationName("asApplicationName").asApplicationVersion("asApplicationVersion")
+                .asProvider("asProvider").serviceInstanceId(UUID.randomUUID().toString())
+                .serviceInstanceName("serviceInstanceName").cloudOwner("cloudOwner").cloudRegion("cloudRegion")
+                .tenantId("tenantId");
+
+        databaseServiceProvider.saveAsInst(asInst);
+
+        final org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc databaseEntry =
+                new org.onap.so.cnfm.lcm.database.beans.AsLcmOpOcc();
+
+        databaseEntry.asInst(asInst).operationState(OperationStateEnum.PROCESSING).isCancelPending(false)
+                .isAutoInvocation(false).operation(AsLcmOpType.INSTANTIATE).startTime(now).stateEnteredTime(now)
+                .operationParams("");
+
+        databaseServiceProvider.addAsLcmOpOcc(databaseEntry);
+
+        return databaseEntry.getId();
+    }
+
+}
diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/resources/application.yaml b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/resources/application.yaml
new file mode 100644 (file)
index 0000000..2b590b2
--- /dev/null
@@ -0,0 +1,43 @@
+# Copyright © 2023 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.
+spring:
+   main:
+      allow-bean-definition-overriding: true
+   datasource:
+      hikari:
+         camunda:
+            jdbcUrl: jdbc:h2:mem:example-simple;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+            driver-class-name: org.h2.Driver
+            pool-name: cnfm-lcm-bpmn-pool
+            registerMbeans: true
+         cnfm:
+            jdbcUrl: jdbc:h2:mem:nfvo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS cnfm;MODE=MYSQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE
+            driver-class-name: org.h2.Driver
+            pool-name: cnfm-lcm-bpmn-pool
+            registerMbeans: true
+   jpa:
+      generate-ddl: true
+      hibernate:
+         ddl-auto: create
+hibernate:
+   dialect: org.hibernate.dialect.H2Dialect
+   hbm2ddl:
+      auto: create
+logging:
+   level:
+      org.reflections.Reflections: ERROR
+cnfm:
+   kube-configs-dir: ${java.io.tmpdir}/kube-configs
+   csar:
+      dir: ${java.io.tmpdir}
\ No newline at end of file