diff options
author | Jozsef Csongvai <jozsef.csongvai@bell.ca> | 2021-01-12 09:12:23 -0500 |
---|---|---|
committer | Jozsef Csongvai <jozsef.csongvai@bell.ca> | 2021-08-04 08:55:43 -0400 |
commit | 30106b39d2ac1bc206134cfcb8fc73eb1f29b923 (patch) | |
tree | be83e5d35925fdd87c39cba7607feaefc23c34b5 /bpmn/so-bpmn-tasks | |
parent | 872613eafe80034cca612bd93294286b3dbed4b1 (diff) |
Add new endpoint and macro for service upgrade
This enables upgrading an existing service instance by
updating its model UUID's in AAI and md-sal.
Issue-ID: SO-3636
Signed-off-by: Jozsef Csongvai <jozsef.csongvai@bell.ca>
Change-Id: Ic5f067a1267053a61f46e2d9563ca4e4ac869bdf
Diffstat (limited to 'bpmn/so-bpmn-tasks')
7 files changed, 307 insertions, 2 deletions
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/Resource.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/Resource.java index 99cff932c5..2a8852a4bd 100644 --- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/Resource.java +++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/Resource.java @@ -22,12 +22,14 @@ package org.onap.so.bpmn.infrastructure.workflow.tasks; +import java.io.Serializable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -public class Resource { +public class Resource implements Serializable { + private static final long serialVersionUID = 4259534487473481127L; private String resourceId; private WorkflowType resourceType; private boolean generated; @@ -37,6 +39,7 @@ public class Resource { private String vfModuleCustomizationId; private String cvnfModuleCustomizationId; private String instanceName; + private String modelInvariantId; private int processingPriority; private Resource parent; private List<Resource> children; @@ -129,6 +132,15 @@ public class Resource { this.instanceName = instanceName; } + public String getModelInvariantId() { + return modelInvariantId; + } + + public void setModelInvariantId(String modelInvariantId) { + this.modelInvariantId = modelInvariantId; + } + + public int getProcessingPriority() { return processingPriority == 0 ? (isBaseVfModule() ? Integer.MIN_VALUE + 1 : 0) : processingPriority; } diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowAction.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowAction.java index e49aed8b25..02508b8867 100644 --- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowAction.java +++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowAction.java @@ -355,6 +355,7 @@ public class WorkflowAction { } else { updateResourceIdsFromAAITraversal(flowsToExecute, resourceList, aaiResourceIds, serviceInstanceId); } + execution.setVariable("resources", resourceList); return flowsToExecute; } diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowActionConstants.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowActionConstants.java index 38ba0077e2..8c6fb2b38b 100644 --- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowActionConstants.java +++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowActionConstants.java @@ -39,6 +39,7 @@ public final class WorkflowActionConstants { public static final String CREATE_INSTANCE = "createInstance"; public static final String DEACTIVATE_INSTANCE = "deactivateInstance"; public static final String DELETE_INSTANCE = "deleteInstance"; + public static final String UPGRADE_INSTANCE = "upgradeInstance"; public static final String FABRIC_CONFIGURATION = "FabricConfiguration"; public static final String NETWORKCOLLECTION = "NetworkCollection"; public static final String RECREATE_INSTANCE = "recreateInstance"; diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/ebb/loader/ServiceEBBLoader.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/ebb/loader/ServiceEBBLoader.java index e4c6d2951f..c000e9475c 100644 --- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/ebb/loader/ServiceEBBLoader.java +++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/ebb/loader/ServiceEBBLoader.java @@ -61,6 +61,7 @@ import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConst import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.DEACTIVATE_INSTANCE; import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.DELETE_INSTANCE; import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.UNASSIGN_INSTANCE; +import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.UPGRADE_INSTANCE; import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.WORKFLOW_ACTION_ERROR_MESSAGE; import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.CREATE_INSTANCE; import static org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowActionConstants.FABRIC_CONFIGURATION; @@ -136,6 +137,7 @@ public class ServiceEBBLoader { } } else if ((ACTIVATE_INSTANCE.equalsIgnoreCase(requestAction) || UNASSIGN_INSTANCE.equalsIgnoreCase(requestAction) || DELETE_INSTANCE.equalsIgnoreCase(requestAction) + || UPGRADE_INSTANCE.equalsIgnoreCase(requestAction) || requestAction.equalsIgnoreCase("activate" + FABRIC_CONFIGURATION))) { // SERVICE-MACRO-ACTIVATE, SERVICE-MACRO-UNASSIGN, and // SERVICE-MACRO-DELETE @@ -193,8 +195,9 @@ public class ServiceEBBLoader { ServiceInstance serviceInstanceAAI = bbInputSetupUtils.getAAIServiceInstanceById(resourceId); org.onap.so.bpmn.servicedecomposition.bbobjects.ServiceInstance serviceInstanceMSO = bbInputSetup.getExistingServiceInstance(serviceInstanceAAI); - Resource serviceResource = + var serviceResource = new Resource(WorkflowType.SERVICE, serviceInstanceMSO.getServiceInstanceId(), false, null); + serviceResource.setModelInvariantId(serviceInstanceAAI.getModelInvariantId()); resourceList.add(serviceResource); traverseServiceInstanceMSOVnfs(resourceList, serviceResource, aaiResourceIds, serviceInstanceMSO); traverseServiceInstanceMSOPnfs(resourceList, serviceResource, aaiResourceIds, serviceInstanceMSO); diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidator.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidator.java new file mode 100644 index 0000000000..5e82b4f284 --- /dev/null +++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidator.java @@ -0,0 +1,114 @@ +package org.onap.so.bpmn.infrastructure.workflow.tasks.validators; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import org.onap.so.bpmn.common.BBConstants; +import org.onap.so.bpmn.common.BuildingBlockExecution; +import org.onap.so.bpmn.common.listener.validation.PreWorkflowValidator; +import org.onap.so.bpmn.infrastructure.workflow.tasks.Resource; +import org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowType; +import org.onap.so.db.catalog.beans.Service; +import org.onap.so.db.catalog.beans.VnfResourceCustomization; +import org.onap.so.db.catalog.client.CatalogDbClient; +import org.onap.so.serviceinstancebeans.RequestDetails; +import org.onap.so.serviceinstancebeans.ServiceInstancesRequest; +import org.springframework.stereotype.Component; + +@Component +public class UpgradePreWorkflowValidator implements PreWorkflowValidator { + + private static final String ERR_MSG_INVARIANT_MISMATCH = + "Request service modelInvariantId: %s does not match AAI service modelInvariantId: %s"; + private static final String ERR_MSG_EXISTING_VNFS_NOT_SUPPORTED = + "Existing vnfs in AAI are not supported by service model. Unsupported vnfCustomizationIds: %s"; + + private final CatalogDbClient catalogDbClient; + + private static final Function<WorkflowType, Predicate<Resource>> resourceType = + workflowType -> resource -> resource.getResourceType() == workflowType; + + public UpgradePreWorkflowValidator(CatalogDbClient catalogDbClient) { + this.catalogDbClient = catalogDbClient; + } + + @Override + public boolean shouldRunFor(String requestAction) { + return "upgradeInstance".equalsIgnoreCase(requestAction); + } + + @Override + public Optional<String> validate(BuildingBlockExecution execution) { + final String bpmnRequest = execution.getVariable(BBConstants.G_BPMN_REQUEST); + List<Resource> resources = execution.getVariable("resources"); + + Optional<ServiceInstancesRequest> sir = parseBpmnRequest(bpmnRequest); + if (sir.isEmpty()) { + return Optional.of("Failed to parse bpmnRequest"); + } + var requestDetails = sir.get().getRequestDetails(); + String requestModelInvariantId = requestDetails.getModelInfo().getModelInvariantId(); + + Optional<String> modelInvariantMismatch = validateInvariantId(resources, requestModelInvariantId); + if (modelInvariantMismatch.isPresent()) { + return modelInvariantMismatch; + } + + List<Resource> aaiVnfResources = getVnfResources(resources); + if (aaiVnfResources.isEmpty()) { + return Optional.empty(); + } + + String serviceModelUuid = requestDetails.getModelInfo().getModelUuid(); + Optional<List<VnfResourceCustomization>> vnfResourceCustomizations = + getVnfResourceCustomizations(serviceModelUuid); + if (vnfResourceCustomizations.isEmpty()) { + return Optional.of(String.format("Service model: %s does not exist in catalog db.", serviceModelUuid)); + } + + return validateExistingVnfsSupported(aaiVnfResources, vnfResourceCustomizations.get()); + } + + private Optional<ServiceInstancesRequest> parseBpmnRequest(String bpmnRequest) { + try { + return Optional.of(new ObjectMapper().readValue(bpmnRequest, ServiceInstancesRequest.class)); + } catch (IOException e) { + return Optional.empty(); + } + } + + private Optional<String> validateInvariantId(List<Resource> resources, String requestModelInvariantId) { + return resources.stream().filter(resourceType.apply(WorkflowType.SERVICE)).findFirst() + .filter(r -> !r.getModelInvariantId().equals(requestModelInvariantId)) + .map(r -> String.format(ERR_MSG_INVARIANT_MISMATCH, requestModelInvariantId, r.getModelInvariantId())); + } + + private Optional<List<VnfResourceCustomization>> getVnfResourceCustomizations(String serviceModelUuid) { + return Optional.ofNullable(catalogDbClient.getServiceByModelUUID(serviceModelUuid)) + .map(Service::getVnfCustomizations); + } + + private List<Resource> getVnfResources(List<Resource> resources) { + return resources.stream().filter(resourceType.apply(WorkflowType.VNF)).collect(Collectors.toList()); + } + + private Optional<String> validateExistingVnfsSupported(List<Resource> vnfResources, + List<VnfResourceCustomization> vnfResourceCustomizations) { + Set<String> modeledVnfCustomizationIds = vnfResourceCustomizations.stream() + .map(VnfResourceCustomization::getModelCustomizationUUID).collect(Collectors.toSet()); + + String unsupportedVnfCustomizationIds = vnfResources.stream().map(Resource::getVnfCustomizationId) + .filter(id -> !modeledVnfCustomizationIds.contains(id)).collect(Collectors.joining(",")); + + if (unsupportedVnfCustomizationIds.isEmpty()) { + return Optional.empty(); + } + return Optional.of(String.format(ERR_MSG_EXISTING_VNFS_NOT_SUPPORTED, unsupportedVnfCustomizationIds)); + } + +} diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/client/orchestration/AAIServiceInstanceResources.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/client/orchestration/AAIServiceInstanceResources.java index cc99f178bd..8c1e8f6d62 100644 --- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/client/orchestration/AAIServiceInstanceResources.java +++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/client/orchestration/AAIServiceInstanceResources.java @@ -181,9 +181,27 @@ public class AAIServiceInstanceResources { .createResourceUri(Types.SERVICE_INSTANCE.getFragment(serviceInstance.getServiceInstanceId())); org.onap.aai.domain.yang.ServiceInstance aaiServiceInstance = aaiObjectMapper.mapServiceInstance(serviceInstance); + mapEmptyStringsToNull(aaiServiceInstance); injectionHelper.getAaiClient().update(serviceInstanceURI, aaiServiceInstance); } + /* + * Per serialization configurations in GraphInventoryCommonObjectMapperPatchProvider, empty strings are mapped to + * null and included in the payload. Null values are on the other hand excluded. Passing null values in a PATCH + * request to AAI will fail. We need to map empty strings to null before serialization in order to exclude these + * values from the payload. + */ + private void mapEmptyStringsToNull(org.onap.aai.domain.yang.ServiceInstance serviceInstance) { + if (serviceInstance != null) { + if ("".equals(serviceInstance.getServiceType())) + serviceInstance.setServiceType(null); + if ("".equals(serviceInstance.getServiceRole())) + serviceInstance.setServiceRole(null); + if ("".equals(serviceInstance.getServiceFunction())) + serviceInstance.setServiceFunction(null); + } + } + public boolean checkInstanceServiceNameInUse(ServiceInstance serviceInstance) { AAIPluralResourceUri uriSI = AAIUriFactory.createNodesUri(Types.SERVICE_INSTANCES.getFragment()) .queryParam("service-instance-name", serviceInstance.getServiceInstanceName()); diff --git a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidatorTest.java b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidatorTest.java new file mode 100644 index 0000000000..1066ca1317 --- /dev/null +++ b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidatorTest.java @@ -0,0 +1,156 @@ +package org.onap.so.bpmn.infrastructure.workflow.tasks.validators; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.onap.so.bpmn.common.BBConstants; +import org.onap.so.bpmn.common.BuildingBlockExecution; +import org.onap.so.bpmn.infrastructure.workflow.tasks.Resource; +import org.onap.so.bpmn.infrastructure.workflow.tasks.WorkflowType; +import org.onap.so.db.catalog.beans.Service; +import org.onap.so.db.catalog.beans.VnfResourceCustomization; +import org.onap.so.db.catalog.client.CatalogDbClient; +import org.onap.so.serviceinstancebeans.ModelInfo; +import org.onap.so.serviceinstancebeans.RequestDetails; +import org.onap.so.serviceinstancebeans.ServiceInstancesRequest; + +public class UpgradePreWorkflowValidatorTest { + + @Mock + private CatalogDbClient catalogDbClient; + + private UpgradePreWorkflowValidator validator; + + private ObjectMapper objectMapper; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + validator = new UpgradePreWorkflowValidator(catalogDbClient); + objectMapper = new ObjectMapper(); + } + + @Test + public void shouldRunFor() { + assertTrue(validator.shouldRunFor("upgradeInstance")); + assertFalse(validator.shouldRunFor("createInstance")); + } + + private BuildingBlockExecution createExecution(ServiceInstancesRequest sir, List<Resource> resourceList) + throws JsonProcessingException { + BuildingBlockExecution mock = Mockito.mock(BuildingBlockExecution.class); + String jsonSir = objectMapper.writer().writeValueAsString(sir); + when(mock.getVariable(BBConstants.G_BPMN_REQUEST)).thenReturn(jsonSir); + when(mock.getVariable("resources")).thenReturn(resourceList); + return mock; + } + + @Test + public void validateModelInvariantMismatch() throws JsonProcessingException { + ServiceInstancesRequest sir = new ServiceInstancesRequest(); + sir.setRequestDetails(new RequestDetails()); + sir.getRequestDetails().setModelInfo(new ModelInfo()); + sir.getRequestDetails().getModelInfo().setModelInvariantId(UUID.randomUUID().toString()); + + Resource serviceResource = new Resource(WorkflowType.SERVICE, "", false, null); + String aaiModelInvariantId = UUID.randomUUID().toString(); + serviceResource.setModelInvariantId(aaiModelInvariantId); + + BuildingBlockExecution execution = createExecution(sir, Arrays.asList(serviceResource)); + + Optional<String> message = validator.validate(execution); + + assertTrue(message.isPresent()); + assertTrue(message.get().startsWith("Request service modelInvariantId")); + } + + @Test + public void validateNoVnfsInAAI() throws JsonProcessingException { + ServiceInstancesRequest sir = new ServiceInstancesRequest(); + sir.setRequestDetails(new RequestDetails()); + sir.getRequestDetails().setModelInfo(new ModelInfo()); + String modelInvariantId = UUID.randomUUID().toString(); + sir.getRequestDetails().getModelInfo().setModelInvariantId(modelInvariantId); + + Resource serviceResource = new Resource(WorkflowType.SERVICE, "", false, null); + serviceResource.setModelInvariantId(modelInvariantId); + + BuildingBlockExecution execution = createExecution(sir, Arrays.asList(serviceResource)); + + Optional<String> message = validator.validate(execution); + + assertThat(message).isEmpty(); + } + + @Test + public void validateAAIVnfsNotSupported() throws JsonProcessingException { + ServiceInstancesRequest sir = new ServiceInstancesRequest(); + sir.setRequestDetails(new RequestDetails()); + sir.getRequestDetails().setModelInfo(new ModelInfo()); + sir.getRequestDetails().getModelInfo().setModelUuid(UUID.randomUUID().toString()); + String modelInvariantId = UUID.randomUUID().toString(); + sir.getRequestDetails().getModelInfo().setModelInvariantId(modelInvariantId); + + Resource serviceResource = new Resource(WorkflowType.SERVICE, "", false, null); + serviceResource.setModelInvariantId(modelInvariantId); + Resource vnfResource = new Resource(WorkflowType.VNF, "", false, serviceResource); + vnfResource.setVnfCustomizationId(UUID.randomUUID().toString()); + + Service service = new Service(); + VnfResourceCustomization vnfCustomization = new VnfResourceCustomization(); + vnfCustomization.setModelCustomizationUUID(UUID.randomUUID().toString()); + service.setVnfCustomizations(Arrays.asList(vnfCustomization)); + + when(catalogDbClient.getServiceByModelUUID(anyString())).thenReturn(service); + + BuildingBlockExecution execution = createExecution(sir, Arrays.asList(serviceResource, vnfResource)); + + Optional<String> message = validator.validate(execution); + + assertTrue(message.isPresent()); + assertTrue(message.get().startsWith("Existing vnfs in AAI are not supported by service model")); + } + + @Test + public void validateHappyCase() throws JsonProcessingException { + ServiceInstancesRequest sir = new ServiceInstancesRequest(); + sir.setRequestDetails(new RequestDetails()); + sir.getRequestDetails().setModelInfo(new ModelInfo()); + sir.getRequestDetails().getModelInfo().setModelUuid(UUID.randomUUID().toString()); + String modelInvariantId = UUID.randomUUID().toString(); + sir.getRequestDetails().getModelInfo().setModelInvariantId(modelInvariantId); + + Resource serviceResource = new Resource(WorkflowType.SERVICE, "", false, null); + serviceResource.setModelInvariantId(modelInvariantId); + Resource vnfResource = new Resource(WorkflowType.VNF, "", false, serviceResource); + String vnfCustomiationId = UUID.randomUUID().toString(); + vnfResource.setVnfCustomizationId(vnfCustomiationId); + + Service service = new Service(); + VnfResourceCustomization vnfCustomization = new VnfResourceCustomization(); + vnfCustomization.setModelCustomizationUUID(vnfCustomiationId); + service.setVnfCustomizations(Arrays.asList(vnfCustomization)); + + when(catalogDbClient.getServiceByModelUUID(anyString())).thenReturn(service); + + BuildingBlockExecution execution = createExecution(sir, Arrays.asList(serviceResource, vnfResource)); + + Optional<String> message = validator.validate(execution); + + assertFalse(message.isPresent()); + } + +} |