Add new endpoint and macro for service upgrade 23/121123/8
authorJozsef Csongvai <jozsef.csongvai@bell.ca>
Tue, 12 Jan 2021 14:12:23 +0000 (09:12 -0500)
committerJozsef Csongvai <jozsef.csongvai@bell.ca>
Wed, 4 Aug 2021 12:55:43 +0000 (08:55 -0400)
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

13 files changed:
adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__MacroData.sql
bpmn/MSOCommonBPMN/src/main/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetup.java
bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetupTest.java
bpmn/MSOCommonBPMN/src/test/resources/__files/ExecuteBuildingBlock/RequestDetailsInput_serviceUpgrade.json [new file with mode: 0644]
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/Resource.java
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowAction.java
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/WorkflowActionConstants.java
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/ebb/loader/ServiceEBBLoader.java
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidator.java [new file with mode: 0644]
bpmn/so-bpmn-tasks/src/main/java/org/onap/so/client/orchestration/AAIServiceInstanceResources.java
bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/workflow/tasks/validators/UpgradePreWorkflowValidatorTest.java [new file with mode: 0644]
mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/Action.java
mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/ServiceInstances.java

index afe6528..6e65ec4 100644 (file)
@@ -15,6 +15,7 @@ INSERT INTO northbound_request_ref_lookup(MACRO_ACTION, ACTION, REQUEST_SCOPE, I
 ('Service-Macro-Unassign', 'unassignInstance', 'Service', false,true, '7','7', 'DEFAULT', '*'),
 ('Service-Macro-Create', 'createInstance', 'Service', false,true, '7','7', 'DEFAULT', '*'),
 ('Service-Macro-Delete', 'deleteInstance', 'Service', false,true, '7','7', 'DEFAULT', '*'),
+('Service-Macro-Upgrade', 'upgradeInstance', 'Service', false,true, '7','7', 'DEFAULT', '*'),
 ('Network-Create', 'createInstance', 'Network', true,true, '7','7', 'DEFAULT', '*'),
 ('Network-Delete', 'deleteInstance', 'Network', true,true, '7','7', 'DEFAULT', '*'),
 ('VNF-Macro-Create', 'createInstance', 'Vnf', false,true, '7','7', 'DEFAULT', '*'),
@@ -103,6 +104,7 @@ INSERT INTO orchestration_flow_reference(COMPOSITE_ACTION, SEQ_NO, FLOW_NAME, FL
 ('Service-Macro-Delete', '14', 'UnassignVnfBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Service-Macro-Delete' and CLOUD_OWNER = 'DEFAULT')),
 ('Service-Macro-Delete', '15', 'UnassignNetworkBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Service-Macro-Delete' and CLOUD_OWNER = 'DEFAULT')),
 ('Service-Macro-Delete', '16', 'UnassignServiceInstanceBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Service-Macro-Delete' and CLOUD_OWNER = 'DEFAULT')),
