update job monitoring to support rollback 02/141402/4
authorakenihan <adam.kenihan@est.tech>
Fri, 27 Jun 2025 10:54:42 +0000 (11:54 +0100)
committerAdam Kenihan <adam.kenihan@est.tech>
Tue, 1 Jul 2025 14:42:47 +0000 (14:42 +0000)
Issue-ID: POLICY-5406
Change-Id: Ibef8e8ea31df91fc12c141ebd0c6dd97b30807ef
Signed-off-by: akenihan <adam.kenihan@est.tech>
16 files changed:
models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationCompositionRollback.java
models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolver.java
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java
models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java
models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolverTest.java
models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java
models/src/test/java/org/onap/policy/clamp/models/acm/utils/AcmUtilsTest.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AutomationCompositionMigrationPublisher.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AbstractScanner.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/MonitoringScanner.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/StageScanner.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/StageScannerTest.java

index c11d5b8..988a7d5 100644 (file)
@@ -50,7 +50,7 @@ public class AutomationCompositionRollback {
     public AutomationCompositionRollback(final AutomationCompositionRollback otherAcmRollback) {\r
         this.instanceId = otherAcmRollback.instanceId;\r
         this.compositionId = otherAcmRollback.compositionId;\r
-        this.elements = PfUtils.mapMap(otherAcmRollback.elements, UnaryOperator.identity());\r
+        this.elements = PfUtils.mapMap(otherAcmRollback.elements, AutomationCompositionElement::new);\r
     }\r
 \r
     /**\r
@@ -61,6 +61,6 @@ public class AutomationCompositionRollback {
     public AutomationCompositionRollback(final AutomationComposition automationComposition) {\r
         this.instanceId = automationComposition.getInstanceId();\r
         this.compositionId = automationComposition.getCompositionId();\r
-        this.elements = PfUtils.mapMap(automationComposition.getElements(), UnaryOperator.identity());\r
+        this.elements = PfUtils.mapMap(automationComposition.getElements(), AutomationCompositionElement::new);\r
     }\r
 }\r
index 758a505..5a4f84a 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation.
+ *  Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,5 +27,6 @@ public enum DeployOrder {
     DELETE,
     UPDATE,
     RESTARTING,
-    MIGRATE
+    MIGRATE,
+    MIGRATION_REVERT
 }
index defa804..539a19a 100644 (file)
@@ -34,6 +34,7 @@ import org.springframework.stereotype.Component;
 public class AcInstanceStateResolver {
     private final StateDefinition<String> graph;
 
+    // DeployState
     private static final String DEPLOYED = DeployState.DEPLOYED.name();
     private static final String DEPLOYING = DeployState.DEPLOYING.name();
     private static final String UNDEPLOYED = DeployState.UNDEPLOYED.name();
@@ -41,37 +42,48 @@ public class AcInstanceStateResolver {
     private static final String UPDATING = DeployState.UPDATING.name();
     private static final String DELETING = DeployState.DELETING.name();
     private static final String MIGRATING = DeployState.MIGRATING.name();
-    private static final String MIGRATION_PRECHECKING = SubState.MIGRATION_PRECHECKING.name();
     private static final String MIGRATION_REVERTING = DeployState.MIGRATION_REVERTING.name();
+
+    // SubState
+    private static final String MIGRATION_PRECHECKING = SubState.MIGRATION_PRECHECKING.name();
     private static final String SUB_STATE_NONE = SubState.NONE.name();
     private static final String PREPARING = SubState.PREPARING.name();
     private static final String REVIEWING = SubState.REVIEWING.name();
 
+    // LockState
     private static final String LOCKED = LockState.LOCKED.name();
     private static final String LOCKING = LockState.LOCKING.name();
     private static final String UNLOCKED = LockState.UNLOCKED.name();
     private static final String UNLOCKING = LockState.UNLOCKING.name();
     private static final String STATE_LOCKED_NONE = LockState.NONE.name();
 
+    // NONE Order
     private static final String DEPLOY_NONE = DeployOrder.NONE.name();
     private static final String LOCK_NONE = LockOrder.NONE.name();
     private static final String SUB_NONE = SubOrder.NONE.name();
 
-    private static final String NO_ERROR = StateChangeResult.NO_ERROR.name();
-    private static final String FAILED = StateChangeResult.FAILED.name();
-    private static final String TIMEOUT = StateChangeResult.TIMEOUT.name();
-
-    // list of results
+    // DeployOrder
     public static final String DEPLOY = DeployOrder.DEPLOY.name();
     public static final String UNDEPLOY = DeployOrder.UNDEPLOY.name();
     public static final String DELETE = DeployOrder.DELETE.name();
+    public static final String MIGRATE = DeployOrder.MIGRATE.name();
+    public static final String MIGRATION_REVERT = DeployOrder.MIGRATION_REVERT.name();
+    public static final String UPDATE = DeployOrder.UPDATE.name();
+
+    // LockOrder
     public static final String LOCK = LockOrder.LOCK.name();
     public static final String UNLOCK = LockOrder.UNLOCK.name();
-    public static final String MIGRATE = DeployOrder.MIGRATE.name();
+
+    // SubOrder
     public static final String MIGRATE_PRECHECK = SubOrder.MIGRATE_PRECHECK.name();
     public static final String PREPARE = SubOrder.PREPARE.name();
     public static final String REVIEW = SubOrder.REVIEW.name();
-    public static final String UPDATE = DeployOrder.UPDATE.name();
+
+    // StateChangeResult
+    private static final String NO_ERROR = StateChangeResult.NO_ERROR.name();
+    private static final String FAILED = StateChangeResult.FAILED.name();
+    private static final String TIMEOUT = StateChangeResult.TIMEOUT.name();
+
     public static final String NONE = "NONE";
 
     /**
@@ -129,7 +141,7 @@ public class AcInstanceStateResolver {
         addSubOrderWithFail(REVIEW, DEPLOYED, LOCKED, REVIEWING);
 
         // rollback
-        addDeployOrderWithFail(MIGRATION_REVERTING, MIGRATING, LOCKED, SUB_STATE_NONE);
+        addDeployOrderWithFail(MIGRATION_REVERT, MIGRATING, LOCKED, SUB_STATE_NONE);
         addDeployOrderWithFail(UNDEPLOY, MIGRATION_REVERTING, LOCKED, SUB_STATE_NONE);
     }
 
index 225c95a..d12d78d 100644 (file)
@@ -157,7 +157,8 @@ public class AutomationCompositionProvider {
     @Transactional(readOnly = true)
     public Set<UUID> getAcInstancesInTransition() {
         var jpaList = automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
-            DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING));
+            DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING,
+            DeployState.MIGRATION_REVERTING));
         jpaList.addAll(automationCompositionRepository.findByLockStateIn(
             List.of(LockState.LOCKING, LockState.UNLOCKING)));
         jpaList.addAll(automationCompositionRepository.findBySubStateIn(
index 09d4dce..6b5c4f9 100644 (file)
@@ -290,7 +290,8 @@ public final class AcmUtils {
         return DeployState.DEPLOYING.equals(deployState) || DeployState.UNDEPLOYING.equals(deployState)
                 || LockState.LOCKING.equals(lockState) || LockState.UNLOCKING.equals(lockState)
                 || DeployState.DELETING.equals(deployState) || DeployState.UPDATING.equals(deployState)
-                || DeployState.MIGRATING.equals(deployState) || !SubState.NONE.equals(subState);
+                || DeployState.MIGRATING.equals(deployState) || DeployState.MIGRATION_REVERTING.equals(deployState)
+                || !SubState.NONE.equals(subState);
     }
 
     /**
@@ -331,7 +332,7 @@ public final class AcmUtils {
      */
     public static DeployState deployCompleted(DeployState deployState) {
         return switch (deployState) {
-            case MIGRATING, UPDATING, DEPLOYING -> DeployState.DEPLOYED;
+            case MIGRATING, MIGRATION_REVERTING, UPDATING, DEPLOYING -> DeployState.DEPLOYED;
             case UNDEPLOYING -> DeployState.UNDEPLOYED;
             case DELETING -> DeployState.DELETED;
             default -> deployState;
index c9c4f0d..09de724 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2023-2024 Nordix Foundation.
+ *  Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -77,9 +77,9 @@ class AcInstanceStateResolverTest {
         assertThat(result).isEqualTo(AcInstanceStateResolver.REVIEW);
 
         // rollback
-        result = acTypeStateResolver.resolve(DeployOrder.MIGRATE, LockOrder.NONE, SubOrder.REVIEW,
-            DeployState.MIGRATION_REVERTING, LockState.LOCKED, SubState.NONE, StateChangeResult.NO_ERROR);
-        assertThat(result).isEqualTo(AcInstanceStateResolver.NONE);
+        result = acTypeStateResolver.resolve(DeployOrder.MIGRATION_REVERT, LockOrder.NONE, SubOrder.NONE,
+                DeployState.MIGRATING, LockState.LOCKED, SubState.NONE, StateChangeResult.FAILED);
+        assertThat(result).isEqualTo(AcInstanceStateResolver.MIGRATION_REVERT);
 
         result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, SubOrder.NONE,
             DeployState.MIGRATION_REVERTING, LockState.LOCKED, SubState.NONE, StateChangeResult.FAILED);
index 40c2639..6ddf965 100644 (file)
@@ -218,7 +218,8 @@ class AutomationCompositionProviderTest {
 
         var automationCompositionRepository = mock(AutomationCompositionRepository.class);
         when(automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
-            DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING)))
+            DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING,
+                DeployState.MIGRATION_REVERTING)))
             .thenReturn(res1);
         when(automationCompositionRepository.findByLockStateIn(List.of(LockState.LOCKING, LockState.UNLOCKING)))
             .thenReturn(List.of(inputAutomationCompositionsJpa.get(1)));
