Allow element version update in migration 05/137605/1
authorFrancescoFioraEst <francesco.fiora@est.tech>
Thu, 11 Jan 2024 13:00:26 +0000 (13:00 +0000)
committerFrancescoFioraEst <francesco.fiora@est.tech>
Wed, 27 Mar 2024 17:06:02 +0000 (17:06 +0000)
Allow composition definition element to update the version in migration.

Issue-ID: POLICY-4950
Change-Id: I40d2a4fea2178a3daf00c57861ce30e231cccb1a
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java

index 84920dd..75b9e86 100644 (file)
@@ -26,8 +26,8 @@ import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
 import java.util.UUID;
 import java.util.stream.Collectors;
-import lombok.AllArgsConstructor;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
 import org.onap.policy.clamp.acm.runtime.participants.AcmParticipantProvider;
 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler;
@@ -47,7 +47,10 @@ import org.onap.policy.clamp.models.acm.utils.AcmUtils;
 import org.onap.policy.common.parameters.BeanValidationResult;
 import org.onap.policy.common.parameters.ObjectValidationResult;
 import org.onap.policy.common.parameters.ValidationStatus;
+import org.onap.policy.models.base.PfKey;
 import org.onap.policy.models.base.PfModelRuntimeException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -56,10 +59,12 @@ import org.springframework.transaction.annotation.Transactional;
  */
 @Service
 @Transactional
-@AllArgsConstructor
+@RequiredArgsConstructor
 public class AutomationCompositionInstantiationProvider {
     private static final String DO_NOT_MATCH = " do not match with ";
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
+
     private final AutomationCompositionProvider automationCompositionProvider;
     private final AcDefinitionProvider acDefinitionProvider;
     private final AcInstanceStateResolver acInstanceStateResolver;
@@ -93,10 +98,13 @@ public class AutomationCompositionInstantiationProvider {
         }
         automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
 
+        return createInstantiationResponse(automationComposition);
+    }
+
+    private InstantiationResponse createInstantiationResponse(AutomationComposition automationComposition) {
         var response = new InstantiationResponse();
         response.setInstanceId(automationComposition.getInstanceId());
         response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
-
         return response;
     }
 
@@ -109,7 +117,6 @@ public class AutomationCompositionInstantiationProvider {
      */
     public InstantiationResponse updateAutomationComposition(UUID compositionId,
             AutomationComposition automationComposition) {
-        var response = new InstantiationResponse();
         var instanceId = automationComposition.getInstanceId();
         var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
         if (!compositionId.equals(acToUpdate.getCompositionId())) {
@@ -127,14 +134,16 @@ public class AutomationCompositionInstantiationProvider {
                 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
             }
             automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
-            response.setInstanceId(instanceId);
-            response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
-            return response;
+            return createInstantiationResponse(automationComposition);
 
         } else if ((DeployState.DEPLOYED.equals(acToUpdate.getDeployState())
                 || DeployState.UPDATING.equals(acToUpdate.getDeployState()))
                 && LockState.LOCKED.equals(acToUpdate.getLockState())) {
-            return updateDeployedAutomationComposition(automationComposition, acToUpdate);
+            if (automationComposition.getCompositionTargetId() != null) {
+                return  migrateAutomationComposition(automationComposition, acToUpdate);
+            } else {
+                return updateDeployedAutomationComposition(automationComposition, acToUpdate);
+            }
         }
         throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
                 "Not allowed to update in the state " + acToUpdate.getDeployState());
@@ -147,15 +156,9 @@ public class AutomationCompositionInstantiationProvider {
      * @param acToBeUpdated the composition to be updated
      * @return the result of the update
      */
-    public InstantiationResponse updateDeployedAutomationComposition(
+    private InstantiationResponse updateDeployedAutomationComposition(
             AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
 
-        if (automationComposition.getCompositionTargetId() != null
-                && !DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
-                    "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
-        }
-
         // Iterate and update the element property values
         for (var element : automationComposition.getElements().entrySet()) {
             var elementId = element.getKey();
@@ -169,31 +172,62 @@ public class AutomationCompositionInstantiationProvider {
             throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Update not allowed");
         }
 
-        if (automationComposition.getCompositionTargetId() != null) {
-            var validationResult =
-                    validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
-            if (!validationResult.isValid()) {
-                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
-            }
-            acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
+        var validationResult = validateAutomationComposition(acToBeUpdated);
+        if (!validationResult.isValid()) {
+            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+        }
+        // Publish property update event to the participants
+        supervisionAcHandler.update(acToBeUpdated);
 
-            // Publish migrate event to the participants
-            supervisionAcHandler.migrate(acToBeUpdated, automationComposition.getCompositionTargetId());
-        } else {
-            var validationResult = validateAutomationComposition(acToBeUpdated);
-            if (!validationResult.isValid()) {
-                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
+        automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
+        return createInstantiationResponse(automationComposition);
+    }
+
+    private InstantiationResponse migrateAutomationComposition(
+        AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+
+        if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
+            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+                "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
+        }
+        if (automationComposition.getRestarting() != null) {
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, "There is a restarting process, Migrate not allowed");
+        }
+
+        // Iterate and update the element property values
+        for (var element : automationComposition.getElements().entrySet()) {
+            var elementId = element.getKey();
+            var dbAcElement = acToBeUpdated.getElements().get(elementId);
+            if (dbAcElement == null) {
+                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, "Element id not present " + elementId);
+            }
+            dbAcElement.getProperties().putAll(element.getValue().getProperties());
+            var newDefinition = element.getValue().getDefinition();
+            var compatibility =
+                newDefinition.asConceptKey().getCompatibility(dbAcElement.getDefinition().asConceptKey());
+            if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
+                throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
+                    dbAcElement.getDefinition() + " is not compatible with " + newDefinition);
+            }
+            if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR.equals(compatibility)) {
+                LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ",
+                    automationComposition.getInstanceId(), newDefinition, compatibility, dbAcElement.getDefinition());
             }
-            // Publish property update event to the participants
-            supervisionAcHandler.update(acToBeUpdated);
+            dbAcElement.setDefinition(element.getValue().getDefinition());
+        }
+
+        var validationResult =
+            validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
+        if (!validationResult.isValid()) {
+            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult());
         }
