aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam Fallon <liam.fallon@est.tech>2023-05-24 07:12:01 +0000
committerGerrit Code Review <gerrit@onap.org>2023-05-24 07:12:01 +0000
commit24d380535b9982f944e96c7532d0914296664869 (patch)
tree399e8836e31297d2d58c2734f0de2f4034dc3615
parente412f387ce7eb0837a009bc23aa15fcd23cffc37 (diff)
parent461bbdb67733552e78037bd96ca7efdfd3015e25 (diff)
Merge "Update AC Element properties on the DEPLOYED state"
-rw-r--r--models/src/main/java/org/onap/policy/clamp/models/acm/concepts/DeployState.java3
-rw-r--r--models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantMessageType.java13
-rw-r--r--models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java61
-rw-r--r--models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java3
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java5
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java49
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java95
-rw-r--r--participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java14
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java65
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java12
-rw-r--r--runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/comm/AcElementPropertiesPublisher.java89
-rw-r--r--runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java16
-rw-r--r--runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandlerTest.java13
13 files changed, 389 insertions, 49 deletions
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/DeployState.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/DeployState.java
index 94aa07097..9dde703b6 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/DeployState.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/DeployState.java
@@ -26,5 +26,6 @@ public enum DeployState {
UNDEPLOYED,
UNDEPLOYING,
DELETING,
- DELETED
+ DELETED,
+ UPDATING
}
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantMessageType.java b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantMessageType.java
index 474bcd36f..e60a13202 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantMessageType.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/ParticipantMessageType.java
@@ -100,5 +100,16 @@ public enum ParticipantMessageType {
/**
* Used by automation composition runtime to request for PARTICIPANT_STATUS message immediately.
*/
- PARTICIPANT_STATUS_REQ
+ PARTICIPANT_STATUS_REQ,
+
+ /**
+ * Used by automation composition runtime to send the element properties update to participant.
+ */
+ PROPERTIES_UPDATE,
+
+ /**
+ * Used by participant to acknowledge the receipt of PROPERTIES_UPDATE message
+ * from automation composition runtime.
+ */
+ PROPERTIES_UPDATE_ACK
}
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java
new file mode 100644
index 000000000..43573cc08
--- /dev/null
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/dmaap/participant/PropertiesUpdate.java
@@ -0,0 +1,61 @@
+/*-
+ * ============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.models.acm.messages.dmaap.participant;
+
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
+import org.onap.policy.models.base.PfUtils;
+
+
+/**
+ * Class to represent the PROPERTIES_UPDATE message that the ACM runtime sends to a participant.
+ * The ACM Runtime sends updated automation composition element property values to Participants.
+ */
+@Getter
+@Setter
+@ToString(callSuper = true)
+public class PropertiesUpdate extends ParticipantMessage {
+
+ // A list of updates to AC element properties
+ private List<ParticipantDeploy> participantUpdatesList = new ArrayList<>();
+
+ /**
+ * Constructor for instantiating properties update class with message name.
+ *
+ */
+ public PropertiesUpdate() {
+ super(ParticipantMessageType.PROPERTIES_UPDATE);
+ }
+
+ /**
+ * Constructs the object, making a deep copy.
+ *
+ * @param source source from which to copy
+ */
+ public PropertiesUpdate(PropertiesUpdate source) {
+ super(source);
+ this.participantUpdatesList = PfUtils.mapList(source.participantUpdatesList, ParticipantDeploy::new);
+ }
+}
diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java
index f4b57f1d1..318b36a19 100644
--- a/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java
+++ b/models/src/main/java/org/onap/policy/clamp/models/acm/messages/rest/instantiation/DeployOrder.java
@@ -24,5 +24,6 @@ public enum DeployOrder {
NONE,
UNDEPLOY,
DEPLOY,
- DELETE
+ DELETE,
+ UPDATE
}
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java
index d6ef80fbe..c8fd91d69 100644
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/api/AutomationCompositionElementListener.java
@@ -62,4 +62,9 @@ public interface AutomationCompositionElementListener {
throws PfModelException {
// default Delete Operation
}
+
+ public default void update(UUID automationCompositionId, AcElementDeploy element, Map<String, Object> properties)
+ throws PfModelException {
+ // default update Operation
+ }
}
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java
new file mode 100644
index 000000000..d6f1970d7
--- /dev/null
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/comm/AcPropertyUpdateListener.java
@@ -0,0 +1,49 @@
+/*-
+ * ============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.participant.intermediary.comm;
+
+import org.onap.policy.clamp.acm.participant.intermediary.handler.ParticipantHandler;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionDeploy;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
+import org.springframework.stereotype.Component;
+
+/**
+ * Listener for AC Element property update messages sent by ACM.
+ */
+@Component
+public class AcPropertyUpdateListener extends ParticipantListener<PropertiesUpdate> {
+
+ /**
+ * Constructs the object.
+ *
+ * @param participantHandler the handler for managing the state of the participant
+ */
+ public AcPropertyUpdateListener(final ParticipantHandler participantHandler) {
+ super(PropertiesUpdate.class, participantHandler,
+ participantHandler::handleAcPropertyUpdate);
+ }
+
+ @Override
+ public String getType() {
+ return ParticipantMessageType.PROPERTIES_UPDATE.name();
+ }
+}
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 d33498518..9087054fe 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
@@ -49,6 +49,7 @@ import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCom
import org.onap.policy.clamp.models.acm.messages.dmaap.participant.AutomationCompositionStateChange;
import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantMessageType;
import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
+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.clamp.models.acm.messages.rest.instantiation.LockOrder;
import org.onap.policy.clamp.models.acm.persistence.provider.AcInstanceStateResolver;
@@ -262,6 +263,33 @@ public class AutomationCompositionHandler {
}
/**
+ * Handle a automation composition properties update message.
+ *
+ * @param updateMsg the properties update message
+ * @param acElementDefinitions the list of AutomationCompositionElementDefinition
+ */
+ public void handleAcPropertyUpdate(PropertiesUpdate updateMsg,
+ List<AutomationCompositionElementDefinition> acElementDefinitions) {
+
+ if (updateMsg.getParticipantUpdatesList().isEmpty()) {
+ LOGGER.warn("No AutomationCompositionElement updates in message {}",
+ updateMsg.getAutomationCompositionId());
+ return;
+ }
+
+ for (var participantDeploy : updateMsg.getParticipantUpdatesList()) {
+ if (participantId.equals(participantDeploy.getParticipantId())) {
+
+ initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
+ participantDeploy, DeployState.UPDATING);
+
+ callParticipantUpdateProperty(participantDeploy.getAcElementList(), acElementDefinitions,
+ updateMsg.getAutomationCompositionId());
+ }
+ }
+ }
+
+ /**
* Handle a automation composition Deploy message.
*
* @param updateMsg the Deploy message
@@ -280,28 +308,34 @@ public class AutomationCompositionHandler {
if (participantId.equals(participantDeploy.getParticipantId())) {
if (updateMsg.isFirstStartPhase()) {
initializeDeploy(updateMsg.getMessageId(), updateMsg.getAutomationCompositionId(),
- participantDeploy);
+ participantDeploy, DeployState.DEPLOYING);
}
- callParticipanDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
+ callParticipantDeploy(participantDeploy.getAcElementList(), acElementDefinitions,
updateMsg.getStartPhase(), updateMsg.getAutomationCompositionId());
}
}
}
- private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy) {
- var automationComposition = new AutomationComposition();
- automationComposition.setInstanceId(instanceId);
- var acElements = storeElementsOnThisParticipant(participantDeploy);
- automationComposition.setElements(prepareAcElementMap(acElements));
- automationCompositionMap.put(instanceId, automationComposition);
+ private void initializeDeploy(UUID messageId, UUID instanceId, ParticipantDeploy participantDeploy,
+ DeployState deployState) {
+ if (automationCompositionMap.containsKey(instanceId)) {
+ updateExistingElementsOnThisParticipant(instanceId, participantDeploy, deployState);
+ } else {
+ var automationComposition = new AutomationComposition();
+ automationComposition.setInstanceId(instanceId);
+ var acElements = storeElementsOnThisParticipant(participantDeploy, deployState);
+ automationComposition.setElements(prepareAcElementMap(acElements));
+ automationCompositionMap.put(instanceId, automationComposition);
+ }
}
- private void callParticipanDeploy(List<AcElementDeploy> acElements,
- List<AutomationCompositionElementDefinition> acElementDefinitions, Integer startPhaseMsg,
- UUID automationCompositionId) {
+ private void callParticipantDeploy(List<AcElementDeploy> acElements,
+ List<AutomationCompositionElementDefinition> acElementDefinitions,
+ Integer startPhaseMsg, UUID automationCompositionId) {
try {
for (var element : acElements) {
- var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions, element.getDefinition());
+ var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
+ element.getDefinition());
if (acElementNodeTemplate != null) {
int startPhase = ParticipantUtils.findStartPhase(acElementNodeTemplate.getProperties());
if (startPhaseMsg.equals(startPhase)) {
@@ -319,6 +353,27 @@ public class AutomationCompositionHandler {
}
+ private void callParticipantUpdateProperty(List<AcElementDeploy> acElements,
+ List<AutomationCompositionElementDefinition> acElementDefinitions,
+ UUID automationCompositionId) {
+ try {
+ for (var element : acElements) {
+ var acElementNodeTemplate = getAcElementNodeTemplate(acElementDefinitions,
+ element.getDefinition());
+ if (acElementNodeTemplate != null) {
+ for (var acElementListener : listeners) {
+ var map = new HashMap<>(acElementNodeTemplate.getProperties());
+ map.putAll(element.getProperties());
+ acElementListener.update(automationCompositionId, element, map);
+ }
+ }
+ }
+ } catch (PfModelException e) {
+ LOGGER.error("Automation composition element update failed for {} {}", automationCompositionId, e);
+ }
+
+ }
+
private ToscaNodeTemplate getAcElementNodeTemplate(
List<AutomationCompositionElementDefinition> acElementDefinitions, ToscaConceptIdentifier acElementDefId) {
@@ -330,20 +385,32 @@ public class AutomationCompositionHandler {
return null;
}
- private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy) {
+ private List<AutomationCompositionElement> storeElementsOnThisParticipant(ParticipantDeploy participantDeploy,
+ DeployState deployState) {
List<AutomationCompositionElement> acElementList = new ArrayList<>();
for (var element : participantDeploy.getAcElementList()) {
var acElement = new AutomationCompositionElement();
acElement.setId(element.getId());
acElement.setParticipantId(participantDeploy.getParticipantId());
acElement.setDefinition(element.getDefinition());
- acElement.setDeployState(DeployState.DEPLOYING);
+ acElement.setDeployState(deployState);
acElement.setLockState(LockState.NONE);
acElementList.add(acElement);
}
return acElementList;
}
+ private void updateExistingElementsOnThisParticipant(
+ UUID instanceId, ParticipantDeploy participantDeploy, DeployState deployState) {
+
+ Map<UUID, AutomationCompositionElement> elementList = automationCompositionMap.get(instanceId).getElements();
+ for (var element : participantDeploy.getAcElementList()) {
+ automationCompositionMap.get(instanceId).getElements().get(element.getId()).getProperties()
+ .putAll(element.getProperties());
+ automationCompositionMap.get(instanceId).getElements().get(element.getId()).setDeployState(deployState);
+ }
+ }
+
private Map<UUID, AutomationCompositionElement> prepareAcElementMap(List<AutomationCompositionElement> acElements) {
Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
for (var element : acElements) {
diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
index 44a988a27..9e1216cec 100644
--- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
+++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/ParticipantHandler.java
@@ -47,6 +47,7 @@ import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRe
import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantRegisterAck;
import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatus;
import org.onap.policy.clamp.models.acm.messages.dmaap.participant.ParticipantStatusReq;
+import org.onap.policy.clamp.models.acm.messages.dmaap.participant.PropertiesUpdate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@@ -121,6 +122,19 @@ public class ParticipantHandler {
}
/**
+ * Handle a automation composition property update message.
+ *
+ * @param propertyUpdateMsg the property update message
+ */
+ @Timed(
+ value = "listener.properties_update",
+ description = "PROPERTIES_UPDATE message received")
+ public void handleAcPropertyUpdate(PropertiesUpdate propertyUpdateMsg) {
+ automationCompositionHandler.handleAcPropertyUpdate(propertyUpdateMsg,
+ acElementDefsMap.get(propertyUpdateMsg.getCompositionId()));
+ }
+
+ /**
* Check if a participant message applies to this participant handler.
*
* @param participantMsg the message to check
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<UUID, AutomationCompositionElement> 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.
*
@@ -109,6 +112,15 @@ 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);
+ acElementPropertiesPublisher.send(automationComposition);
+ }
+
+ /**
* Handle Delete an AutomationComposition instance.
*
* @param automationComposition the AutomationComposition
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<PropertiesUpdate> {
+
+ 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<UUID, List<AcElementDeploy>> 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<ParticipantDeploy> 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
@@ -313,22 +313,6 @@ class AutomationCompositionInstantiationProviderTest {
}
@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);
var acDefinition = CommonTestData.createAcDefinition(serviceTemplate, AcTypeState.COMMISSIONED);
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 =