From: akenihan Date: Tue, 17 Jun 2025 09:30:45 +0000 (+0100) Subject: Add rollback support to update data in memory for participant intermediary X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=5abd51cbe6936cd7e418455258a2339709552806;p=policy%2Fclamp.git Add rollback support to update data in memory for participant intermediary Issue-ID: POLICY-5395 Change-Id: I8db012b00112d61b51e6627a6ffb74fe1ce23833 Signed-off-by: akenihan --- diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java index 920f39f23..b281ece46 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java @@ -307,8 +307,13 @@ public class AutomationCompositionHandler { migrateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(), migrationMsg.getCompositionTargetId(), participantDeploy, migrationMsg.getStage()); - callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(), - acCopy, migrationMsg.getCompositionTargetId(), migrationMsg.getStage()); + if (Boolean.TRUE.equals(migrationMsg.getRollback())) { + callParticipantRollback(migrationMsg.getMessageId(), participantDeploy.getAcElementList(), + acCopy, migrationMsg.getCompositionTargetId(), migrationMsg.getStage()); + } else { + callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(), + acCopy, migrationMsg.getCompositionTargetId(), migrationMsg.getStage()); + } } } } @@ -339,13 +344,13 @@ public class AutomationCompositionHandler { var instanceElementMigrateDto = CacheProvider .changeStateToNew(instanceElementMigrateMap.get(acElement.getId())); - listener.migrate(messageId, compositionElementDto, compositionElementTargetDto, instanceElementDto, - instanceElementMigrateDto, stage); + listener.migrate(messageId, compositionElementDto, compositionElementTargetDto, + instanceElementDto, instanceElementMigrateDto, stage); } else { listener.migrate(messageId, compositionElementMap.get(acElement.getId()), compositionElementTargetMap.get(acElement.getId()), - instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()), - stage); + instanceElementMap.get(acElement.getId()), instanceElementMigrateMap + .get(acElement.getId()), stage); } } } @@ -358,10 +363,44 @@ public class AutomationCompositionHandler { Map.of(), Map.of(), ElementState.REMOVED); var instanceDtoTarget = new InstanceElementDto(acCopy.getInstanceId(), elementId, Map.of(), Map.of(), ElementState.REMOVED); - listener.migrate(messageId, compositionElementMap.get(elementId), compositionDtoTarget, instanceElementMap.get(elementId), instanceDtoTarget, 0); } } } + + private void callParticipantRollback(UUID messageId, List acElements, + AutomationComposition acCopy, UUID compositionTargetId, int stage) { + var compositionElementMap = cacheProvider.getCompositionElementDtoMap(acCopy); + var instanceElementMap = cacheProvider.getInstanceElementDtoMap(acCopy); + + for (var acElement : acElements) { + var compositionInProperties = cacheProvider + .getCommonProperties(compositionTargetId, acElement.getDefinition()); + var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties); + if (stageSet.contains(stage)) { + if (instanceElementMap.get(acElement.getId()) == null) { + var compositionElementDto = + new CompositionElementDto(acCopy.getCompositionId(), acElement.getDefinition(), + Map.of(), Map.of(), ElementState.NOT_PRESENT); + var instanceElementDto = new InstanceElementDto(acCopy.getInstanceId(), acElement.getId(), + Map.of(), Map.of(), ElementState.NOT_PRESENT); + + listener.rollback(messageId, compositionElementDto, + instanceElementDto, stage); + } else { + listener.rollback(messageId, compositionElementMap.get(acElement.getId()), + instanceElementMap.get(acElement.getId()), stage); + } + } + } + if (stage == 0) { + // Call rollback for removed elements + List removedElements = findElementsToRemove(acElements, acCopy.getElements()); + for (var elementId : removedElements) { + listener.rollback(messageId, compositionElementMap.get(elementId), + instanceElementMap.get(elementId), 0); + } + } + } } diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java index 590d45f2a..fa69442da 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandler.java @@ -434,4 +434,36 @@ public class ThreadHandler implements Closeable { } executionMap.remove(instanceElement.elementId()); } + + /** + * Handles AutomationComposition Rollback. + * + * @param messageId the messageId + * @param compositionElement the information of the Automation Composition Definition Element + * @param instanceElement the information of the Automation Composition Instance Element + * @param stage the stage + */ + public void rollback(UUID messageId, CompositionElementDto compositionElement, + InstanceElementDto instanceElement, + int stage) { + cleanExecution(instanceElement.elementId(), messageId); + var result = executor.submit(() -> + this.rollbackProcess(compositionElement, + instanceElement, stage)); + executionMap.put(instanceElement.elementId(), result); + } + + private void rollbackProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement, + int stage) { + try { + listener.rollbackMigration(compositionElement, instanceElement, stage); + } catch (PfModelException e) { + LOGGER.error("Automation composition element rollback failed {} {}", + instanceElement.elementId(), e.getMessage()); + intermediaryApi.updateAutomationCompositionElementState( + instanceElement.instanceId(), instanceElement.elementId(), DeployState.DEPLOYED, + null, StateChangeResult.FAILED, "Automation composition rollback migrate failed"); + } + executionMap.remove(instanceElement.elementId()); + } } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java index b60737246..b9a499bef 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java @@ -220,13 +220,20 @@ class AutomationCompositionHandlerTest { var ach = new AutomationCompositionHandler( mock(CacheProvider.class), mock(ParticipantMessagePublisher.class), mock(ThreadHandler.class)); var migrationMsg = new AutomationCompositionMigration(); + var rollbackMsg = new AutomationCompositionMigration(); + rollbackMsg.setRollback(true); + migrationMsg.setStage(0); assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg)); migrationMsg.setAutomationCompositionId(UUID.randomUUID()); migrationMsg.setCompositionTargetId(UUID.randomUUID()); assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg)); - migrationMsg.setRollback(true); - assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(migrationMsg)); + + rollbackMsg.setStage(0); + assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(rollbackMsg)); + rollbackMsg.setAutomationCompositionId(UUID.randomUUID()); + rollbackMsg.setCompositionTargetId(UUID.randomUUID()); + assertDoesNotThrow(() -> ach.handleAutomationCompositionMigration(rollbackMsg)); } @Test @@ -244,7 +251,14 @@ class AutomationCompositionHandlerTest { automationComposition.getInstanceId(), definitions, automationComposition.getCompositionTargetId(), definitions); - testMigration(cacheProvider, automationComposition, 0, automationComposition.getElements().size()); + var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + automationComposition.getCompositionTargetId(), definitions); + + testMigration(cacheProvider, automationComposition, 0, + automationComposition.getElements().size(), false); + testMigration(cacheProviderRollback, automationComposition, 0, + automationComposition.getElements().size(), true); } @Test @@ -271,8 +285,12 @@ class AutomationCompositionHandlerTest { var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), automationComposition.getInstanceId(), definitions, acMigrate.getCompositionTargetId(), migrateDefinitions); + var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + acMigrate.getCompositionTargetId(), migrateDefinitions); - testMigration(cacheProvider, acMigrate, 0, acMigrate.getElements().size() + 1); + testMigration(cacheProvider, acMigrate, 0, acMigrate.getElements().size() + 1, false); + testMigration(cacheProviderRollback, acMigrate, 0, acMigrate.getElements().size() + 1, true); } @Test @@ -306,30 +324,41 @@ class AutomationCompositionHandlerTest { var cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), automationComposition.getInstanceId(), definitions, acMigrate.getCompositionTargetId(), migrateDefinitions); + var cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + acMigrate.getCompositionTargetId(), migrateDefinitions); + // scenario 1,2 migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate() .setProperties(Map.of("stage", List.of(1, 2)))); // expected the element deleted - testMigration(cacheProvider, acMigrate, 0, 1); + testMigration(cacheProvider, acMigrate, 0, 1, false); + testMigration(cacheProviderRollback, acMigrate, 0, 1, true); // expected 4 elements from stage 1 - testMigration(cacheProvider, acMigrate, 1, 4); + testMigration(cacheProvider, acMigrate, 1, 4, false); + testMigration(cacheProviderRollback, acMigrate, 1, 4, true); // scenario 0,2 cacheProvider = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), automationComposition.getInstanceId(), definitions, acMigrate.getCompositionTargetId(), migrateDefinitions); + cacheProviderRollback = createCacheProvider(participantDeploy, automationComposition.getCompositionId(), + automationComposition.getInstanceId(), definitions, + acMigrate.getCompositionTargetId(), migrateDefinitions); migrateDefinitions.forEach(el -> el.getAutomationCompositionElementToscaNodeTemplate() .setProperties(Map.of("stage", List.of(0, 2)))); // expected the element deleted + 4 elements from stage 0 - testMigration(cacheProvider, acMigrate, 0, 5); + testMigration(cacheProvider, acMigrate, 0, 5, false); + testMigration(cacheProviderRollback, acMigrate, 0, 5, true); // expected 0 elements - testMigration(cacheProvider, acMigrate, 1, 0); + testMigration(cacheProvider, acMigrate, 1, 0, false); + testMigration(cacheProviderRollback, acMigrate, 1, 0, true); } private CacheProvider createCacheProvider(ParticipantDeploy participantDeploy, @@ -343,20 +372,28 @@ class AutomationCompositionHandlerTest { } private void testMigration(CacheProvider cacheProvider, AutomationComposition acMigrate, - int stage, int expectedMigrated) { + int stage, int expectedMigrated, boolean rollback) { var migrationMsg = new AutomationCompositionMigration(); migrationMsg.setStage(stage); migrationMsg.setCompositionId(acMigrate.getCompositionId()); migrationMsg.setAutomationCompositionId(acMigrate.getInstanceId()); migrationMsg.setCompositionTargetId(acMigrate.getCompositionTargetId()); - migrationMsg.setRollback(false); var participantMigrate = CommonTestData.createparticipantDeploy(cacheProvider.getParticipantId(), acMigrate); migrationMsg.setParticipantUpdatesList(List.of(participantMigrate)); var listener = mock(ThreadHandler.class); clearInvocations(); - var ach = new AutomationCompositionHandler(cacheProvider, mock(ParticipantMessagePublisher.class), listener); + var ach = new AutomationCompositionHandler(cacheProvider, + mock(ParticipantMessagePublisher.class), listener); + + clearInvocations(); + migrationMsg.setRollback(rollback); ach.handleAutomationCompositionMigration(migrationMsg); - verify(listener, times(expectedMigrated)).migrate(any(), any(), any(), any(), any(), anyInt()); + + if (!rollback) { + verify(listener, times(expectedMigrated)).migrate(any(), any(), any(), any(), any(), anyInt()); + } else { + verify(listener, times(expectedMigrated)).rollback(any(), any(), any(), anyInt()); + } } } diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java index 957f6e76e..f03990a63 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ThreadHandlerTest.java @@ -128,6 +128,11 @@ class ThreadHandlerTest { verify(listener, timeout(TIMEOUT)).migrate(compositionElement, compositionElementTarget, instanceElement, instanceElementUpdated, 0); + clearInvocations(listener); + threadHandler.rollback(messageId, compositionElement, instanceElement, 0); + verify(listener, timeout(TIMEOUT)).rollbackMigration(compositionElement, instanceElement, 0); + + clearInvocations(listener); threadHandler.undeploy(messageId, compositionElement, instanceElement); verify(listener, timeout(TIMEOUT)).undeploy(compositionElement, instanceElement); @@ -330,6 +335,14 @@ class ThreadHandlerTest { verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Automation composition element migrate precheck failed"); + + clearInvocations(listener); + doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener) + .rollbackMigration(compositionElement, instanceElement, 0); + threadHandler.rollback(compositionElement.compositionId(), compositionElement, instanceElement, 0); + verify(intermediaryApi, timeout(TIMEOUT)).updateAutomationCompositionElementState(instanceId, elementId, + DeployState.DEPLOYED, null, StateChangeResult.FAILED, + "Automation composition element migrate precheck failed"); } } }