index 8feeb87..fb0f683 100644 (file)
@@ -74,6 +74,8 @@ class AcmUtilsTest {
         assertThat(AcmUtils.isInTransitionalState(DeployState.DELETING, LockState.NONE, SubState.NONE)).isTrue();
         assertThat(AcmUtils.isInTransitionalState(DeployState.UPDATING, LockState.LOCKED, SubState.NONE)).isTrue();
         assertThat(AcmUtils.isInTransitionalState(DeployState.MIGRATING, LockState.LOCKED, SubState.NONE)).isTrue();
+        assertThat(AcmUtils.isInTransitionalState(DeployState.MIGRATION_REVERTING, LockState.LOCKED,
+                SubState.NONE)).isTrue();
         assertThat(AcmUtils.isInTransitionalState(DeployState.DEPLOYED, LockState.LOCKED,
                 SubState.MIGRATION_PRECHECKING)).isTrue();
     }
index ee1a47a..e1093c7 100644 (file)
@@ -228,7 +228,7 @@ public class AutomationCompositionInstantiationProvider {
         var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated);
         var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
 
-        updateAcForMigration(acToBeUpdated, acDefinition);
+        updateAcForMigration(acToBeUpdated, acDefinition, DeployState.MIGRATING);
 
         var acToPublish = new AutomationComposition(acToBeUpdated);
 