+('Service-Macro-Upgrade', '1', 'ChangeModelServiceInstanceBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Service-Macro-Upgrade' and CLOUD_OWNER = 'DEFAULT')),
 ('Network-Create', '1', 'AssignNetworkBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Network-Create' and CLOUD_OWNER = 'DEFAULT')),
 ('Network-Create', '2', 'CreateNetworkBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Network-Create' and CLOUD_OWNER = 'DEFAULT')),
 ('Network-Create', '3', 'ActivateNetworkBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'Network-Create' and CLOUD_OWNER = 'DEFAULT')),
@@ -962,6 +964,12 @@ UPDATE vnf_recipe
 SET ORCHESTRATION_URI = '/mso/async/services/WorkflowActionBB'
 WHERE NF_ROLE = 'GR-API-DEFAULT' AND ACTION = 'applyUpdatedConfig';
 
+DELETE FROM service_recipe where ACTION = 'upgradeInstance';
+INSERT INTO service_recipe (ACTION, VERSION_STR, DESCRIPTION, ORCHESTRATION_URI, RECIPE_TIMEOUT, SERVICE_MODEL_UUID)
+VALUES
+('upgradeInstance', '1.0', 'Gr api recipe to upgrade service-instance', '/mso/async/services/WorkflowActionBB', 180, 'd88da85c-d9e8-4f73-b837-3a72a431622b');
+
+
 INSERT INTO rainy_day_handler_macro (FLOW_NAME, SERVICE_TYPE, VNF_TYPE, ERROR_CODE, WORK_STEP, POLICY, SECONDARY_POLICY, REG_EX_ERROR_MESSAGE, SERVICE_ROLE)
 VALUES 
 ('VNFCheckPserversLockedFlagActivity','*','*','*','*','Rollback','Abort','*', '*'),
index 569f6b1..d39da5e 100644 (file)
@@ -1249,7 +1249,8 @@ public class BBInputSetup implements JavaDelegate {
                 || requestAction.equalsIgnoreCase("activateInstance")
                 || requestAction.equalsIgnoreCase("activateFabricConfiguration")
                 || requestAction.equalsIgnoreCase("recreateInstance")
-                || requestAction.equalsIgnoreCase("replaceInstance")) {
+                || requestAction.equalsIgnoreCase("replaceInstance")
+                || requestAction.equalsIgnoreCase("upgradeInstance")) {
             return getGBBMacroExistingService(executeBB, lookupKeyMap, bbName, requestAction,
                     requestDetails.getCloudConfiguration());
         }
@@ -1429,7 +1430,13 @@ public class BBInputSetup implements JavaDelegate {
         if (serviceInstanceId != null) {
             aaiServiceInstance = bbInputSetupUtils.getAAIServiceInstanceById(serviceInstanceId);
             if (aaiServiceInstance != null) {
-                service = bbInputSetupUtils.getCatalogServiceByModelUUID(aaiServiceInstance.getModelVersionId());
+                String modelVersionId = aaiServiceInstance.getModelVersionId();
+                if ("upgradeInstance".equalsIgnoreCase(requestAction)) {
+                    modelVersionId = requestDetails.getModelInfo().getModelVersionId();
+                }
+
+                service = bbInputSetupUtils.getCatalogServiceByModelUUID(modelVersionId);
+
                 if (service == null) {
                     String message = String.format(
                             "Related service instance model not found in MSO CatalogDB: model-version-id=%s",
index 8961c99..b561055 100644 (file)
@@ -46,6 +46,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.UUID;
 import org.camunda.bpm.engine.delegate.DelegateExecution;
 import org.junit.Assert;
 import org.junit.Rule;
@@ -2983,6 +2984,31 @@ public class BBInputSetupTest {
                 any(Service.class), isA(ConfigurationResourceKeys.class));
     }
 
+    @Test
+    public void testGetGBBMacroExistingServiceUpgrade() throws Exception {
+        String requestAction = "upgradeInstance";
+        GeneralBuildingBlock gBB = mapper.readValue(new File(RESOURCE_PATH + "GeneralBuildingBlockExpected.json"),
+                GeneralBuildingBlock.class);
+        ExecuteBuildingBlock executeBB = mapper.readValue(new File(RESOURCE_PATH + "ExecuteBuildingBlockSimple.json"),
+                ExecuteBuildingBlock.class);
+        RequestDetails requestDetails = mapper
+                .readValue(new File(RESOURCE_PATH + "RequestDetailsInput_serviceUpgrade.json"), RequestDetails.class);
+        Map<ResourceKey, String> lookupKeyMap = prepareLookupKeyMap();
+        executeBB.setRequestDetails(requestDetails);
+
+        doReturn(new Service()).when(SPY_bbInputSetupUtils)
+                .getCatalogServiceByModelUUID(requestDetails.getModelInfo().getModelVersionId());
+        doReturn(new org.onap.aai.domain.yang.ServiceInstance()).when(SPY_bbInputSetupUtils)
+                .getAAIServiceInstanceById(lookupKeyMap.get(ResourceKey.SERVICE_INSTANCE_ID));
+        doReturn(gBB).when(SPY_bbInputSetup).populateGBBWithSIAndAdditionalInfo(any(BBInputSetupParameter.class));
+
+        SPY_bbInputSetup.getGBBMacroExistingService(executeBB, lookupKeyMap,
+                executeBB.getBuildingBlock().getBpmnFlowName(), requestAction, null);
+
+        verify(SPY_bbInputSetupUtils, times(1))
+                .getCatalogServiceByModelUUID(requestDetails.getModelInfo().getModelVersionId());
+    }
+
     @Test
     public void testGetGBBMacroExistingServiceServiceinstancenotFoundInAai() throws Exception {
         ExecuteBuildingBlock executeBB = mapper.readValue(new File(RESOURCE_PATH + "ExecuteBuildingBlockSimple.json"),
diff --git a/bpmn/MSOCommonBPMN/src/test/resources/__files/ExecuteBuildingBlock/RequestDetailsInput_serviceUpgrade.json b/bpmn/MSOCommonBPMN/src/test/resources/__files/ExecuteBuildingBlock/RequestDetailsInput_serviceUpgrade.json
new file mode 100644 (file)
index 0000000..2a721dd
--- /dev/null
@@ -0,0 +1,31 @@
+{
+       "modelInfo": {
+               "modelType": "service",
+               "modelInvariantId": "5d48acb5-097d-4982-aeb2-f4a3bd87d31b",
+               "modelVersionId": "3c40d244-808e-42ca-b09a-256d83d19d0a",
+               "modelName": "Sample Service Upgrade",
+               "modelVersion": "10.0"
+       },
+       "owningEntity": {
+               "owningEntityId": "038d99af-0427-42c2-9d15-971b99b9b489",
+               "owningEntityName": "TEST"
+       },
+       "project": {
+               "projectName": "projectName"
+       },
+       "subscriberInfo": {
+               "globalSubscriberId": "subscriberId"
+       },
+       "requestInfo": {
+               "instanceName": "test_Service",
+               "productFamilyId": "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb",
+               "source": "VID",
+               "suppressRollback": false,
+               "requestorId": "xxxxxx"
+       },
+       "requestParameters": {
+               "subscriptionServiceType": "test",
+               "aLaCarte": false,
+               "userParams": []
+       }
+}
index 99cff93..2a8852a 100644 (file)
 
 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;
     }
index e49aed8..02508b8 100644 (file)
@@ -355,6 +355,7 @@ public class WorkflowAction {
         } else {
             updateResourceIdsFromAAITraversal(flowsToExecute, resourceList, aaiResourceIds, serviceInstanceId);
         }
+        execution.setVariable("resources", resourceList);
         return flowsToExecute;
     }
 
index 38ba007..8c6fb2b 100644 (file)
@@ -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";
index e4c6d29..c000e94 100644 (file)
@@ -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 (file)
index 0000000..5e82b4f
--- /dev/null
@@ -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));
+    }
+
+}
index cc99f17..8c1e8f6 100644 (file)
@@ -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 (file)
index 0000000..1066ca1
--- /dev/null
@@ -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());
+    }
+
+}
index 88c4bc3..2a91eae 100644 (file)
@@ -26,6 +26,7 @@ public enum Action implements Actions {
     updateInstance,
     deleteInstance,
     configureInstance,
+    upgradeInstance,
     replaceInstance,
     replaceInstanceRetainAssignments,
     activateInstance,
index bcbc7c7..36922a8 100644 (file)
@@ -378,6 +378,24 @@ public class ServiceInstances extends AbstractRestHandler {
         }
     }
 
+    @POST
+    @Path("/{version:[vV][5-7]}/serviceInstances/{serviceInstanceId}/upgrade")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Operation(description = "Upgrade a Service Instance to newer model", responses = @ApiResponse(
+            content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))))
+    @Transactional
+    public Response upgradeServiceInstance(String request, @PathParam("version") String version,
+            @PathParam("serviceInstanceId") String serviceInstanceId, @Context ContainerRequestContext requestContext)
+            throws ApiException {
+        String requestId = requestHandlerUtils.getRequestId(requestContext);
+        HashMap<String, String> instanceIdMap = new HashMap<>();
+        instanceIdMap.put("serviceInstanceId", serviceInstanceId);
+
+        return serviceInstances(request, Action.upgradeInstance, instanceIdMap, version, requestId,
+                requestHandlerUtils.getRequestUri(requestContext, uriPrefix));
+    }
+
     @POST
     @Path("/{version:[vV][5-7]}/serviceInstances/{serviceInstanceId}/vnfs/{vnfInstanceId}/replace")
     @Consumes(MediaType.APPLICATION_JSON)