From ebb4d0cf867d752ae148880dd0109fc3cf6d6025 Mon Sep 17 00:00:00 2001 From: FrancescoFioraEst Date: Wed, 31 May 2023 16:38:22 +0100 Subject: Add Failure handling support in the ACM-R Issue-ID: POLICY-4705 Change-Id: I919b7981cdbe69ac7ce703fceb2e980a6d9a056e Signed-off-by: FrancescoFioraEst --- .../models/acm/concepts/AutomationComposition.java | 3 + .../acm/concepts/AutomationCompositionElement.java | 4 +- .../models/acm/concepts/StateChangeResult.java | 26 ++++ .../dmaap/participant/ParticipantAckMessage.java | 6 +- .../concepts/JpaAutomationComposition.java | 15 +- .../concepts/JpaAutomationCompositionElement.java | 10 ++ .../provider/AcInstanceStateResolver.java | 49 ++++-- .../policy/clamp/models/acm/utils/AcmUtils.java | 3 +- .../provider/AcInstanceStateResolverTest.java | 28 ++-- .../handler/AutomationCompositionHandler.java | 5 +- ...AutomationCompositionInstantiationProvider.java | 30 ++-- .../runtime/supervision/SupervisionAcHandler.java | 83 +++++++++-- .../runtime/supervision/SupervisionScanner.java | 5 + .../supervision/SupervisionAcHandlerTest.java | 166 +++++++++++++++++++-- 14 files changed, 364 insertions(+), 69 deletions(-) create mode 100644 models/src/main/java/org/onap/policy/clamp/models/acm/concepts/StateChangeResult.java diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java index dc8a39b34..54c9b6190 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/AutomationComposition.java @@ -50,6 +50,8 @@ public class AutomationComposition extends ToscaEntity implements Comparable elements; + private StateChangeResult stateChangeResult; + /** * Copy contructor, does a deep copy. * @@ -62,6 +64,7 @@ public class AutomationComposition extends ToscaEntity implements Comparable(), DeployState.UNDEPLOYED, LockState.LOCKED); + new ArrayList<>(), DeployState.UNDEPLOYED, LockState.NONE); } /** @@ -139,6 +143,7 @@ public class JpaAutomationComposition extends Validated this.deployState = copyConcept.deployState; this.lockState = copyConcept.lockState; this.description = copyConcept.description; + this.stateChangeResult = copyConcept.stateChangeResult; this.elements = PfUtils.mapList(copyConcept.elements, JpaAutomationCompositionElement::new); } @@ -162,6 +167,7 @@ public class JpaAutomationComposition extends Validated automationComposition.setDeployState(deployState); automationComposition.setLockState(lockState); automationComposition.setDescription(description); + automationComposition.setStateChangeResult(stateChangeResult); automationComposition.setElements(new LinkedHashMap<>(this.elements.size())); for (var element : this.elements) { automationComposition.getElements().put(UUID.fromString(element.getElementId()), element.toAuthorative()); @@ -179,7 +185,7 @@ public class JpaAutomationComposition extends Validated this.deployState = automationComposition.getDeployState(); this.lockState = automationComposition.getLockState(); this.description = automationComposition.getDescription(); - + this.stateChangeResult = automationComposition.getStateChangeResult(); this.elements = new ArrayList<>(automationComposition.getElements().size()); for (var elementEntry : automationComposition.getElements().entrySet()) { var jpaAutomationCompositionElement = @@ -232,6 +238,11 @@ public class JpaAutomationComposition extends Validated if (result != 0) { return result; } + + result = ObjectUtils.compare(stateChangeResult, other.stateChangeResult); + if (result != 0) { + return result; + } return PfUtils.compareObjects(elements, other.elements); } } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionElement.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionElement.java index 27da0399c..60a911b21 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionElement.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/concepts/JpaAutomationCompositionElement.java @@ -101,6 +101,9 @@ public class JpaAutomationCompositionElement extends Validated @Column private String description; + @Column + private String message; + @Lob @NotNull @Valid @@ -169,6 +172,7 @@ public class JpaAutomationCompositionElement extends Validated this.lockState = copyConcept.lockState; this.operationalState = copyConcept.operationalState; this.useState = copyConcept.useState; + this.message = copyConcept.message; } /** @@ -194,6 +198,7 @@ public class JpaAutomationCompositionElement extends Validated element.setLockState(lockState); element.setOperationalState(operationalState); element.setUseState(useState); + element.setMessage(message); return element; } @@ -209,6 +214,7 @@ public class JpaAutomationCompositionElement extends Validated this.lockState = element.getLockState(); this.operationalState = element.getOperationalState(); this.useState = element.getUseState(); + this.message = element.getMessage(); } @Override @@ -260,6 +266,10 @@ public class JpaAutomationCompositionElement extends Validated return result; } + result = ObjectUtils.compare(message, other.message); + if (result != 0) { + return result; + } return ObjectUtils.compare(description, other.description); } } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolver.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolver.java index 8676b3397..659169b9f 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolver.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolver.java @@ -22,6 +22,7 @@ package org.onap.policy.clamp.models.acm.persistence.provider; 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; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder; import org.onap.policy.clamp.models.acm.utils.StateDefinition; @@ -32,15 +33,24 @@ public class AcInstanceStateResolver { private final StateDefinition graph; private static final String DEPLOYED = DeployState.DEPLOYED.name(); + private static final String DEPLOYING = DeployState.DEPLOYING.name(); private static final String UNDEPLOYED = DeployState.UNDEPLOYED.name(); + private static final String UNDEPLOYING = DeployState.UNDEPLOYING.name(); + private static final String UPDATING = DeployState.UPDATING.name(); + private static final String DELETING = DeployState.DELETING.name(); 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(); private static final String DEPLOY_NONE = DeployOrder.NONE.name(); private static final String LOCK_NONE = LockOrder.NONE.name(); + private static final String NO_ERROR = StateChangeResult.NO_ERROR.name(); + private static final String FAILED = StateChangeResult.FAILED.name(); + // list of results public static final String DEPLOY = DeployOrder.DEPLOY.name(); public static final String UNDEPLOY = DeployOrder.UNDEPLOY.name(); @@ -53,13 +63,30 @@ public class AcInstanceStateResolver { * Construct. */ public AcInstanceStateResolver() { - this.graph = new StateDefinition<>(4, NONE); + this.graph = new StateDefinition<>(5, NONE); + + // no error + this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYED, STATE_LOCKED_NONE, NO_ERROR}, DEPLOY); + this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYED, LOCKED, NO_ERROR}, UNDEPLOY); + this.graph.put(new String[] {DELETE, LOCK_NONE, UNDEPLOYED, LOCK_NONE, NO_ERROR}, DELETE); + this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, LOCKED, NO_ERROR}, UNLOCK); + this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, UNLOCKED, NO_ERROR}, LOCK); + + // failed + this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, FAILED}, DEPLOY); + this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UNDEPLOYING, STATE_LOCKED_NONE, FAILED}, UNDEPLOY); + this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, UPDATING, STATE_LOCKED_NONE, FAILED}, UNDEPLOY); + + this.graph.put(new String[] {DEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, FAILED}, DEPLOY); + this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYING, STATE_LOCKED_NONE, FAILED}, UNDEPLOY); + + this.graph.put(new String[] {DELETE, LOCK_NONE, DELETING, LOCK_NONE, FAILED}, DELETE); + + this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, LOCKING, FAILED}, UNLOCK); + this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, LOCKING, FAILED}, LOCK); - this.graph.put(new String[] {DEPLOY, LOCK_NONE, UNDEPLOYED, STATE_LOCKED_NONE}, DEPLOY); - this.graph.put(new String[] {UNDEPLOY, LOCK_NONE, DEPLOYED, LOCKED}, UNDEPLOY); - this.graph.put(new String[] {DELETE, LOCK_NONE, UNDEPLOYED, LOCK_NONE}, DELETE); - this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, LOCKED}, UNLOCK); - this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, UNLOCKED}, LOCK); + this.graph.put(new String[] {DEPLOY_NONE, LOCK, DEPLOYED, UNLOCKING, FAILED}, LOCK); + this.graph.put(new String[] {DEPLOY_NONE, UNLOCK, DEPLOYED, UNLOCKING, FAILED}, UNLOCK); } /** @@ -68,17 +95,19 @@ public class AcInstanceStateResolver { * @param acDeployOrder the Deploy Ordered * @param acLockOrder the Lock Ordered * @param acDeployState then current Deploy State - * @param acLockState the current Lock State + * @param acLockState the current Lock State + * @param acStateChangeResult the current Result of the State Change * @return the order (DEPLOY/UNDEPLOY/LOCK/UNLOCK) to send to participant or NONE if order is not consistent */ public String resolve(DeployOrder acDeployOrder, LockOrder acLockOrder, DeployState acDeployState, - LockState acLockState) { + LockState acLockState, StateChangeResult acStateChangeResult) { var deployOrder = acDeployOrder != null ? acDeployOrder : DeployOrder.NONE; var lockOrder = acLockOrder != null ? acLockOrder : LockOrder.NONE; + var stateChangeResult = acStateChangeResult != null ? acStateChangeResult : StateChangeResult.NO_ERROR; var deployState = acDeployState != null ? acDeployState : DeployState.UNDEPLOYED; var lockState = acLockState != null ? acLockState : LockState.NONE; - return this.graph - .get(new String[] {deployOrder.name(), lockOrder.name(), deployState.name(), lockState.name()}); + return this.graph.get(new String[] {deployOrder.name(), lockOrder.name(), deployState.name(), lockState.name(), + stateChangeResult.name()}); } } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java b/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java index 7de4720ad..671aca60f 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/utils/AcmUtils.java @@ -285,7 +285,7 @@ public final class AcmUtils { public static boolean isInTransitionalState(DeployState deployState, LockState lockState) { return DeployState.DEPLOYING.equals(deployState) || DeployState.UNDEPLOYING.equals(deployState) || LockState.LOCKING.equals(lockState) || LockState.UNLOCKING.equals(lockState) - || DeployState.DELETING.equals(deployState); + || DeployState.DELETING.equals(deployState) || DeployState.UPDATING.equals(deployState); } /** @@ -339,6 +339,7 @@ public final class AcmUtils { public static DeployState deployCompleted(DeployState deployState) { DeployState result = null; switch (deployState) { + case UPDATING: case DEPLOYING: result = DeployState.DEPLOYED; break; diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolverTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolverTest.java index 103bca2ec..7f6cb2f0c 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolverTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcInstanceStateResolverTest.java @@ -25,6 +25,7 @@ import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; 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; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder; @@ -33,32 +34,33 @@ class AcInstanceStateResolverTest { @Test void testResolve() { var acTypeStateResolver = new AcInstanceStateResolver(); - var result = - acTypeStateResolver.resolve(DeployOrder.DEPLOY, LockOrder.NONE, DeployState.UNDEPLOYED, LockState.NONE); + var result = acTypeStateResolver.resolve(DeployOrder.DEPLOY, LockOrder.NONE, DeployState.UNDEPLOYED, + LockState.NONE, StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.DEPLOY); result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, DeployState.DEPLOYED, - LockState.LOCKED); + LockState.LOCKED, StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.UNDEPLOY); - result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, DeployState.DEPLOYED, - LockState.LOCKED); + result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, DeployState.DEPLOYED, LockState.LOCKED, + StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.UNLOCK); - result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.LOCK, DeployState.DEPLOYED, - LockState.UNLOCKED); + result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.LOCK, DeployState.DEPLOYED, LockState.UNLOCKED, + StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.LOCK); - result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, DeployState.UNDEPLOYED, LockState.NONE); + result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.NONE, DeployState.UNDEPLOYED, LockState.NONE, + StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.NONE); result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.UNLOCK, DeployState.DEPLOYED, - LockState.LOCKED); + LockState.LOCKED, StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.NONE); - result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, DeployState.UNDEPLOYED, - LockState.NONE); + result = acTypeStateResolver.resolve(DeployOrder.NONE, LockOrder.UNLOCK, DeployState.UNDEPLOYED, LockState.NONE, + StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.NONE); result = acTypeStateResolver.resolve(DeployOrder.UNDEPLOY, LockOrder.NONE, DeployState.DEPLOYING, - LockState.NONE); + LockState.NONE, StateChangeResult.NO_ERROR); assertThat(result).isEqualTo(AcInstanceStateResolver.NONE); - result = acTypeStateResolver.resolve(null, null, null, null); + result = acTypeStateResolver.resolve(null, null, null, null, null); assertThat(result).isEqualTo(AcInstanceStateResolver.NONE); } 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 9087054fe..514bc655f 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 @@ -209,8 +209,11 @@ public class AutomationCompositionHandler { private boolean checkConsistantOrderState(AutomationComposition automationComposition, DeployOrder deployOrder, LockOrder lockOrder) { + if (DeployOrder.UPDATE.equals(deployOrder)) { + return true; + } return acInstanceStateResolver.resolve(deployOrder, lockOrder, automationComposition.getDeployState(), - automationComposition.getLockState()) != null; + automationComposition.getLockState(), automationComposition.getStateChangeResult()) != null; } /** diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java index 787547860..eb0c9b7d2 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java @@ -21,8 +21,6 @@ package org.onap.policy.clamp.acm.runtime.instantiation; - -import java.util.Map; import java.util.UUID; import javax.validation.Valid; import javax.ws.rs.core.Response; @@ -31,7 +29,6 @@ import lombok.AllArgsConstructor; import org.onap.policy.clamp.acm.runtime.supervision.SupervisionAcHandler; 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.AutomationCompositionElement; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositions; import org.onap.policy.clamp.models.acm.concepts.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; @@ -126,12 +123,13 @@ public class AutomationCompositionInstantiationProvider { response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier()); return response; - } else if (DeployState.DEPLOYED.equals(acToUpdate.getDeployState()) + } else if ((DeployState.DEPLOYED.equals(acToUpdate.getDeployState()) + || DeployState.UPDATING.equals(acToUpdate.getDeployState())) && LockState.LOCKED.equals(acToUpdate.getLockState())) { return updateDeployedAutomationComposition(compositionId, automationComposition, acToUpdate); } throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, - "Not allowed to update in the state " + acToUpdate.getDeployState()); + "Not allowed to update in the state " + acToUpdate.getDeployState()); } /** @@ -143,24 +141,24 @@ public class AutomationCompositionInstantiationProvider { * @return the result of the update */ public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId, - AutomationComposition automationComposition, - AutomationComposition acToBeUpdated) { + AutomationComposition automationComposition, AutomationComposition acToBeUpdated) { // Iterate and update the element property values - for (Map.Entry dbAcElement : acToBeUpdated.getElements().entrySet()) { + for (var dbAcElement : acToBeUpdated.getElements().entrySet()) { var elementId = dbAcElement.getKey(); if (automationComposition.getElements().containsKey(elementId)) { - dbAcElement.getValue().getProperties().putAll(automationComposition.getElements().get(elementId) - .getProperties()); + dbAcElement.getValue().getProperties() + .putAll(automationComposition.getElements().get(elementId).getProperties()); } } - // Publish property update event to the participants - supervisionAcHandler.update(acToBeUpdated); - 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); + automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated); var response = new InstantiationResponse(); var instanceId = automationComposition.getInstanceId(); @@ -169,7 +167,6 @@ public class AutomationCompositionInstantiationProvider { return response; } - /** * Validate AutomationComposition. * @@ -234,7 +231,8 @@ public class AutomationCompositionInstantiationProvider { throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId); } - if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState())) { + if (!DeployState.UNDEPLOYED.equals(automationComposition.getDeployState()) + && !DeployState.DELETING.equals(automationComposition.getDeployState())) { throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, "Automation composition state is still " + automationComposition.getDeployState()); } @@ -279,7 +277,7 @@ public class AutomationCompositionInstantiationProvider { var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId()); var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(), acInstanceStateUpdate.getLockOrder(), automationComposition.getDeployState(), - automationComposition.getLockState()); + automationComposition.getLockState(), automationComposition.getStateChangeResult()); switch (result) { case "DEPLOY": supervisionAcHandler.deploy(automationComposition, acDefinition); 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 da3cbc399..e9f8d6ce5 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 @@ -34,6 +34,7 @@ import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition 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; +import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck; import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider; import org.onap.policy.clamp.models.acm.utils.AcmUtils; @@ -55,7 +56,6 @@ public class SupervisionAcHandler { // Publishers for participant communication private final AutomationCompositionDeployPublisher automationCompositionDeployPublisher; private final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher; - private final AcElementPropertiesPublisher acElementPropertiesPublisher; /** @@ -65,7 +65,17 @@ public class SupervisionAcHandler { * @param acDefinition the AutomationCompositionDefinition */ public void deploy(AutomationComposition automationComposition, AutomationCompositionDefinition acDefinition) { - AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYING, LockState.NONE); + if (StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult())) { + automationComposition.setDeployState(DeployState.DEPLOYING); + for (var element : automationComposition.getElements().values()) { + if (!DeployState.DEPLOYED.equals(element.getDeployState())) { + element.setDeployState(DeployState.DEPLOYING); + } + } + } else { + AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYING, LockState.NONE); + } + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); automationCompositionDeployPublisher.send(automationComposition, acDefinition.getServiceTemplate(), startPhase, @@ -79,7 +89,17 @@ public class SupervisionAcHandler { * @param acDefinition the AutomationCompositionDefinition */ public void undeploy(AutomationComposition automationComposition, AutomationCompositionDefinition acDefinition) { - AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYING, LockState.NONE); + if (StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult())) { + automationComposition.setDeployState(DeployState.UNDEPLOYING); + for (var element : automationComposition.getElements().values()) { + if (!DeployState.UNDEPLOYED.equals(element.getDeployState())) { + element.setDeployState(DeployState.UNDEPLOYING); + } + } + } else { + AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYING, LockState.NONE); + } + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); automationCompositionStateChangePublisher.send(automationComposition, startPhase, true); @@ -92,7 +112,17 @@ public class SupervisionAcHandler { * @param acDefinition the AutomationCompositionDefinition */ public void unlock(AutomationComposition automationComposition, AutomationCompositionDefinition acDefinition) { - AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.UNLOCKING); + if (StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult())) { + automationComposition.setLockState(LockState.UNLOCKING); + for (var element : automationComposition.getElements().values()) { + if (!LockState.UNLOCKED.equals(element.getLockState())) { + element.setLockState(LockState.UNLOCKING); + } + } + } else { + AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.UNLOCKING); + } + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); automationCompositionStateChangePublisher.send(automationComposition, startPhase, true); @@ -105,7 +135,17 @@ public class SupervisionAcHandler { * @param acDefinition the AutomationCompositionDefinition */ public void lock(AutomationComposition automationComposition, AutomationCompositionDefinition acDefinition) { - AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.LOCKING); + if (StateChangeResult.FAILED.equals(automationComposition.getStateChangeResult())) { + automationComposition.setLockState(LockState.LOCKING); + for (var element : automationComposition.getElements().values()) { + if (!LockState.LOCKED.equals(element.getLockState())) { + element.setLockState(LockState.LOCKING); + } + } + } else { + AcmUtils.setCascadedState(automationComposition, DeployState.DEPLOYED, LockState.LOCKING); + } + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); automationCompositionStateChangePublisher.send(automationComposition, startPhase, true); @@ -113,10 +153,12 @@ public class SupervisionAcHandler { /** * Handle Element property update on a deployed instance. + * * @param automationComposition the AutomationComposition */ public void update(AutomationComposition automationComposition) { - AcmUtils.setCascadedState(automationComposition, DeployState.UPDATING, LockState.NONE); + AcmUtils.setCascadedState(automationComposition, DeployState.UPDATING, automationComposition.getLockState()); + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); acElementPropertiesPublisher.send(automationComposition); } @@ -128,6 +170,7 @@ public class SupervisionAcHandler { */ public void delete(AutomationComposition automationComposition, AutomationCompositionDefinition acDefinition) { AcmUtils.setCascadedState(automationComposition, DeployState.DELETING, LockState.NONE); + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); automationCompositionProvider.updateAutomationComposition(automationComposition); var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate()); automationCompositionStateChangePublisher.send(automationComposition, startPhase, true); @@ -176,8 +219,11 @@ public class SupervisionAcHandler { || automationCompositionAckMessage.getAutomationCompositionResultMap().isEmpty()) { if (DeployState.DELETING.equals(automationComposition.get().getDeployState())) { // scenario when Automation Composition instance has never been deployed - automationComposition.get().getElements().values() - .forEach(element -> element.setDeployState(DeployState.DELETED)); + for (var element : automationComposition.get().getElements().values()) { + if (element.getParticipantId().equals(automationCompositionAckMessage.getParticipantId())) { + element.setDeployState(DeployState.DELETED); + } + } automationCompositionProvider.updateAutomationComposition(automationComposition.get()); } else { LOGGER.warn("Empty AutomationCompositionResultMap {} {}", @@ -188,26 +234,37 @@ public class SupervisionAcHandler { } var updated = updateState(automationComposition.get(), - automationCompositionAckMessage.getAutomationCompositionResultMap().entrySet()); + automationCompositionAckMessage.getAutomationCompositionResultMap().entrySet(), + automationCompositionAckMessage.getStateChangeResult()); if (updated) { automationCompositionProvider.updateAutomationComposition(automationComposition.get()); } } private boolean updateState(AutomationComposition automationComposition, - Set> automationCompositionResultSet) { + Set> automationCompositionResultSet, + StateChangeResult stateChangeResult) { var updated = false; + var elementInErrors = StateChangeResult.FAILED.equals(stateChangeResult); + boolean inProgress = StateChangeResult.NO_ERROR.equals(automationComposition.getStateChangeResult()); + for (var acElementAck : automationCompositionResultSet) { var element = automationComposition.getElements().get(acElementAck.getKey()); if (element != null) { - element.setDeployState(acElementAck.getValue().getDeployState()); - element.setLockState(acElementAck.getValue().getLockState()); + element.setMessage(acElementAck.getValue().getMessage()); + element.setOutProperties(acElementAck.getValue().getOutProperties()); element.setOperationalState(acElementAck.getValue().getOperationalState()); element.setUseState(acElementAck.getValue().getUseState()); - element.setOutProperties(acElementAck.getValue().getOutProperties()); updated = true; + if (!elementInErrors || inProgress) { + element.setDeployState(acElementAck.getValue().getDeployState()); + element.setLockState(acElementAck.getValue().getLockState()); + } } } + if (elementInErrors && inProgress) { + automationComposition.setStateChangeResult(stateChangeResult.FAILED); + } return updated; } } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java index e23d79d57..803bc86ca 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java @@ -138,6 +138,11 @@ public class SupervisionScanner { LOGGER.debug("automation composition scan: transition from state {} to {} not completed", automationComposition.getDeployState(), automationComposition.getLockState()); + if (DeployState.UPDATING.equals(automationComposition.getDeployState())) { + // UPDATING do not need phases + return; + } + var isForward = AcmUtils.isForward(automationComposition.getDeployState(), automationComposition.getLockState()); 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 e763127cc..6988cd3c4 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 @@ -42,6 +42,7 @@ 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.DeployState; import org.onap.policy.clamp.models.acm.concepts.LockState; +import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeployAck; import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType; import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider; @@ -59,8 +60,7 @@ class SupervisionAcHandlerTest { .thenReturn(Optional.of(automationComposition)); var handler = new SupervisionAcHandler(automationCompositionProvider, - mock(AutomationCompositionDeployPublisher.class), - mock(AutomationCompositionStateChangePublisher.class), + mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), mock(AcElementPropertiesPublisher.class)); var automationCompositionAckMessage = @@ -98,8 +98,7 @@ class SupervisionAcHandlerTest { automationCompositionAckMessage.setAutomationCompositionId(IDENTIFIER); var handler = new SupervisionAcHandler(automationCompositionProvider, - mock(AutomationCompositionDeployPublisher.class), - mock(AutomationCompositionStateChangePublisher.class), + mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), mock(AcElementPropertiesPublisher.class)); handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage); @@ -107,13 +106,66 @@ class SupervisionAcHandlerTest { verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); } + @Test + void testHandleAcUpdateAckFailedMessage() { + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud"); + automationComposition.setDeployState(DeployState.DEPLOYING); + automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR); + when(automationCompositionProvider.findAutomationComposition(IDENTIFIER)) + .thenReturn(Optional.of(automationComposition)); + + var automationCompositionAckMessage = + new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK); + for (var element : automationComposition.getElements().values()) { + element.setDeployState(DeployState.DEPLOYED); + } + var elementEntry = automationComposition.getElements().entrySet().iterator().next(); + elementEntry.getValue().setDeployState(DeployState.DEPLOYING); + var acElementDeployAck = + new AcElementDeployAck(DeployState.UNDEPLOYED, LockState.NONE, "", "", Map.of(), true, "Error"); + automationCompositionAckMessage + .setAutomationCompositionResultMap(Map.of(elementEntry.getKey(), acElementDeployAck)); + + automationCompositionAckMessage.setParticipantId(CommonTestData.getParticipantId()); + automationCompositionAckMessage.setAutomationCompositionId(IDENTIFIER); + + var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); + + var handler = new SupervisionAcHandler(automationCompositionProvider, + mock(AutomationCompositionDeployPublisher.class), automationCompositionStateChangePublisher, null); + + handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage); + + verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); + } + + @Test + void testDeployFailed() { + var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var handler = new SupervisionAcHandler(automationCompositionProvider, automationCompositionDeployPublisher, + mock(AutomationCompositionStateChangePublisher.class), mock(AcElementPropertiesPublisher.class)); + + var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); + var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Deploy"); + automationComposition.setStateChangeResult(StateChangeResult.FAILED); + handler.deploy(automationComposition, acDefinition); + verify(automationCompositionProvider).updateAutomationComposition(automationComposition); + verify(automationCompositionDeployPublisher).send(automationComposition, acDefinition.getServiceTemplate(), 0, + true); + } + @Test void testUndeploy() { var automationCompositionProvider = mock(AutomationCompositionProvider.class); var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var handler = new SupervisionAcHandler(automationCompositionProvider, - mock(AutomationCompositionDeployPublisher.class), - acStateChangePublisher, mock(AcElementPropertiesPublisher.class)); + mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher, + mock(AcElementPropertiesPublisher.class)); var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); var automationComposition = @@ -124,17 +176,56 @@ class SupervisionAcHandlerTest { verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean()); } + @Test + void testUndeployFailed() { + var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var handler = new SupervisionAcHandler(automationCompositionProvider, + mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher, + mock(AcElementPropertiesPublisher.class)); + + var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); + var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "UnDeploy"); + automationComposition.setStateChangeResult(StateChangeResult.FAILED); + automationComposition.getElements().values() + .forEach(element -> element.setDeployState(DeployState.UNDEPLOYING)); + handler.undeploy(automationComposition, acDefinition); + verify(automationCompositionProvider).updateAutomationComposition(automationComposition); + verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean()); + } + @Test void testUnlock() { var automationCompositionProvider = mock(AutomationCompositionProvider.class); var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var handler = new SupervisionAcHandler(automationCompositionProvider, - mock(AutomationCompositionDeployPublisher.class), - acStateChangePublisher, mock(AcElementPropertiesPublisher.class)); + mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher, + mock(AcElementPropertiesPublisher.class)); + var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); + var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "UnLock"); + handler.unlock(automationComposition, acDefinition); + + verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); + verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean()); + } + + @Test + void testUnlockFailed() { + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); + var handler = new SupervisionAcHandler(automationCompositionProvider, + mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher, + mock(AcElementPropertiesPublisher.class)); var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "UnLock"); + automationComposition.setStateChangeResult(StateChangeResult.FAILED); + automationComposition.getElements().values().forEach(element -> element.setLockState(LockState.UNLOCKING)); handler.unlock(automationComposition, acDefinition); verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); @@ -146,15 +237,70 @@ class SupervisionAcHandlerTest { var automationCompositionProvider = mock(AutomationCompositionProvider.class); var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var handler = new SupervisionAcHandler(automationCompositionProvider, - mock(AutomationCompositionDeployPublisher.class), - acStateChangePublisher, mock(AcElementPropertiesPublisher.class)); + mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher, + mock(AcElementPropertiesPublisher.class)); + var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); + var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Lock"); + handler.lock(automationComposition, acDefinition); + + verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); + verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean()); + } + + @Test + void testLockFailed() { + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); + var handler = new SupervisionAcHandler(automationCompositionProvider, + mock(AutomationCompositionDeployPublisher.class), acStateChangePublisher, + mock(AcElementPropertiesPublisher.class)); var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Lock"); + automationComposition.setStateChangeResult(StateChangeResult.FAILED); + automationComposition.getElements().values().forEach(element -> element.setLockState(LockState.LOCKING)); handler.lock(automationComposition, acDefinition); verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); verify(acStateChangePublisher).send(any(AutomationComposition.class), anyInt(), anyBoolean()); } + + @Test + void testDeleteAck() { + var automationCompositionProvider = mock(AutomationCompositionProvider.class); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Crud"); + automationComposition.setDeployState(DeployState.DELETING); + when(automationCompositionProvider.findAutomationComposition(IDENTIFIER)) + .thenReturn(Optional.of(automationComposition)); + + var automationCompositionAckMessage = + new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_DEPLOY_ACK); + automationCompositionAckMessage + .setParticipantId(automationComposition.getElements().values().iterator().next().getParticipantId()); + automationCompositionAckMessage.setAutomationCompositionId(IDENTIFIER); + + var handler = new SupervisionAcHandler(automationCompositionProvider, + mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), + mock(AcElementPropertiesPublisher.class)); + + handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage); + + verify(automationCompositionProvider).updateAutomationComposition(any(AutomationComposition.class)); + } + + @Test + void testUpdate() { + var acElementPropertiesPublisher = mock(AcElementPropertiesPublisher.class); + var handler = new SupervisionAcHandler(mock(AutomationCompositionProvider.class), + mock(AutomationCompositionDeployPublisher.class), mock(AutomationCompositionStateChangePublisher.class), + acElementPropertiesPublisher); + var automationComposition = + InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Lock"); + handler.update(automationComposition); + verify(acElementPropertiesPublisher).send(any(AutomationComposition.class)); + } } -- cgit 1.2.3-korg