@@ -243,8 +243,8 @@ public class AutomationCompositionInstantiationProvider {
     }
 
     private void updateAcForMigration(AutomationComposition acToBeUpdated,
-                                      AutomationCompositionDefinition acDefinition) {
-        AcmUtils.setCascadedState(acToBeUpdated, DeployState.MIGRATING, LockState.LOCKED);
+                                      AutomationCompositionDefinition acDefinition, DeployState deployState) {
+        AcmUtils.setCascadedState(acToBeUpdated, deployState, LockState.LOCKED);
         acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
         var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
         acToBeUpdated.setPhase(stage);
@@ -461,26 +461,39 @@ public class AutomationCompositionInstantiationProvider {
     /**
      * Rollback AC Instance.
      *
-     * @param instanceId the instanceId
+     * @param compositionId The UUID of the automation composition definition
+     * @param instanceId    The UUID of the automation composition instance
      */
     public void rollback(UUID compositionId, UUID instanceId) {
         var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
         validateCompositionRequested(compositionId, automationComposition);
-        var automationCompositionToRollback =
-            automationCompositionProvider.getAutomationCompositionRollback(instanceId);
-
-        if (DeployState.DEPLOYED.equals(automationComposition.getDeployState())
-              && SubState.NONE.equals(automationComposition.getSubState())
-              && StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult())) {
-            automationComposition.setCompositionId(automationCompositionToRollback.getCompositionId());
-            automationComposition.setElements(automationCompositionToRollback.getElements().values().stream()
-                    .collect(Collectors.toMap(AutomationCompositionElement::getId, UnaryOperator.identity())));
-            automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
-            AcmUtils.setCascadedState(automationComposition, DeployState.MIGRATION_REVERTING, LockState.LOCKED);
-            automationCompositionProvider.updateAutomationComposition(automationComposition);
-        } else {
+
+        if (!DeployOrder.MIGRATION_REVERT.name().equals(acInstanceStateResolver.resolve(
+                DeployOrder.MIGRATION_REVERT, LockOrder.NONE,
+                SubOrder.NONE, automationComposition.getDeployState(), automationComposition.getLockState(),
+                automationComposition.getSubState(), automationComposition.getStateChangeResult()))) {
             throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
         }
+
+        var automationCompositionToRollback =
+                automationCompositionProvider.getAutomationCompositionRollback(instanceId);
+        var acToBeUpdated = new AutomationComposition(automationComposition);
+        acToBeUpdated.setCompositionTargetId(automationCompositionToRollback.getCompositionId());
+        acToBeUpdated.setElements(automationCompositionToRollback.getElements().values().stream()
+                .collect(Collectors.toMap(AutomationCompositionElement::getId, AutomationCompositionElement::new)));
+
+        var acDefinition = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionTargetId());
+        var validationResult =
+                validateAutomationComposition(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
+        if (!validationResult.isValid()) {
+            throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+        }
+
+        updateAcForMigration(acToBeUpdated, acDefinition, DeployState.MIGRATION_REVERTING);
+        var elementsRemoved = getElementRemoved(automationComposition, acToBeUpdated);
+        automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
+        elementsRemoved.forEach(automationCompositionProvider::deleteAutomationCompositionElement);
+        supervisionAcHandler.migrate(acToBeUpdated);
     }
 
     private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
index 572f7b1..4aef404 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2023-2024 Nordix Foundation.
+ * Copyright (C) 2023-2025 OpenInfra Foundation Europe. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ package org.onap.policy.clamp.acm.runtime.supervision.comm;
 import io.micrometer.core.annotation.Timed;
 import java.util.UUID;
 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
+import org.onap.policy.clamp.models.acm.concepts.DeployState;
 import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
 import org.onap.policy.clamp.models.acm.utils.AcmUtils;
@@ -43,6 +44,7 @@ public class AutomationCompositionMigrationPublisher
             description = "AUTOMATION_COMPOSITION_MIGRATION messages published")
     public void send(AutomationComposition automationComposition, int stage) {
         var acMigration = new AutomationCompositionMigration();
+        acMigration.setRollback(DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState()));
         acMigration.setPrecheck(Boolean.TRUE.equals(automationComposition.getPrecheck()));
         acMigration.setCompositionId(automationComposition.getCompositionId());
         acMigration.setAutomationCompositionId(automationComposition.getInstanceId());
@@ -51,7 +53,6 @@ public class AutomationCompositionMigrationPublisher
         acMigration.setStage(stage);
         acMigration.setParticipantUpdatesList(
                 AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.MIGRATE));