+        acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
+
+        // Publish migrate event to the participants
+        supervisionAcHandler.migrate(acToBeUpdated, automationComposition.getCompositionTargetId());
 
         automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
-        var response = new InstantiationResponse();
-        var instanceId = automationComposition.getInstanceId();
-        response.setInstanceId(instanceId);
-        response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier());
-        return response;
+        return createInstantiationResponse(automationComposition);
     }
 
     private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition) {
index 87bfe1b..fbd8330 100644 (file)
@@ -240,6 +240,11 @@ class AutomationCompositionInstantiationProviderTest {
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
                         .hasMessageMatching("There is a restarting process, Update not allowed");
 
+        automationCompositionUpdate.setCompositionTargetId(UUID.randomUUID());
+        assertThatThrownBy(
+                () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
+                .hasMessageMatching("There is a restarting process, Migrate not allowed");
+
         automationCompositionUpdate.setDeployState(DeployState.UNDEPLOYED);
         automationCompositionUpdate.setLockState(LockState.NONE);
 
@@ -321,6 +326,41 @@ class AutomationCompositionInstantiationProviderTest {
         InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationComposition);
     }
 
+    @Test
+    void testMigrateBadRequest() {
+        var acDefinitionProvider = mock(AcDefinitionProvider.class);
+        var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        var compositionId = acDefinition.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionId)).thenReturn(Optional.of(acDefinition));
+
+        var automationComposition =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+        automationComposition.setCompositionId(compositionId);
+        automationComposition.setDeployState(DeployState.DEPLOYED);
+        automationComposition.setLockState(LockState.LOCKED);
+        var acProvider = mock(AutomationCompositionProvider.class);
+        when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
+                .thenReturn(automationComposition);
+        when(acProvider.updateAutomationComposition(automationComposition)).thenReturn(automationComposition);
+
+        var acDefinitionTarget = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        var compositionTargetId = acDefinitionTarget.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionTargetId)).thenReturn(Optional.of(acDefinitionTarget));
+
+        var acMigrate = new AutomationComposition(automationComposition);
+        acMigrate.setCompositionTargetId(compositionTargetId);
+        automationComposition.getElements().clear();
+
+        var supervisionAcHandler = mock(SupervisionAcHandler.class);
+        var acmParticipantProvider = mock(AcmParticipantProvider.class);
+        var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
+                null, supervisionAcHandler, acmParticipantProvider, new AcRuntimeParameterGroup());
+
+        assertThatThrownBy(() -> instantiationProvider
+                .updateAutomationComposition(automationComposition.getCompositionId(), acMigrate))
+                .hasMessageStartingWith("Element id not present");
+    }
+
     @Test
     void testInstantiationDelete() {
         var automationComposition =