From 9783df1b5660ee0e0460cfd8dc5477a7edcb1d94 Mon Sep 17 00:00:00 2001 From: "waqas.ikram" Date: Mon, 23 Jan 2023 14:59:18 +0000 Subject: Adding Create AS support Change-Id: I4b1d417c7f20d67d5fb0d05718819186f8dd3bea Issue-ID: SO-4068 Signed-off-by: waqas.ikram --- so-cnfm/so-cnfm-lcm/pom.xml | 1 + .../lcm/bpmn/flows/tasks/AbstractServiceTask.java | 208 +++++++++++++ .../so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java | 342 +++++++++++++++++++++ .../src/main/resources/CreateAs.bpmn | 266 ++++++++++++++++ .../org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java | 181 +++++++++++ .../DefaultToShortClassNameBeanNameGenerator.java | 37 +++ .../so/cnfm/lcm/bpmn/flows/TestApplication.java | 45 +++ .../lcm/bpmn/flows/tasks/CreateAsTaskTest.java | 191 ++++++++++++ .../src/test/resources/application.yaml | 2 +- so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/pom.xml | 69 +++++ .../main/java/org/onap/so/cnfm/lcm/Constants.java | 35 +++ .../so/cnfm/lcm/GsonSerializerConfiguration.java | 42 +++ .../so/cnfm/lcm/SoCnfmAsLcmManagerUrlProvider.java | 53 ++++ .../lifecycle/AsLcmOperationOccurrenceManager.java | 125 ++++++++ .../so/cnfm/lcm/lifecycle/AsLifeCycleManager.java | 86 ++++++ .../rest/AsLcmOperationOccurrencesController.java | 71 +++++ .../lcm/rest/AsLifecycleManagementController.java | 107 +++++++ .../java/org/onap/so/cnfm/lcm/TestApplication.java | 37 +++ .../AsLcmOperationOccurrencesControllerTest.java | 125 ++++++++ .../src/test/resources/application.yaml | 43 +++ 20 files changed, 2065 insertions(+), 1 deletion(-) create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/AbstractServiceTask.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/CreateAs.bpmn create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/DefaultToShortClassNameBeanNameGenerator.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/TestApplication.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTaskTest.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/pom.xml create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/Constants.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/GsonSerializerConfiguration.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/SoCnfmAsLcmManagerUrlProvider.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLcmOperationOccurrenceManager.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLifeCycleManager.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesController.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLifecycleManagementController.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/TestApplication.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesControllerTest.java create mode 100644 so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/resources/application.yaml diff --git a/so-cnfm/so-cnfm-lcm/pom.xml b/so-cnfm/so-cnfm-lcm/pom.xml index ad758d1..0b1dd81 100644 --- a/so-cnfm/so-cnfm-lcm/pom.xml +++ b/so-cnfm/so-cnfm-lcm/pom.xml @@ -15,5 +15,6 @@ so-cnfm-lcm-api so-cnfm-lcm-database-service so-cnfm-lcm-bpmn-flows + so-cnfm-lcm-service \ 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 index 0000000..45d7806 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/AbstractServiceTask.java @@ -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 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 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 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 index 0000000..85af369 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTask.java @@ -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 optional = sdcPackageProvider.getSdcResourcePackage(createAsRequest.getAsdId()); + + if (optional.isPresent()) { + logger.info("ASD Package exists for asdId {}", createAsRequest.getAsdId()); + + final Map 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 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 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 asdProperties = + (Map) 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 deploymentItems = + (List) 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 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 getLifeCycleParams(final AsDeploymentItem asDeploymentItem, + final DeploymentItem deploymentItem) { + final List 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 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 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 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 index 0000000..f828e6d --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/main/resources/CreateAs.bpmn @@ -0,0 +1,266 @@ + + + + + Flow_1tqn5q5 + + + Flow_0t87ov3 + + + + Flow_1tqn5q5 + Flow_0y07mxe + + + + Flow_1rtsvpm + Flow_0t87ov3 + + + + Flow_09582uw + Flow_1f4vi10 + Flow_0qabgp7 + + + Flow_0y07mxe + Flow_09582uw + + + + + Flow_0554tjv + + + + Flow_04xvpee + + + + Flow_0554tjv + Flow_04xvpee + + + + + + Flow_0j1otrx + + + + Flow_0oqv7vl + + + + Flow_0j1otrx + Flow_0oqv7vl + + + + + #{not doesAsPackageExists} + + + Flow_1f4vi10 + Flow_1yql1cm + + + + #{doesAsPackageExists} + + + Flow_0qabgp7 + Flow_1exrj2b + + + + Flow_1exrj2b + Flow_1rkg44s + Flow_1yql1cm + + + #{not doesAsInstanceExists} + + + #{doesAsInstanceExists} + + + Flow_1rkg44s + Flow_1jvfwd2 + + + + Flow_1jvfwd2 + Flow_0e5hvno + + + + Flow_0e5hvno + Flow_1rtsvpm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 index 0000000..9920ab9 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/BaseTest.java @@ -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 getJob(final String jobId) { + return databaseServiceProvider.getJob(jobId); + } + + public Optional getJobByResourceId(final String resourceId) { + return databaseServiceProvider.getJobByResourceId(resourceId); + } + + public ProcessInstance executeWorkflow(final String processDefinitionKey, final String businessKey, + final Map 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 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 index 0000000..3ae5cac --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/DefaultToShortClassNameBeanNameGenerator.java @@ -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 index 0000000..40868ab --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/TestApplication.java @@ -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 index 0000000..bd0afe9 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/java/org/onap/so/cnfm/lcm/bpmn/flows/tasks/CreateAsTaskTest.java @@ -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 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 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 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); + } +} diff --git a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml index 404bbdb..72bc80f 100644 --- a/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-bpmn-flows/src/test/resources/application.yaml @@ -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 index 0000000..b025d73 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm + so-cnfm-lcm + 1.9.0-SNAPSHOT + + + so-cnfm-lcm-service + SO CNFM LCM Service + + + + org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm + so-cnfm-lcm-api + ${project.version} + + + org.onap.so.adapters.so-cnf-adapter.so-cnfm.lcm + so-cnfm-lcm-bpmn-flows + ${project.version} + + + org.springframework.boot + spring-boot-starter-web + + + com.fasterxml.jackson.core + jackson-databind + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.onap.so + common + ${so-core-version} + + + org.springframework.boot + spring-boot-starter-test + test + + + junit + junit + test + + + com.h2database + h2 + test + + + \ 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 index 0000000..d7237c9 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/Constants.java @@ -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 index 0000000..f979f99 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/GsonSerializerConfiguration.java @@ -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 index 0000000..2e8aa05 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/SoCnfmAsLcmManagerUrlProvider.java @@ -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 index 0000000..8bb1c6b --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLcmOperationOccurrenceManager.java @@ -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 getAsLcmOperationOccurrence(final String asLcmOpOccId) { + logger.info("Getting AS LCM Operation Occurrence Operation for id: {}", asLcmOpOccId); + + final Optional 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 index 0000000..7ba8f8b --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/lifecycle/AsLifeCycleManager.java @@ -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 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 index 0000000..8c25d20 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesController.java @@ -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 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 index 0000000..698ef7c --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/main/java/org/onap/so/cnfm/lcm/rest/AsLifecycleManagementController.java @@ -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 createAs(@RequestBody final CreateAsRequest createAsRequest) { + logger.info("Received Create AS Request: {}n", createAsRequest); + + final ImmutablePair 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 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 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 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 index 0000000..c2775fb --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/TestApplication.java @@ -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 index 0000000..c3dd4d0 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/java/org/onap/so/cnfm/lcm/rest/AsLcmOperationOccurrencesControllerTest.java @@ -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 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 index 0000000..2b590b2 --- /dev/null +++ b/so-cnfm/so-cnfm-lcm/so-cnfm-lcm-service/src/test/resources/application.yaml @@ -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 -- cgit 1.2.3-korg