-
         super.send(acMigration);
     }
 }
index 655abcd..84b5a9e 100644 (file)
@@ -59,7 +59,8 @@ public abstract class AbstractScanner {
                 automationComposition.getSubState());
 
         var deployState = automationComposition.getDeployState();
-        if (DeployState.MIGRATING.equals(automationComposition.getDeployState())) {
+        if (DeployState.MIGRATING.equals(automationComposition.getDeployState())
+                || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState())) {
             // migration scenario
             automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
             automationComposition.setCompositionTargetId(null);
index dcf0881..8436778 100644 (file)
@@ -110,6 +110,7 @@ public class MonitoringScanner {
         }
 
         if (DeployState.MIGRATING.equals(automationComposition.getDeployState())
+                || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState())
                 || SubState.PREPARING.equals(automationComposition.getSubState())) {
             stageScanner.scanStage(automationComposition, serviceTemplate, updateSync);
         } else if (DeployState.UPDATING.equals(automationComposition.getDeployState())
index 65caa87..b9eae89 100644 (file)
@@ -79,6 +79,7 @@ public class StageScanner extends AbstractScanner {
                 var toscaNodeTemplate = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
                         .get(element.getDefinition().getName());
                 var stageSet = DeployState.MIGRATING.equals(automationComposition.getDeployState())
+                            || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState())
                         ? ParticipantUtils.findStageSetMigrate(toscaNodeTemplate.getProperties())
                         : ParticipantUtils.findStageSetPrepare(toscaNodeTemplate.getProperties());
                 var minStage = stageSet.stream().min(Comparator.comparing(Integer::valueOf)).orElse(0);
@@ -109,7 +110,8 @@ public class StageScanner extends AbstractScanner {
     }
 
     private void sendNextStage(final AutomationComposition automationComposition, int minStageNotCompleted) {
-        if (DeployState.MIGRATING.equals(automationComposition.getDeployState())) {
+        if (DeployState.MIGRATING.equals(automationComposition.getDeployState())
+                || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState())) {
             LOGGER.debug("retry message AutomationCompositionMigration");
             acMigrationPublisher.send(automationComposition, minStageNotCompleted);
         }
index 0cfd08e..c28c787 100644 (file)
@@ -24,7 +24,6 @@ package org.onap.policy.clamp.acm.runtime.instantiation;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
@@ -47,6 +46,7 @@ import org.onap.policy.clamp.acm.runtime.util.CommonTestData;
 import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
 import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionRollback;
 import org.onap.policy.clamp.models.acm.concepts.DeployState;
 import org.onap.policy.clamp.models.acm.concepts.LockState;
 import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
@@ -221,7 +221,8 @@ class AutomationCompositionInstantiationProviderTest {
             element.setId(UUID.randomUUID());
             automationCompositionUpdate.getElements().put(element.getId(), element);
         }
-        acmFromDb.getElements().values().forEach(element -> element.setDeployState(DeployState.DEPLOYED));
+        acmFromDb.getElements().values().forEach(element ->
+                element.setDeployState(DeployState.DEPLOYED));
         acmFromDb.setDeployState(DeployState.DEPLOYED);
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
@@ -241,23 +242,24 @@ class AutomationCompositionInstantiationProviderTest {
                 .thenReturn(automationCompositionUpdate);
 
         var instantiationProvider =
-            new AutomationCompositionInstantiationProvider(acProvider, mock(AcDefinitionProvider.class),
-                new AcInstanceStateResolver(), mock(SupervisionAcHandler.class), mock(ParticipantProvider.class),
-                mock(AcRuntimeParameterGroup.class), encryptionUtils);
+                new AutomationCompositionInstantiationProvider(acProvider, mock(AcDefinitionProvider.class),
+                        new AcInstanceStateResolver(), mock(SupervisionAcHandler.class),
+                        mock(ParticipantProvider.class),
+                        mock(AcRuntimeParameterGroup.class), encryptionUtils);
 
         var compositionId = automationCompositionUpdate.getCompositionId();
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
-                        .hasMessageMatching(
-                                "Not allowed to UPDATE in the state " + automationCompositionUpdate.getDeployState());
+                .hasMessageMatching(
+                        "Not allowed to UPDATE in the state " + automationCompositionUpdate.getDeployState());
 
         automationCompositionUpdate.setDeployState(DeployState.UPDATING);
         automationCompositionUpdate.setLockState(LockState.LOCKED);
         automationCompositionUpdate.setCompositionTargetId(UUID.randomUUID());
         assertThatThrownBy(
                 () -> instantiationProvider.updateAutomationComposition(compositionId, automationCompositionUpdate))
-                        .hasMessageMatching(
-                                "Not allowed to MIGRATE in the state " + automationCompositionUpdate.getDeployState());
+                .hasMessageMatching(
+                        "Not allowed to MIGRATE in the state " + automationCompositionUpdate.getDeployState());
     }
 
     @Test
@@ -306,7 +308,7 @@ class AutomationCompositionInstantiationProviderTest {
         AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.LOCKED,
                 SubState.NONE);
         var instantiationResponse = instantiationProvider.updateAutomationComposition(compositionId,
-                        automationCompositionTarget);
+                automationCompositionTarget);
 
         verify(supervisionAcHandler).migrate(any());
         InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationCompositionTarget);
