From a944487231ad341d8d6b0f302c47bad20169c107 Mon Sep 17 00:00:00 2001 From: FrancescoFioraEst Date: Wed, 7 Aug 2024 10:52:23 +0100 Subject: Add validation for state set by the participant Issue-ID: POLICY-5097 Change-Id: I7520b7220c8525448eff707e2e57debca63520fe Signed-off-by: FrancescoFioraEst --- .../runtime/supervision/SupervisionAcHandler.java | 66 ++++++++++++------ .../runtime/supervision/SupervisionHandler.java | 32 +++++---- .../supervision/SupervisionAcHandlerTest.java | 63 +++++++++++++++++ .../supervision/SupervisionHandlerTest.java | 78 +++++++++++----------- 4 files changed, 167 insertions(+), 72 deletions(-) (limited to 'runtime-acm') diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java index 66f035e5e..6a56a2c2b 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java @@ -23,7 +23,6 @@ package org.onap.policy.clamp.acm.runtime.supervision; import io.micrometer.core.annotation.Timed; import io.opentelemetry.context.Context; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.ExecutorService; @@ -38,7 +37,6 @@ import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublish import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck; 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.AutomationCompositionElement; 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.ParticipantUtils; @@ -259,10 +257,14 @@ public class SupervisionAcHandler { } private void setAcElementStateInDb(AutomationCompositionDeployAck automationCompositionAckMessage) { + if (!validateMessage(automationCompositionAckMessage)) { + return; + } + var automationCompositionOpt = automationCompositionProvider .findAutomationComposition(automationCompositionAckMessage.getAutomationCompositionId()); if (automationCompositionOpt.isEmpty()) { - LOGGER.warn("AutomationComposition not found in database {}", + LOGGER.error("AutomationComposition not found in database {}", automationCompositionAckMessage.getAutomationCompositionId()); return; } @@ -271,13 +273,7 @@ public class SupervisionAcHandler { if (automationCompositionAckMessage.getAutomationCompositionResultMap() == null || automationCompositionAckMessage.getAutomationCompositionResultMap().isEmpty()) { if (DeployState.DELETING.equals(automationComposition.getDeployState())) { - // scenario when Automation Composition instance has never been deployed - for (var element : automationComposition.getElements().values()) { - if (element.getParticipantId().equals(automationCompositionAckMessage.getParticipantId())) { - element.setDeployState(DeployState.DELETED); - automationCompositionProvider.updateAutomationCompositionElement(element); - } - } + deleteAcInstance(automationComposition, automationCompositionAckMessage.getParticipantId()); } else { LOGGER.warn("Empty AutomationCompositionResultMap {} {}", automationCompositionAckMessage.getAutomationCompositionId(), @@ -296,6 +292,40 @@ public class SupervisionAcHandler { } } + private boolean validateMessage(AutomationCompositionDeployAck acAckMessage) { + if (acAckMessage.getAutomationCompositionId() == null + || acAckMessage.getStateChangeResult() == null) { + LOGGER.error("Not valid AutomationCompositionDeployAck message"); + return false; + } + if (!StateChangeResult.NO_ERROR.equals(acAckMessage.getStateChangeResult()) + && !StateChangeResult.FAILED.equals(acAckMessage.getStateChangeResult())) { + LOGGER.error("Not valid AutomationCompositionDeployAck message, stateChangeResult is not valid {} ", + acAckMessage.getStateChangeResult()); + return false; + } + + if (acAckMessage.getStage() == null) { + for (var el : acAckMessage.getAutomationCompositionResultMap().values()) { + if (AcmUtils.isInTransitionalState(el.getDeployState(), el.getLockState(), SubState.NONE)) { + LOGGER.error("Not valid AutomationCompositionDeployAck message, states are not valid"); + return false; + } + } + } + return true; + } + + private void deleteAcInstance(AutomationComposition automationComposition, UUID participantId) { + // scenario when Automation Composition instance has never been deployed + for (var element : automationComposition.getElements().values()) { + if (element.getParticipantId().equals(participantId)) { + element.setDeployState(DeployState.DELETED); + automationCompositionProvider.updateAutomationCompositionElement(element); + } + } + } + private boolean updateState(AutomationComposition automationComposition, Set> automationCompositionResultSet, StateChangeResult stateChangeResult, Integer stage) { @@ -309,28 +339,20 @@ public class SupervisionAcHandler { for (var acElementAck : automationCompositionResultSet) { var element = automationComposition.getElements().get(acElementAck.getKey()); if (element != null) { - element.setMessage(acElementAck.getValue().getMessage()); + element.setMessage(AcmUtils.validatedMessage(acElementAck.getValue().getMessage())); element.setOutProperties(acElementAck.getValue().getOutProperties()); element.setOperationalState(acElementAck.getValue().getOperationalState()); element.setUseState(acElementAck.getValue().getUseState()); - element.setSubState(SubState.NONE); + if (stage == null) { + element.setSubState(SubState.NONE); + } element.setDeployState(acElementAck.getValue().getDeployState()); element.setLockState(acElementAck.getValue().getLockState()); element.setStage(stage); - element.setRestarting(null); automationCompositionProvider.updateAutomationCompositionElement(element); } } - if (automationComposition.getRestarting() != null) { - var restarting = automationComposition.getElements().values().stream() - .map(AutomationCompositionElement::getRestarting).filter(Objects::nonNull).findAny(); - if (restarting.isEmpty()) { - automationComposition.setRestarting(null); - updated = true; - } - } - return updated; } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java index a4e470495..95294285e 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java @@ -30,6 +30,7 @@ import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider; +import org.onap.policy.clamp.models.acm.utils.AcmUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -53,6 +54,22 @@ public class SupervisionHandler { */ @Timed(value = "listener.participant_prime_ack", description = "PARTICIPANT_PRIME_ACK messages received") public void handleParticipantMessage(ParticipantPrimeAck participantPrimeAckMessage) { + if (participantPrimeAckMessage.getCompositionId() == null + || participantPrimeAckMessage.getCompositionState() == null + || participantPrimeAckMessage.getStateChangeResult() == null) { + LOGGER.error("Not valid ParticipantPrimeAck message"); + return; + } + if (AcTypeState.PRIMING.equals(participantPrimeAckMessage.getCompositionState()) + || AcTypeState.DEPRIMING.equals(participantPrimeAckMessage.getCompositionState())) { + LOGGER.error("Not valid state {}", participantPrimeAckMessage.getCompositionState()); + return; + } + if (!StateChangeResult.NO_ERROR.equals(participantPrimeAckMessage.getStateChangeResult()) + && !StateChangeResult.FAILED.equals(participantPrimeAckMessage.getStateChangeResult())) { + LOGGER.error("Vot valid stateChangeResult {} ", participantPrimeAckMessage.getStateChangeResult()); + return; + } var acDefinitionOpt = acDefinitionProvider.findAcDefinition(participantPrimeAckMessage.getCompositionId()); if (acDefinitionOpt.isEmpty()) { LOGGER.warn("AC Definition not found in database {}", participantPrimeAckMessage.getCompositionId()); @@ -60,7 +77,7 @@ public class SupervisionHandler { } var acDefinition = acDefinitionOpt.get(); if (!AcTypeState.PRIMING.equals(acDefinition.getState()) - && !AcTypeState.DEPRIMING.equals(acDefinition.getState()) && acDefinition.getRestarting() == null) { + && !AcTypeState.DEPRIMING.equals(acDefinition.getState())) { LOGGER.error("AC Definition {} already primed/deprimed with participant {}", participantPrimeAckMessage.getCompositionId(), participantPrimeAckMessage.getParticipantId()); return; @@ -81,15 +98,11 @@ public class SupervisionHandler { } boolean completed = true; - boolean restarting = false; for (var element : acDefinition.getElementStateMap().values()) { handlePrimeAckElement(participantPrimeAckMessage, element); if (!finalState.equals(element.getState())) { completed = false; } - if (element.getRestarting() != null) { - restarting = true; - } } if (inProgress && !msgInErrors && completed) { @@ -99,13 +112,9 @@ public class SupervisionHandler { acDefinition.setStateChangeResult(StateChangeResult.NO_ERROR); } } - if (!restarting && acDefinition.getRestarting() != null) { - toUpdate = true; - acDefinition.setRestarting(null); - } if (toUpdate) { acDefinitionProvider.updateAcDefinitionState(acDefinition.getCompositionId(), acDefinition.getState(), - acDefinition.getStateChangeResult(), acDefinition.getRestarting()); + acDefinition.getStateChangeResult(), null); if (!participantPrimeAckMessage.getParticipantId().equals(participantPrimeAckMessage.getReplicaId())) { participantSyncPublisher.sendSync(acDefinition, participantPrimeAckMessage.getReplicaId()); } @@ -114,9 +123,8 @@ public class SupervisionHandler { private void handlePrimeAckElement(ParticipantPrimeAck participantPrimeAckMessage, NodeTemplateState element) { if (participantPrimeAckMessage.getParticipantId().equals(element.getParticipantId())) { - element.setMessage(participantPrimeAckMessage.getMessage()); + element.setMessage(AcmUtils.validatedMessage(participantPrimeAckMessage.getMessage())); element.setState(participantPrimeAckMessage.getCompositionState()); - element.setRestarting(null); acDefinitionProvider.updateAcDefinitionElement(element, participantPrimeAckMessage.getCompositionId()); } } diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java index 5f87db30c..b104084a8 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java @@ -59,6 +59,68 @@ class SupervisionAcHandlerTest { private static final String AC_INSTANTIATION_CREATE_JSON = "src/test/resources/rest/acm/AutomationComposition.json"; private static final UUID IDENTIFIER = UUID.randomUUID(); + @Test + void testAutomationCompositionDeployAckNull() { + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class), + mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), + mock(AcElementPropertiesPublisher.class), null, + mock(ParticipantSyncPublisher.class), null); + + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud"); + automationComposition.setInstanceId(IDENTIFIER); + var automationCompositionAckMessage = + getAutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK, + automationComposition, DeployState.DEPLOYED, LockState.UNLOCKED); + automationCompositionAckMessage.setStateChangeResult(null); + handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage); + + automationCompositionAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); + automationCompositionAckMessage.setAutomationCompositionId(null); + handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage); + + automationCompositionAckMessage.setAutomationCompositionId(automationComposition.getInstanceId()); + handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage); + + automationCompositionAckMessage = + getAutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK, + automationComposition, DeployState.DEPLOYING, LockState.UNLOCKED); + handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage); + + verify(automationCompositionProvider, times(0)).updateAutomationCompositionElement(any()); + } + + @Test + void testHandleAcMigrationWithStage() { + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud"); + automationComposition.setInstanceId(IDENTIFIER); + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + when(automationCompositionProvider.findAutomationComposition(IDENTIFIER)) + .thenReturn(Optional.of(automationComposition)); + when(automationCompositionProvider.updateAcState(any(AutomationComposition.class))) + .thenReturn(automationComposition); + + var acDefinitionProvider = mock(AcDefinitionProvider.class); + when(acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId())) + .thenReturn(new AutomationCompositionDefinition()); + + var handler = new SupervisionAcHandler(automationCompositionProvider, acDefinitionProvider, + mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), + mock(AcElementPropertiesPublisher.class), null, + mock(ParticipantSyncPublisher.class), null); + + var automationCompositionAckMessage = + getAutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK, + automationComposition, DeployState.MIGRATING, LockState.LOCKED); + automationCompositionAckMessage.setStage(1); + handler.handleAutomationCompositionStateChangeAckMessage(automationCompositionAckMessage); + + verify(automationCompositionProvider, times(3)) + .updateAutomationCompositionElement(any(AutomationCompositionElement.class)); + } + @Test void testHandleAutomationCompositionStateChangeAckMessage() { var automationComposition = @@ -319,6 +381,7 @@ class SupervisionAcHandlerTest { automationCompositionAckMessage .setParticipantId(automationComposition.getElements().values().iterator().next().getParticipantId()); automationCompositionAckMessage.setAutomationCompositionId(IDENTIFIER); + automationCompositionAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AcDefinitionProvider.class), mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java index e8be3b6b7..e689e6467 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java @@ -28,35 +28,68 @@ import static org.mockito.Mockito.when; import static org.onap.policy.clamp.acm.runtime.util.CommonTestData.TOSCA_SERVICE_TEMPLATE_YAML; import java.util.Optional; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.onap.policy.clamp.acm.runtime.instantiation.InstantiationUtils; import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublisher; 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.ParticipantState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider; class SupervisionHandlerTest { + @Test + void testParticipantPrimeAckNull() { + var acDefinitionProvider = mock(AcDefinitionProvider.class); + var handler = new SupervisionHandler(acDefinitionProvider, mock(ParticipantSyncPublisher.class)); + + var participantPrimeAckMessage = new ParticipantPrimeAck(); + participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); + handler.handleParticipantMessage(participantPrimeAckMessage); + + participantPrimeAckMessage.setCompositionId(UUID.randomUUID()); + handler.handleParticipantMessage(participantPrimeAckMessage); + + participantPrimeAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); + handler.handleParticipantMessage(participantPrimeAckMessage); + + participantPrimeAckMessage.setStateChangeResult(null); + participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); + handler.handleParticipantMessage(participantPrimeAckMessage); + + participantPrimeAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); + participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMING); + handler.handleParticipantMessage(participantPrimeAckMessage); + + participantPrimeAckMessage.setCompositionState(AcTypeState.DEPRIMING); + handler.handleParticipantMessage(participantPrimeAckMessage); + + verify(acDefinitionProvider, times(0)).findAcDefinition(any()); + verify(acDefinitionProvider, times(0)).updateAcDefinitionElement(any(), any()); + } + @Test void testParticipantPrimeAckNotFound() { var participantPrimeAckMessage = new ParticipantPrimeAck(); participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); - participantPrimeAckMessage.setState(ParticipantState.ON_LINE); + participantPrimeAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); + participantPrimeAckMessage.setCompositionId(UUID.randomUUID()); + participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); var acDefinitionProvider = mock(AcDefinitionProvider.class); var handler = new SupervisionHandler(acDefinitionProvider, mock(ParticipantSyncPublisher.class)); - handler.handleParticipantMessage(participantPrimeAckMessage); - verify(acDefinitionProvider).findAcDefinition(any()); + verify(acDefinitionProvider).findAcDefinition(participantPrimeAckMessage.getCompositionId()); + verify(acDefinitionProvider, times(0)).updateAcDefinitionElement(any(), any()); } @Test void testParticipantPrimeAckPrimed() { var participantPrimeAckMessage = new ParticipantPrimeAck(); participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); - participantPrimeAckMessage.setState(ParticipantState.ON_LINE); + participantPrimeAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); + participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); var acDefinition = CommonTestData.createAcDefinition( InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMED); @@ -76,7 +109,7 @@ class SupervisionHandlerTest { var participantPrimeAckMessage = new ParticipantPrimeAck(); participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); - participantPrimeAckMessage.setState(ParticipantState.ON_LINE); + participantPrimeAckMessage.setStateChangeResult(StateChangeResult.NO_ERROR); var acDefinition = CommonTestData.createAcDefinition( InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMING); @@ -104,7 +137,7 @@ class SupervisionHandlerTest { void testParticipantPrimeAckFailed() { var participantPrimeAckMessage = new ParticipantPrimeAck(); participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); - participantPrimeAckMessage.setState(ParticipantState.ON_LINE); + participantPrimeAckMessage.setCompositionState(AcTypeState.COMMISSIONED); participantPrimeAckMessage.setStateChangeResult(StateChangeResult.FAILED); var acDefinition = CommonTestData.createAcDefinition( @@ -125,35 +158,4 @@ class SupervisionHandlerTest { verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), AcTypeState.PRIMING, StateChangeResult.FAILED, null); } - - @Test - void testParticipantPrimeAckRestarted() { - var participantPrimeAckMessage = new ParticipantPrimeAck(); - participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); - participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); - participantPrimeAckMessage.setState(ParticipantState.ON_LINE); - - var acDefinition = CommonTestData.createAcDefinition( - InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMED); - acDefinition.setStateChangeResult(StateChangeResult.TIMEOUT); - acDefinition.setRestarting(true); - participantPrimeAckMessage.setCompositionId(acDefinition.getCompositionId()); - for (var element : acDefinition.getElementStateMap().values()) { - element.setParticipantId(CommonTestData.getParticipantId()); - element.setRestarting(true); - } - - var acDefinitionProvider = mock(AcDefinitionProvider.class); - when(acDefinitionProvider.findAcDefinition(acDefinition.getCompositionId())) - .thenReturn(Optional.of(acDefinition)); - - var handler = new SupervisionHandler(acDefinitionProvider, mock(ParticipantSyncPublisher.class)); - - handler.handleParticipantMessage(participantPrimeAckMessage); - verify(acDefinitionProvider).findAcDefinition(any()); - verify(acDefinitionProvider, times(acDefinition.getElementStateMap().size())) - .updateAcDefinitionElement(any(), any()); - verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), AcTypeState.PRIMED, - StateChangeResult.NO_ERROR, null); - } } -- cgit