From 461bbdb67733552e78037bd96ca7efdfd3015e25 Mon Sep 17 00:00:00 2001 From: rameshiyer27 Date: Thu, 18 May 2023 16:47:10 +0100 Subject: Update AC Element properties on the DEPLOYED state User can update the instance property values on DEPLOYED state. The runtime sends PROPERTY_UPDATE event to the participants and the updated values are stored on the runtime database. Participants can implement the update method to perform the required action. Issue-ID: POLICY-4682 Signed-off-by: zrrmmua Change-Id: Ic35fba669b5ffcf2c75d6deaa8c309d58e4026f0 --- ...AutomationCompositionInstantiationProvider.java | 65 +++++++++++++--- .../runtime/supervision/SupervisionAcHandler.java | 12 +++ .../comm/AcElementPropertiesPublisher.java | 89 ++++++++++++++++++++++ ...mationCompositionInstantiationProviderTest.java | 16 ---- .../supervision/SupervisionAcHandlerTest.java | 13 ++-- 5 files changed, 163 insertions(+), 32 deletions(-) create mode 100644 runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java (limited to 'runtime-acm/src') 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 4665fec37..787547860 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,6 +21,8 @@ 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; @@ -29,8 +31,10 @@ 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; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.AcInstanceStateUpdate; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse; import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider; @@ -100,33 +104,72 @@ public class AutomationCompositionInstantiationProvider { */ public InstantiationResponse updateAutomationComposition(UUID compositionId, AutomationComposition automationComposition) { + var response = new InstantiationResponse(); var instanceId = automationComposition.getInstanceId(); var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId); if (!compositionId.equals(acToUpdate.getCompositionId())) { throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId); } - if (!DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) { - throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, - "Not allow to update for state in " + acToUpdate.getDeployState()); + if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) { + acToUpdate.setElements(automationComposition.getElements()); + acToUpdate.setName(automationComposition.getName()); + acToUpdate.setVersion(automationComposition.getVersion()); + acToUpdate.setDescription(automationComposition.getDescription()); + acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom()); + var validationResult = validateAutomationComposition(acToUpdate); + if (!validationResult.isValid()) { + throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, validationResult.getResult()); + } + automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate); + response.setInstanceId(instanceId); + response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier()); + return response; + + } else if (DeployState.DEPLOYED.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()); + } + + /** + * Update deployed AC Element properties. + * + * @param compositionId The UUID of the automation composition definition + * @param automationComposition the automation composition + * @param acToBeUpdated the composition to be updated + * @return the result of the update + */ + public InstantiationResponse updateDeployedAutomationComposition(UUID compositionId, + AutomationComposition automationComposition, + AutomationComposition acToBeUpdated) { + + // Iterate and update the element property values + for (Map.Entry dbAcElement : acToBeUpdated.getElements().entrySet()) { + var elementId = dbAcElement.getKey(); + if (automationComposition.getElements().containsKey(elementId)) { + dbAcElement.getValue().getProperties().putAll(automationComposition.getElements().get(elementId) + .getProperties()); + } } - acToUpdate.setElements(automationComposition.getElements()); - acToUpdate.setName(automationComposition.getName()); - acToUpdate.setVersion(automationComposition.getVersion()); - acToUpdate.setDescription(automationComposition.getDescription()); - acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom()); - var validationResult = validateAutomationComposition(acToUpdate); + // 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()); } - automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate); - + automationComposition = automationCompositionProvider.updateAutomationComposition(acToBeUpdated); var response = new InstantiationResponse(); + var instanceId = automationComposition.getInstanceId(); response.setInstanceId(instanceId); response.setAffectedAutomationComposition(automationComposition.getKey().asIdentifier()); return response; } + /** * Validate AutomationComposition. * 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 654c31194..da3cbc399 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 @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import lombok.AllArgsConstructor; +import org.onap.policy.clamp.acm.runtime.supervision.comm.AcElementPropertiesPublisher; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher; import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck; @@ -55,6 +56,8 @@ public class SupervisionAcHandler { private final AutomationCompositionDeployPublisher automationCompositionDeployPublisher; private final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher; + private final AcElementPropertiesPublisher acElementPropertiesPublisher; + /** * Handle Deploy an AutomationComposition instance. * @@ -108,6 +111,15 @@ public class SupervisionAcHandler { automationCompositionStateChangePublisher.send(automationComposition, startPhase, true); } + /** + * Handle Element property update on a deployed instance. + * @param automationComposition the AutomationComposition + */ + public void update(AutomationComposition automationComposition) { + AcmUtils.setCascadedState(automationComposition, DeployState.UPDATING, LockState.NONE); + acElementPropertiesPublisher.send(automationComposition); + } + /** * Handle Delete an AutomationComposition instance. * diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java new file mode 100644 index 000000000..c5f33ad97 --- /dev/null +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.clamp.acm.runtime.supervision.comm; + +import io.micrometer.core.annotation.Timed; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.UnaryOperator; +import lombok.AllArgsConstructor; +import org.onap.policy.clamp.models.acm.concepts.AcElementDeploy; +import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; +import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy; +import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate; +import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder; +import org.onap.policy.models.base.PfUtils; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +/** + * This class is used to send PropertiesUpdate messages to participants. + */ +@Component +@AllArgsConstructor +public class AcElementPropertiesPublisher extends AbstractParticipantPublisher { + + private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionDeployPublisher.class); + + /** + * Send ACElementPropertiesUpdate to Participant. + * + * @param automationComposition the AutomationComposition + */ + @Timed(value = "publisher.properties_update", + description = "AC Element Properties Update published") + public void send(AutomationComposition automationComposition) { + Map> map = new HashMap<>(); + for (var element : automationComposition.getElements().values()) { + var acElementDeploy = new AcElementDeploy(); + acElementDeploy.setId(element.getId()); + acElementDeploy.setDefinition(new ToscaConceptIdentifier(element.getDefinition())); + acElementDeploy.setOrderedState(DeployOrder.UPDATE); + acElementDeploy.setProperties(PfUtils.mapMap(element.getProperties(), UnaryOperator.identity())); + + map.putIfAbsent(element.getParticipantId(), new ArrayList<>()); + map.get(element.getParticipantId()).add(acElementDeploy); + } + List participantDeploys = new ArrayList<>(); + for (var entry : map.entrySet()) { + var participantDeploy = new ParticipantDeploy(); + participantDeploy.setParticipantId(entry.getKey()); + participantDeploy.setAcElementList(entry.getValue()); + participantDeploys.add(participantDeploy); + } + + var propertiesUpdate = new PropertiesUpdate(); + propertiesUpdate.setCompositionId(automationComposition.getCompositionId()); + propertiesUpdate.setAutomationCompositionId(automationComposition.getInstanceId()); + propertiesUpdate.setMessageId(UUID.randomUUID()); + propertiesUpdate.setTimestamp(Instant.now()); + propertiesUpdate.setParticipantUpdatesList(participantDeploys); + + LOGGER.debug("AC Element properties update sent {}", propertiesUpdate); + super.send(propertiesUpdate); + } +} diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java index faf356c22..54a0c9613 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java @@ -312,22 +312,6 @@ class AutomationCompositionInstantiationProviderTest { + " Commissioned automation composition definition not primed\n"); } - @Test - void testUpdateBadRequest() { - var automationComposition = InstantiationUtils - .getAutomationCompositionFromResource(AC_INSTANTIATION_AC_DEFINITION_NOT_FOUND_JSON, "AcNotFound"); - - var acProvider = mock(AutomationCompositionProvider.class); - automationComposition.setDeployState(DeployState.DEPLOYED); - when(acProvider.getAutomationComposition(automationComposition.getInstanceId())) - .thenReturn(automationComposition); - var provider = new AutomationCompositionInstantiationProvider(acProvider, - mock(AcDefinitionProvider.class), null, null); - - assertThatThrownBy(() -> provider.updateAutomationComposition(automationComposition.getCompositionId(), - automationComposition)).hasMessageMatching("Not allow to update for state in DEPLOYED"); - } - @Test void testCompositionInstanceState() { var acDefinitionProvider = mock(AcDefinitionProvider.class); 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 c61984b01..e763127cc 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 @@ -33,6 +33,7 @@ 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.AcElementPropertiesPublisher; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher; import org.onap.policy.clamp.acm.runtime.util.CommonTestData; @@ -59,7 +60,8 @@ class SupervisionAcHandlerTest { var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AutomationCompositionDeployPublisher.class), - mock(AutomationCompositionStateChangePublisher.class)); + mock(AutomationCompositionStateChangePublisher.class), + mock(AcElementPropertiesPublisher.class)); var automationCompositionAckMessage = new AutomationCompositionDeployAck(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK); @@ -97,7 +99,8 @@ class SupervisionAcHandlerTest { var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AutomationCompositionDeployPublisher.class), - mock(AutomationCompositionStateChangePublisher.class)); + mock(AutomationCompositionStateChangePublisher.class), + mock(AcElementPropertiesPublisher.class)); handler.handleAutomationCompositionUpdateAckMessage(automationCompositionAckMessage); @@ -110,7 +113,7 @@ class SupervisionAcHandlerTest { var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AutomationCompositionDeployPublisher.class), - acStateChangePublisher); + acStateChangePublisher, mock(AcElementPropertiesPublisher.class)); var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); var automationComposition = @@ -127,7 +130,7 @@ class SupervisionAcHandlerTest { var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AutomationCompositionDeployPublisher.class), - acStateChangePublisher); + acStateChangePublisher, mock(AcElementPropertiesPublisher.class)); var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); var automationComposition = @@ -144,7 +147,7 @@ class SupervisionAcHandlerTest { var acStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var handler = new SupervisionAcHandler(automationCompositionProvider, mock(AutomationCompositionDeployPublisher.class), - acStateChangePublisher); + acStateChangePublisher, mock(AcElementPropertiesPublisher.class)); var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.PRIMED); var automationComposition = -- cgit 1.2.3-korg