@@ -360,13 +362,13 @@ class AutomationCompositionInstantiationProviderTest {
         var participantProvider = mock(ParticipantProvider.class);
         var encryptionUtils = new EncryptionUtils(CommonTestData.getTestParamaterGroup());
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-            new AcInstanceStateResolver(), supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup(),
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup(),
                 encryptionUtils);
 
         assertThatThrownBy(() -> instantiationProvider
                 .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition))
-                        .hasMessageMatching(
-                                String.format(AC_DEFINITION_NOT_FOUND, automationComposition.getCompositionTargetId()));
+                .hasMessageMatching(
+                        String.format(AC_DEFINITION_NOT_FOUND, automationComposition.getCompositionTargetId()));
 
         var acDefinitionTarget = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var compositionTargetId = acDefinitionTarget.getCompositionId();
@@ -391,7 +393,7 @@ class AutomationCompositionInstantiationProviderTest {
         when(acDefinitionProvider.findAcDefinition(compositionId)).thenReturn(Optional.of(acDefinition));
 
         var automationComposition =
-            InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
         automationComposition.setCompositionId(compositionId);
         automationComposition.setDeployState(DeployState.DEPLOYED);
         automationComposition.setLockState(LockState.LOCKED);
@@ -399,20 +401,20 @@ class AutomationCompositionInstantiationProviderTest {
         automationComposition.setPrecheck(true);
         var acProvider = mock(AutomationCompositionProvider.class);
         when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
-            .thenReturn(automationComposition);
+                .thenReturn(automationComposition);
         when(acProvider.updateAutomationComposition(automationComposition)).thenReturn(automationComposition);
 
         var supervisionAcHandler = mock(SupervisionAcHandler.class);
         var acmParticipantProvider = mock(ParticipantProvider.class);
         var encryptionUtils = mock(EncryptionUtils.class);
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-            new AcInstanceStateResolver(), supervisionAcHandler, acmParticipantProvider, new AcRuntimeParameterGroup(),
-                encryptionUtils);
+                new AcInstanceStateResolver(), supervisionAcHandler, acmParticipantProvider,
+                new AcRuntimeParameterGroup(), encryptionUtils);
 
         assertThatThrownBy(() -> instantiationProvider
-            .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition))
-            .hasMessageMatching(
-                String.format(AC_DEFINITION_NOT_FOUND, automationComposition.getCompositionTargetId()));
+                .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition))
+                .hasMessageMatching(
+                        String.format(AC_DEFINITION_NOT_FOUND, automationComposition.getCompositionTargetId()));
 
         var acDefinitionTarget = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var compositionTargetId = acDefinitionTarget.getCompositionId();
@@ -421,7 +423,7 @@ class AutomationCompositionInstantiationProviderTest {
         automationComposition.setCompositionTargetId(compositionTargetId);
 
         var instantiationResponse = instantiationProvider
-            .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition);
+                .updateAutomationComposition(automationComposition.getCompositionId(), automationComposition);
 
         verify(supervisionAcHandler).migratePrecheck(any());
         verify(acProvider).updateAutomationComposition(automationComposition);
@@ -555,7 +557,7 @@ class AutomationCompositionInstantiationProviderTest {
         var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
         var compositionId = acDefinition.getCompositionId();
         var automationComposition =
-            InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Rollback");
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Rollback");
         automationComposition.setCompositionId(compositionId);
         automationComposition.setInstanceId(UUID.randomUUID());
         automationComposition.setDeployState(DeployState.MIGRATION_REVERTING);
@@ -563,7 +565,7 @@ class AutomationCompositionInstantiationProviderTest {
 
         var acProvider = mock(AutomationCompositionProvider.class);
         when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
-            .thenReturn(automationComposition);
+                .thenReturn(automationComposition);
         var rollbackRecord = new JpaAutomationCompositionRollback();
         when(acProvider.getAutomationCompositionRollback(any(UUID.class))).thenReturn(rollbackRecord.toAuthorative());
 
@@ -572,15 +574,15 @@ class AutomationCompositionInstantiationProviderTest {
         final var participantProvider = mock(ParticipantProvider.class);
         final var encryptionUtils = new EncryptionUtils(CommonTestData.getTestParamaterGroup());
         var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
-            new AcInstanceStateResolver(), supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup(),
-            encryptionUtils);
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup(),
+                encryptionUtils);
 
         var instanceId = automationComposition.getInstanceId();
         assertThrows(PfModelRuntimeException.class, () -> instantiationProvider.rollback(compositionId, instanceId));
 
         // DeployState != MIGRATION_REVERTING
         when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
-            .thenReturn(automationComposition);
+                .thenReturn(automationComposition);
         when(acProvider.getAutomationCompositionRollback(any(UUID.class))).thenReturn(rollbackRecord.toAuthorative());
 
         automationComposition.setDeployState(DeployState.DELETING);
@@ -605,44 +607,53 @@ class AutomationCompositionInstantiationProviderTest {
 
     @Test
     void testRollbackSuccess() {
-        final var acDefinitionProvider = mock(AcDefinitionProvider.class);
-        final var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
-        final var compositionId = acDefinition.getCompositionId();
+        var acDefinitionProvider = mock(AcDefinitionProvider.class);
+        var acDefinition = CommonTestData.createAcDefinition(serviceTemplateMigration, AcTypeState.PRIMED);
+        var compositionId = acDefinition.getCompositionId();
+        when(acDefinitionProvider.findAcDefinition(compositionId)).thenReturn(Optional.of(acDefinition));
 
         var automationComposition =
-            InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Rollback");
-        automationComposition.setInstanceId(UUID.randomUUID());
+                InstantiationUtils.getAutomationCompositionFromResource(AC_MIGRATE_JSON, "Crud");
+        var instanceId = UUID.randomUUID();
+        automationComposition.setInstanceId(instanceId);
         automationComposition.setCompositionId(compositionId);
-        automationComposition.setDeployState(DeployState.DEPLOYED);
-        automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
+        automationComposition.setDeployState(DeployState.MIGRATING);
+        automationComposition.setLockState(LockState.LOCKED);
+        automationComposition.setStateChangeResult(StateChangeResult.FAILED);
         automationComposition.setSubState(SubState.NONE);
-        automationComposition.setCompositionTargetId(UUID.randomUUID());
-
         var acProvider = mock(AutomationCompositionProvider.class);
-        when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
-            .thenReturn(automationComposition);
-        final var supervisionAcHandler = mock(SupervisionAcHandler.class);
-        final var participantProvider = mock(ParticipantProvider.class);
-        final var encryptionUtils = new EncryptionUtils(CommonTestData.getTestParamaterGroup());
-        final var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider,
-            acDefinitionProvider, new AcInstanceStateResolver(), supervisionAcHandler,
-            participantProvider, new AcRuntimeParameterGroup(), encryptionUtils);
+        when(acProvider.getAutomationComposition(instanceId)).thenReturn(automationComposition);
+        when(acProvider.updateAutomationComposition(automationComposition)).thenReturn(automationComposition);
 
-        var rollbackRecord = new JpaAutomationCompositionRollback();
-        rollbackRecord.setCompositionId(automationComposition.getCompositionId().toString());
+        var acRollback =
+                InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
 
-        when(acProvider.getAutomationComposition(automationComposition.getInstanceId()))
-            .thenReturn(automationComposition);
-        when(acProvider.getAutomationCompositionRollback(any(UUID.class))).thenReturn(rollbackRecord.toAuthorative());
+        var rollbackRecord = new AutomationCompositionRollback();
+        var compositionTargetId = UUID.randomUUID();
+        rollbackRecord.setCompositionId(compositionTargetId);
+        rollbackRecord.setInstanceId(instanceId);
+        rollbackRecord.setElements(acRollback.getElements());
+        when(acProvider.getAutomationCompositionRollback(instanceId)).thenReturn(rollbackRecord);
 
-        instantiationProvider.rollback(compositionId, automationComposition.getInstanceId());
+        var supervisionAcHandler = mock(SupervisionAcHandler.class);
+        var participantProvider = mock(ParticipantProvider.class);
+        var encryptionUtils = new EncryptionUtils(CommonTestData.getTestParamaterGroup());
+        var instantiationProvider = new AutomationCompositionInstantiationProvider(acProvider, acDefinitionProvider,
+                new AcInstanceStateResolver(), supervisionAcHandler, participantProvider, new AcRuntimeParameterGroup(),
+                encryptionUtils);
+        assertThatThrownBy(() -> instantiationProvider.rollback(compositionId, instanceId))
+                .hasMessageMatching(String.format(AC_DEFINITION_NOT_FOUND, compositionTargetId));
 
-        verify(acProvider).updateAutomationComposition(automationComposition);
-        assertEquals(DeployState.MIGRATION_REVERTING, automationComposition.getDeployState());
+        var acDefinitionTarget = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED);
+        when(acDefinitionProvider.findAcDefinition(compositionTargetId)).thenReturn(Optional.of(acDefinitionTarget));
+        when(acDefinitionProvider.getAcDefinition(compositionTargetId)).thenReturn(acDefinitionTarget);
+
+        instantiationProvider.rollback(compositionId, automationComposition.getInstanceId());
+        verify(acProvider).updateAutomationComposition(any(AutomationComposition.class));
     }
 
     private void assertThatDeleteThrownBy(AutomationComposition automationComposition, DeployState deployState,
-            LockState lockState) {
+                                          LockState lockState) {
         automationComposition.setDeployState(deployState);
         automationComposition.setLockState(lockState);
         var acProvider = mock(AutomationCompositionProvider.class);
@@ -697,7 +708,7 @@ class AutomationCompositionInstantiationProviderTest {
 
         assertThatThrownBy(
                 () -> instantiationProvider.createAutomationComposition(compositionId, automationCompositionCreate))
-                        .hasMessageMatching(automationCompositionCreate.getKey().asIdentifier() + " already defined");
+                .hasMessageMatching(automationCompositionCreate.getKey().asIdentifier() + " already defined");
     }
 
     @Test
@@ -768,16 +779,16 @@ class AutomationCompositionInstantiationProviderTest {
 
         assertThatThrownBy(
                 () -> provider.getAutomationComposition(wrongCompositionId, automationComposition.getInstanceId()))
-                        .hasMessageMatching(compositionId + DO_NOT_MATCH + wrongCompositionId);
+                .hasMessageMatching(compositionId + DO_NOT_MATCH + wrongCompositionId);
         assertThatThrownBy(() -> provider.compositionInstanceState(wrongCompositionId,
                 automationComposition.getInstanceId(), new AcInstanceStateUpdate()))
-                        .hasMessageMatching(compositionId + DO_NOT_MATCH + wrongCompositionId);
+                .hasMessageMatching(compositionId + DO_NOT_MATCH + wrongCompositionId);
 
         var compositionTargetId = UUID.randomUUID();
         automationComposition.setCompositionTargetId(compositionTargetId);
         assertThatThrownBy(
                 () -> provider.getAutomationComposition(wrongCompositionId, automationComposition.getInstanceId()))
-                        .hasMessageMatching(compositionId + DO_NOT_MATCH + wrongCompositionId);
+                .hasMessageMatching(compositionId + DO_NOT_MATCH + wrongCompositionId);
 
         var result = provider.getAutomationComposition(compositionTargetId, automationComposition.getInstanceId());
         assertThat(result).isNotNull();
@@ -873,4 +884,4 @@ class AutomationCompositionInstantiationProviderTest {
         provider.compositionInstanceState(compositionId, instanceId, acInstanceStateUpdate);
         verify(supervisionAcHandler).review(any(AutomationComposition.class));
     }
-}
+}
\ No newline at end of file
index dd015b9..44582d6 100644 (file)
@@ -292,6 +292,49 @@ class SupervisionScannerTest {
         verify(messageProvider).removeJob(JOB_ID);
     }
 
+    @Test
+    void testSendAutomationCompositionMigrationReverting() {
+        var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud");
+        automationComposition.setDeployState(DeployState.MIGRATION_REVERTING);
+        automationComposition.setInstanceId(INSTANCE_ID);
+        automationComposition.setCompositionId(COMPOSITION_ID);
+        var compositionTargetId = UUID.randomUUID();
+        automationComposition.setCompositionTargetId(compositionTargetId);
+        automationComposition.setLockState(LockState.LOCKED);
+        automationComposition.setLastMsg(TimestampHelper.now());
+        automationComposition.setPhase(0);
+        for (var element : automationComposition.getElements().values()) {
+            element.setDeployState(DeployState.DEPLOYED);
+            element.setLockState(LockState.LOCKED);
+        }
+
+        var automationCompositionProvider = mock(AutomationCompositionProvider.class);
+        Set<UUID> set = new HashSet<>();
+        set.add(automationComposition.getInstanceId());
+        when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(set);
+        when(automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId()))
+                .thenReturn(Optional.of(automationComposition));
+
+        var definitionTarget = createAutomationCompositionDefinition(AcTypeState.PRIMED);
+        definitionTarget.setCompositionId(compositionTargetId);
+        var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMED);
+        when(acDefinitionProvider.getAcDefinition(compositionTargetId)).thenReturn(definitionTarget);
+        var stageScanner = mock(StageScanner.class);
+
+        var messageProvider = mock(MessageProvider.class);
+        when(messageProvider.createJob(automationComposition.getInstanceId())).thenReturn(Optional.of(JOB_ID));
+        var monitoringScanner = new MonitoringScanner(automationCompositionProvider, acDefinitionProvider,
+                mock(AcDefinitionScanner.class), stageScanner, mock(SimpleScanner.class), mock(PhaseScanner.class),
+                messageProvider);
+        var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+                messageProvider, monitoringScanner);
+
+        supervisionScanner.run();
+        verify(stageScanner).scanStage(automationComposition, definitionTarget.getServiceTemplate(),
+                new UpdateSync());
+        verify(messageProvider).removeJob(JOB_ID);
+    }
+
     @Test
     void testSendAutomationCompositionSimpleScan() {
         var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud");
index 1cd1146..f51d43d 100644 (file)
@@ -101,6 +101,57 @@ class StageScannerTest {
         assertEquals(compositionTargetId, automationComposition.getCompositionId());
     }
 
+    @Test
+    void testSendAutomationCompositionMigrationReverting() {
+        var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud");
+        automationComposition.setInstanceId(UUID.randomUUID());
+        automationComposition.setDeployState(DeployState.MIGRATION_REVERTING);
+        automationComposition.setCompositionId(COMPOSITION_ID);
+        var compositionTargetId = UUID.randomUUID();
+        automationComposition.setCompositionTargetId(compositionTargetId);
+        automationComposition.setLockState(LockState.LOCKED);
+        automationComposition.setLastMsg(TimestampHelper.now());
+        automationComposition.setPhase(0);
+        for (var element : automationComposition.getElements().values()) {
+            element.setDeployState(DeployState.DEPLOYED);
+            element.setLockState(LockState.LOCKED);
+        }
+        // first element is not migrated yet
+        var element = automationComposition.getElements().entrySet().iterator().next().getValue();
+        element.setDeployState(DeployState.MIGRATION_REVERTING);
+
+        var acProvider = mock(AutomationCompositionProvider.class);
+        when(acProvider.updateAutomationComposition(any())).thenReturn(automationComposition);
+        var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
+        var encryptionUtils = new EncryptionUtils(acRuntimeParameterGroup);
+        var supervisionScanner = new StageScanner(acProvider, mock(ParticipantSyncPublisher.class),
+                mock(AutomationCompositionMigrationPublisher.class), mock(AcPreparePublisher.class),
+                acRuntimeParameterGroup, encryptionUtils);
+        var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML);
+        supervisionScanner.scanStage(automationComposition, serviceTemplate, new UpdateSync());
+        verify(acProvider, times(0)).updateAutomationComposition(any(AutomationComposition.class));
+        assertEquals(DeployState.MIGRATION_REVERTING, automationComposition.getDeployState());
+
+        // send message for next stage
+        clearInvocations(acProvider);
+        var toscaNodeTemplate = serviceTemplate.getToscaTopologyTemplate().getNodeTemplates()
+                .get(element.getDefinition().getName());
+        toscaNodeTemplate.setProperties(Map.of("stage", List.of(1)));
+
+        supervisionScanner.scanStage(automationComposition, serviceTemplate, new UpdateSync());
+        verify(acProvider).updateAutomationComposition(any(AutomationComposition.class));
+        assertEquals(DeployState.MIGRATION_REVERTING, automationComposition.getDeployState());
+
+        // first element is migrated
+        clearInvocations(acProvider);
+        element.setDeployState(DeployState.DEPLOYED);
+        supervisionScanner.scanStage(automationComposition, serviceTemplate, new UpdateSync());
+        verify(acProvider).updateAutomationComposition(any(AutomationComposition.class));
+
+        assertEquals(DeployState.DEPLOYED, automationComposition.getDeployState());
+        assertEquals(compositionTargetId, automationComposition.getCompositionId());
+    }
+
     @Test
     void testSendAutomationCompositionPrepare() {
         var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud");