ToscaServiceTemplate toscaServiceTemplate) {
Set<Integer> minStage = new HashSet<>();
for (var element : automationComposition.getElements().values()) {
- var toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
- .get(element.getDefinition().getName());
- var stage = DeployState.MIGRATING.equals(automationComposition.getDeployState())
- ? ParticipantUtils.findStageSetMigrate(toscaNodeTemplate.getProperties())
- : ParticipantUtils.findStageSetPrepare(toscaNodeTemplate.getProperties());
- minStage.addAll(stage);
+ if (! MigrationState.REMOVED.equals(element.getMigrationState())) {
+ var toscaNodeTemplate = toscaServiceTemplate.getToscaTopologyTemplate().getNodeTemplates()
+ .get(element.getDefinition().getName());
+ var stage = DeployState.MIGRATING.equals(automationComposition.getDeployState())
+ ? ParticipantUtils.findStageSetMigrate(toscaNodeTemplate.getProperties())
+ : ParticipantUtils.findStageSetPrepare(toscaNodeTemplate.getProperties());
+ minStage.addAll(stage);
+ }
+
}
return minStage.stream().min(Integer::compare).orElse(0);
}
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
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.MigrationState;
import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
import org.onap.policy.clamp.models.acm.concepts.ParticipantDefinition;
import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
* @return the result of validation
*/
public static BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
- ToscaServiceTemplate serviceTemplate, String toscaCompositionName) {
+ ToscaServiceTemplate serviceTemplate, String toscaCompositionName, boolean migrateOperation) {
var result = new BeanValidationResult(ENTRY + automationComposition.getName(), automationComposition);
var map = getMapToscaNodeTemplates(serviceTemplate);
.collect(Collectors.toMap(ToscaConceptIdentifier::getName, UnaryOperator.identity()));
// @formatter:on
- if (definitions.size() != automationComposition.getElements().size()) {
+ if (definitions.size() != automationComposition.getElements().size()
+ && !migrateOperation) {
result.setResult(ValidationStatus.INVALID,
- "Elements of the instance not matching with the elements of the composition");
+ "Elements of the instance not matching with the elements of the composition");
}
for (var element : automationComposition.getElements().values()) {
- result.addResult(validateDefinition(definitions, element.getDefinition()));
+ result.addResult(validateDefinition(definitions, element.getDefinition(), element.getMigrationState()));
}
}
}
private static ValidationResult validateDefinition(Map<String, ToscaConceptIdentifier> definitions,
- ToscaConceptIdentifier definition) {
+ ToscaConceptIdentifier definition,
+ MigrationState migrationState) {
var result = new BeanValidationResult(ENTRY + definition.getName(), definition);
var identifier = definitions.get(definition.getName());
- if (identifier == null) {
+ if (identifier == null && MigrationState.DEFAULT.equals(migrationState)) {
result.setResult(ValidationStatus.INVALID, "Not found");
- } else if (!identifier.equals(definition)) {
+ } else if (! definition.equals(identifier) && MigrationState.DEFAULT.equals(migrationState)) {
result.setResult(ValidationStatus.INVALID, "Version not matching");
}
return (result.isClean() ? null : result);
* @param deployOrder the DeployOrder
*/
public static List<ParticipantDeploy> createParticipantDeployList(AutomationComposition automationComposition,
- DeployOrder deployOrder, List<AutomationCompositionElement> removedElements) {
+ DeployOrder deployOrder) {
Map<UUID, List<AcElementDeploy>> map = new HashMap<>();
for (var element : automationComposition.getElements().values()) {
var acElementDeploy = createAcElementDeploy(element, deployOrder);
participantDeploy.setAcElementList(entry.getValue());
participantDeploys.add(participantDeploy);
}
- // Include the participantIds for the removed elements
- for (var element : removedElements) {
- if (map.get(element.getParticipantId()) == null) {
- var participantDeploy = new ParticipantDeploy();
- participantDeploy.setParticipantId(element.getParticipantId());
- participantDeploys.add(participantDeploy);
- map.put(element.getParticipantId(), new ArrayList<>());
- }
-
- }
return participantDeploys;
}
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
import org.onap.policy.clamp.models.acm.concepts.DeployState;
import org.onap.policy.clamp.models.acm.concepts.LockState;
-import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
import org.onap.policy.clamp.models.acm.concepts.SubState;
import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate;
import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder;
var doc = new DocToscaServiceTemplate(CommonTestData.getToscaServiceTemplate(TOSCA_TEMPLATE_YAML));
var automationComposition = CommonTestData.getJsonObject(AC_INSTANTIATION_JSON, AutomationComposition.class);
var result = AcmUtils.validateAutomationComposition(automationComposition, doc.toAuthorative(),
- AUTOMATION_COMPOSITION_NODE_TYPE);
+ AUTOMATION_COMPOSITION_NODE_TYPE, false);
assertTrue(result.isValid());
var element = automationComposition.getElements().values().iterator().next();
automationComposition.getElements().remove(element.getId());
result = AcmUtils.validateAutomationComposition(automationComposition, doc.toAuthorative(),
- AUTOMATION_COMPOSITION_NODE_TYPE);
+ AUTOMATION_COMPOSITION_NODE_TYPE, false);
assertFalse(result.isValid());
assertThat(result.getMessage()).contains("not matching");
}
var automationComposition = getDummyAutomationComposition();
var toscaServiceTemplate = getDummyToscaServiceTemplate();
var result = AcmUtils.validateAutomationComposition(automationComposition,
- toscaServiceTemplate, AUTOMATION_COMPOSITION_NODE_TYPE);
+ toscaServiceTemplate, AUTOMATION_COMPOSITION_NODE_TYPE, false);
assertNotNull(result);
assertFalse(result.isValid());
nodeTemplates.put("org.onap.dcae.acm.DCAEMicroserviceAutomationCompositionParticipant", nodeTemplate);
toscaServiceTemplate.getToscaTopologyTemplate().setNodeTemplates(nodeTemplates);
result = AcmUtils.validateAutomationComposition(automationComposition, toscaServiceTemplate,
- AUTOMATION_COMPOSITION_NODE_TYPE);
+ AUTOMATION_COMPOSITION_NODE_TYPE, false);
assertFalse(result.isValid());
var doc = new DocToscaServiceTemplate(CommonTestData.getToscaServiceTemplate(TOSCA_TEMPLATE_YAML));
result = AcmUtils.validateAutomationComposition(automationComposition, doc.toAuthorative(),
- AUTOMATION_COMPOSITION_NODE_TYPE);
+ AUTOMATION_COMPOSITION_NODE_TYPE, false);
assertFalse(result.isValid());
}
@Test
void testCreateAcElementDeployList() {
var automationComposition = getDummyAutomationComposition();
- var result = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.DEPLOY, List.of());
+ var result = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.DEPLOY);
assertThat(result).hasSameSizeAs(automationComposition.getElements().values());
for (var participantDeploy : result) {
for (var element : participantDeploy.getAcElementList()) {
}
}
- @Test
- void testAcDeployListWithRemovedElements() {
- var removedElement1 = CommonTestData.getJsonObject(
- "src/test/resources/json/AutomationCompositionElementNoOrderedState.json",
- AutomationCompositionElement.class);
- var participantId1 = UUID.randomUUID();
- var participantId2 = UUID.randomUUID();
- assert removedElement1 != null;
- removedElement1.setParticipantId(participantId1);
- var removedElement2 = new AutomationCompositionElement(removedElement1);
- removedElement2.setParticipantId(participantId2);
-
- var automationComposition = getDummyAutomationComposition();
- var result = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.DEPLOY,
- List.of(removedElement1, removedElement2));
- assertThat(result).hasSize(automationComposition.getElements().values().size() + 2);
- var participantIds = result.stream().map(ParticipantDeploy::getParticipantId).toList();
- assertThat(participantIds).containsAll(List.of(participantId1, participantId2));
- }
-
@Test
void testCreateAcElementRestart() {
var element = getDummyAutomationComposition().getElements().values().iterator().next();
DeployState.DELETED, null, StateChangeResult.NO_ERROR, "Migration - Deleted");
} else {
intermediaryApi.updateAutomationCompositionElementState(instanceId, elementId,
- DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Migration - Delete failed!");
+ DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration - Delete failed!");
}
}
simulatorService.getConfig().setMigrateSuccess(false);
simulatorService.deleteInMigration(instanceId, elementId);
verify(intermediaryApi).updateAutomationCompositionElementState(instanceId, elementId,
- DeployState.UNDEPLOYED, null, StateChangeResult.FAILED, "Migration - Delete failed!");
+ DeployState.DEPLOYED, null, StateChangeResult.FAILED, "Migration - Delete failed!");
}
}
private void checkComposition(ParticipantSync participantSyncMsg) {
- // edge case scenario in migration whit remove/add elements,
+ // edge case scenario in migration with remove/add elements,
// when composition or target composition doesn't contain elements from this participant
for (var msg : cacheProvider.getMessagesOnHold().values()) {
if (participantSyncMsg.getCompositionId().equals(msg.getCompositionTargetId())) {
if (migrationMsg.getAutomationCompositionId() == null || migrationMsg.getCompositionTargetId() == null) {
return;
}
-
+ var acTargetDefinition = cacheProvider.getAcElementsDefinitions().get(migrationMsg.getCompositionTargetId());
var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
if (automationComposition == null) {
- LOGGER.debug("Automation composition {} does not use this participant",
+ if (acTargetDefinition == null) {
+ LOGGER.warn("Automation composition {} does not use this participant",
+ migrationMsg.getAutomationCompositionId());
+ return;
+ }
+ } else {
+ LOGGER.info("Migration Precheck invoked on an existing participant for the instance {}",
migrationMsg.getAutomationCompositionId());
- return;
}
- automationComposition.setSubState(SubState.MIGRATION_PRECHECKING);
for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
+ if (automationComposition == null) { // New element with new participant
+ automationComposition = cacheProvider.createAcInstance(migrationMsg.getCompositionId(),
+ migrationMsg.getCompositionTargetId(), migrationMsg.getAutomationCompositionId(),
+ participantDeploy, DeployState.MIGRATING, SubState.MIGRATION_PRECHECKING,
+ migrationMsg.getRevisionIdInstance());
+ LOGGER.info("New participant with new element type added for Migration Precheck");
+ }
callParticipantMigratePrecheck(migrationMsg.getMessageId(), participantDeploy.getAcElementList(),
automationComposition, migrationMsg.getCompositionTargetId());
if (acPrepareMsg.isPreDeploy()) {
for (var participantPrepare : acPrepareMsg.getParticipantList()) {
if (cacheProvider.getParticipantId().equals(participantPrepare.getParticipantId())) {
- cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(),
+ cacheProvider.initializeAutomationComposition(acPrepareMsg.getCompositionId(), null,
acPrepareMsg.getAutomationCompositionId(), participantPrepare, DeployState.UNDEPLOYED,
SubState.PREPARING, acPrepareMsg.getRevisionIdInstance());
callParticipanPrepare(acPrepareMsg.getMessageId(), participantPrepare.getAcElementList(),
package org.onap.policy.clamp.acm.participant.intermediary.handler;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.UUID;
-import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.onap.policy.clamp.acm.participant.intermediary.api.CompositionElementDto;
import org.onap.policy.clamp.acm.participant.intermediary.api.ElementState;
import org.onap.policy.clamp.acm.participant.intermediary.api.InstanceElementDto;
import org.onap.policy.clamp.acm.participant.intermediary.comm.ParticipantMessagePublisher;
+import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.AcDefinition;
import org.onap.policy.clamp.acm.participant.intermediary.handler.cache.CacheProvider;
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.AutomationCompositionElement;
import org.onap.policy.clamp.models.acm.concepts.DeployState;
import org.onap.policy.clamp.models.acm.concepts.LockState;
+import org.onap.policy.clamp.models.acm.concepts.MigrationState;
import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils;
import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
@RequiredArgsConstructor
public class AutomationCompositionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionHandler.class);
+ private static final String AC_NOT_USED = "Automation composition {} does not use this participant";
private final CacheProvider cacheProvider;
private final ParticipantMessagePublisher publisher;
automationCompositionAck.setAutomationCompositionId(stateChangeMsg.getAutomationCompositionId());
publisher.sendAutomationCompositionAck(automationCompositionAck);
} else {
- LOGGER.debug("Automation composition {} does not use this participant",
- stateChangeMsg.getAutomationCompositionId());
+ LOGGER.warn(AC_NOT_USED, stateChangeMsg.getAutomationCompositionId());
}
return;
}
}
}
- private void migrateExistingElementsOnThisParticipant(UUID instanceId, UUID compositionTargetId,
- ParticipantDeploy participantDeploy, int stage) {
- var automationComposition = cacheProvider.getAutomationComposition(instanceId);
- var acElementList = automationComposition.getElements();
+ private void migrateExistingElementsOnThisParticipant(AutomationComposition automationComposition,
+ UUID compositionTargetId, ParticipantDeploy participantDeploy,
+ int stage, boolean newParticipant) {
for (var element : participantDeploy.getAcElementList()) {
+ UUID compIdForCommonProperties = null;
+ if (MigrationState.REMOVED.equals(element.getMigrationState())) {
+ compIdForCommonProperties = automationComposition.getCompositionId();
+ } else {
+ compIdForCommonProperties = compositionTargetId;
+ }
var compositionInProperties =
- cacheProvider.getCommonProperties(compositionTargetId, element.getDefinition());
+ cacheProvider.getCommonProperties(compIdForCommonProperties, element.getDefinition());
var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties);
+ if (MigrationState.REMOVED.equals(element.getMigrationState())) {
+ stageSet = Set.of(0);
+ }
if (stageSet.contains(stage)) {
- var acElement = acElementList.get(element.getId());
- if (acElement == null) {
- var newElement = CacheProvider.createAutomationCompositionElement(element);
- newElement.setParticipantId(participantDeploy.getParticipantId());
- newElement.setDeployState(DeployState.MIGRATING);
- newElement.setLockState(LockState.LOCKED);
- newElement.setStage(stage);
-
- acElementList.put(element.getId(), newElement);
- LOGGER.info("New Ac Element with id {} is added in Migration", element.getId());
- } else {
- AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
- acElement.setDeployState(DeployState.MIGRATING);
- acElement.setStage(stage);
- acElement.setDefinition(element.getDefinition());
- }
+ migrateElement(element, automationComposition, compositionTargetId, stage, newParticipant,
+ participantDeploy);
}
}
- // Check for missing elements and remove them from cache
- var elementsToRemove = findElementsToRemove(participantDeploy.getAcElementList(), acElementList);
- for (var key : elementsToRemove) {
- acElementList.remove(key);
- LOGGER.info("Element with id {} is removed in Migration", key);
+ }
+
+ private void migrateElement(AcElementDeploy element, AutomationComposition automationComposition,
+ UUID compositionTargetId, int stage, boolean newParticipant,
+ ParticipantDeploy participantDeploy) {
+ var acElementList = automationComposition.getElements();
+ automationComposition.setCompositionTargetId(compositionTargetId);
+ automationComposition.setDeployState(DeployState.MIGRATING);
+ var acElement = acElementList.get(element.getId());
+ if (acElement == null) { // NEW element with existing participant
+ var newElement = CacheProvider.createAutomationCompositionElement(element);
+ newElement.setParticipantId(participantDeploy.getParticipantId());
+ newElement.setDeployState(DeployState.MIGRATING);
+ newElement.setLockState(LockState.LOCKED);
+ newElement.setStage(stage);
+ newElement.setMigrationState(MigrationState.NEW);
+
+ acElementList.put(element.getId(), newElement);
+ LOGGER.info("New Ac Element with id {} is added in Migration", element.getId());
+ } else {
+ acElement.setStage(stage);
+ acElement.setMigrationState(element.getMigrationState());
+ if (! newParticipant) { //DEFAULT element
+ AcmUtils.recursiveMerge(acElement.getProperties(), element.getProperties());
+ acElement.setDeployState(DeployState.MIGRATING);
+ acElement.setDefinition(element.getDefinition());
+ }
+ LOGGER.info("Cache updated for the migration of element with id {}", element.getId());
}
+
}
private void updateExistingElementsOnThisParticipant(UUID instanceId, ParticipantDeploy participantDeploy) {
}
}
- private List<UUID> findElementsToRemove(List<AcElementDeploy> acElementDeployList,
- Map<UUID, AutomationCompositionElement> acElementList) {
- var acElementDeploySet = acElementDeployList.stream().map(AcElementDeploy::getId).collect(Collectors.toSet());
- return acElementList.keySet().stream().filter(id -> !acElementDeploySet.contains(id)).toList();
- }
-
/**
* Method to handle when the new state from participant is UNINITIALISED state.
*
*/
private void handleUndeployState(UUID messageId, final AutomationComposition automationComposition,
Integer startPhaseMsg) {
- automationComposition.setCompositionTargetId(null);
automationComposition.setDeployState(DeployState.UNDEPLOYING);
for (var element : automationComposition.getElements().values()) {
- var compositionInProperties = cacheProvider.getCommonProperties(automationComposition.getCompositionId(),
- element.getDefinition());
+ UUID compositionId = null;
+ if (MigrationState.NEW.equals(element.getMigrationState())) {
+ compositionId = automationComposition.getCompositionTargetId();
+ } else {
+ compositionId = automationComposition.getCompositionId();
+ }
+ var compositionInProperties = cacheProvider.getCommonProperties(compositionId, element.getDefinition());
int startPhase = ParticipantUtils.findStartPhase(compositionInProperties);
+ if (MigrationState.NEW.equals(element.getMigrationState())) {
+ // Undeploy newly added element on a Failed Migration
+ startPhase = 0;
+ }
if (startPhaseMsg.equals(startPhase)) {
element.setDeployState(DeployState.UNDEPLOYING);
var compositionElement =
- cacheProvider.createCompositionElementDto(automationComposition.getCompositionId(), element);
+ cacheProvider.createCompositionElementDto(compositionId, element);
var instanceElement = new InstanceElementDto(automationComposition.getInstanceId(), element.getId(),
element.getProperties(), element.getOutProperties());
listener.undeploy(messageId, compositionElement, instanceElement);
*/
public void handleAutomationCompositionMigration(AutomationCompositionMigration migrationMsg) {
var automationComposition = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
+ var acTargetDefinition = cacheProvider.getAcElementsDefinitions().get(migrationMsg.getCompositionTargetId());
+ if (Boolean.FALSE.equals(migrationMsg.getRollback())) {
+ handleMigration(automationComposition, acTargetDefinition, migrationMsg);
+ } else {
+ handleRollback(automationComposition, migrationMsg);
+ }
+ }
+
+ private void handleRollback(AutomationComposition automationComposition,
+ AutomationCompositionMigration migrationMsg) {
+ AutomationComposition acCopy = null;
if (automationComposition == null) {
- LOGGER.debug("Automation composition {} does not use this participant",
- migrationMsg.getAutomationCompositionId());
+ LOGGER.warn(AC_NOT_USED, migrationMsg.getAutomationCompositionId());
return;
+ } else {
+ LOGGER.info("Rollback operation invoked for the instance {}", migrationMsg.getAutomationCompositionId());
+ acCopy = new AutomationComposition(automationComposition);
+ automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
+ automationComposition.setDeployState(DeployState.MIGRATION_REVERTING);
}
- var acCopy = new AutomationComposition(automationComposition);
- automationComposition.setCompositionTargetId(migrationMsg.getCompositionTargetId());
- automationComposition.setDeployState(DeployState.MIGRATING);
for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
+ migrateExistingElementsOnThisParticipant(automationComposition, migrationMsg.getCompositionTargetId(),
+ participantDeploy, migrationMsg.getStage(), false);
- migrateExistingElementsOnThisParticipant(migrationMsg.getAutomationCompositionId(),
- migrationMsg.getCompositionTargetId(), participantDeploy, migrationMsg.getStage());
-
- callParticipantMigrate(migrationMsg.getMessageId(), participantDeploy.getAcElementList(), acCopy,
- migrationMsg.getCompositionTargetId(), migrationMsg.getStage(),
- Boolean.TRUE.equals(migrationMsg.getRollback()));
+ callParticipantMigrate(migrationMsg, participantDeploy.getAcElementList(), acCopy);
}
+
}
}
- private void callParticipantMigrate(UUID messageId, List<AcElementDeploy> acElements, AutomationComposition acCopy,
- UUID compositionTargetId, int stage, boolean rollback) {
- var compositionElementMap = cacheProvider.getCompositionElementDtoMap(acCopy);
- var instanceElementMap = cacheProvider.getInstanceElementDtoMap(acCopy);
- var automationComposition = cacheProvider.getAutomationComposition(acCopy.getInstanceId());
- var compositionElementTargetMap =
- cacheProvider.getCompositionElementDtoMap(automationComposition, compositionTargetId);
- var instanceElementMigrateMap = cacheProvider.getInstanceElementDtoMap(automationComposition);
+ private void handleMigration(AutomationComposition automationComposition, AcDefinition acTargetDefinition,
+ AutomationCompositionMigration migrationMsg) {
+ AutomationComposition acCopy = null;
+ if (automationComposition == null) {
+ if (acTargetDefinition == null) {
+ LOGGER.warn(AC_NOT_USED, migrationMsg.getAutomationCompositionId());
+ return;
+ }
+ } else {
+ LOGGER.info("Migration invoked on an existing participant for the instance {}",
+ migrationMsg.getAutomationCompositionId());
+ acCopy = new AutomationComposition(automationComposition);
+ }
+ var newParticipant = false;
+ for (var participantDeploy : migrationMsg.getParticipantUpdatesList()) {
+ if (cacheProvider.getParticipantId().equals(participantDeploy.getParticipantId())) {
+ if (automationComposition == null) {
+ // New element with new participant added in Migration
+ LOGGER.info("Participant newly added in Migration for the instance {}",
+ migrationMsg.getAutomationCompositionId());
+ newParticipant = true;
+ cacheProvider.initializeAutomationComposition(migrationMsg.getCompositionId(),
+ migrationMsg.getCompositionTargetId(), migrationMsg.getAutomationCompositionId(),
+ participantDeploy, DeployState.MIGRATING, SubState.NONE,
+ migrationMsg.getRevisionIdInstance());
+ automationComposition = cacheProvider
+ .getAutomationComposition(migrationMsg.getAutomationCompositionId());
+ }
+ migrateExistingElementsOnThisParticipant(automationComposition, migrationMsg.getCompositionTargetId(),
+ participantDeploy, migrationMsg.getStage(), newParticipant);
+
+ callParticipantMigrate(migrationMsg, participantDeploy.getAcElementList(), acCopy);
+ }
+ }
+ }
- // Call migrate for newly added and updated elements
+ private void callParticipantMigrate(AutomationCompositionMigration migrationMsg, List<AcElementDeploy> acElements,
+ AutomationComposition formerAcInstance) {
+ var latestAcFromCache = cacheProvider.getAutomationComposition(migrationMsg.getAutomationCompositionId());
+ var instanceElementTargetMap = cacheProvider.getInstanceElementDtoMap(latestAcFromCache);
+ var compositionElementTargetMap = cacheProvider.getCompositionElementDtoMap(latestAcFromCache,
+ migrationMsg.getCompositionTargetId());
+ Map<UUID, CompositionElementDto> compositionElementMap = new HashMap<>();
+ Map<UUID, InstanceElementDto> instanceElementMap = new HashMap<>();
+ if (formerAcInstance != null) { //Existing participant
+ compositionElementMap = cacheProvider.getCompositionElementDtoMap(formerAcInstance);
+ instanceElementMap = cacheProvider.getInstanceElementDtoMap(formerAcInstance);
+ }
+ // Call migrate for new and existing elements
for (var acElement : acElements) {
+ UUID compIdForCommonProperties = null;
+ if (MigrationState.REMOVED.equals(acElement.getMigrationState())) {
+ compIdForCommonProperties = latestAcFromCache.getCompositionId();
+ } else {
+ compIdForCommonProperties = migrationMsg.getCompositionTargetId();
+ }
var compositionInProperties =
- cacheProvider.getCommonProperties(compositionTargetId, acElement.getDefinition());
+ cacheProvider.getCommonProperties(compIdForCommonProperties, acElement.getDefinition());
var stageSet = ParticipantUtils.findStageSetMigrate(compositionInProperties);
- if (stageSet.contains(stage)) {
- if (instanceElementMap.get(acElement.getId()) == null) {
- var compositionElementDto =
- new CompositionElementDto(acCopy.getCompositionId(), acElement.getDefinition(), Map.of(),
- Map.of(), ElementState.NOT_PRESENT);
- var instanceElementDto =
- new InstanceElementDto(acCopy.getInstanceId(), acElement.getId(), Map.of(), Map.of(),
- ElementState.NOT_PRESENT);
+ if (MigrationState.REMOVED.equals(acElement.getMigrationState())) {
+ stageSet = Set.of(0);
+ }
+ var rollback = Boolean.TRUE.equals(migrationMsg.getRollback());
+ if (stageSet.contains(migrationMsg.getStage())) {
+ if (MigrationState.NEW.equals(acElement.getMigrationState())) {
+ var compositionElementDto = new CompositionElementDto(migrationMsg.getCompositionId(),
+ acElement.getDefinition(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
+ var instanceElementDto = new InstanceElementDto(migrationMsg.getAutomationCompositionId(),
+ acElement.getId(), Map.of(), Map.of(), ElementState.NOT_PRESENT);
var compositionElementTargetDto =
CacheProvider.changeStateToNew(compositionElementTargetMap.get(acElement.getId()));
- var instanceElementMigrateDto =
- CacheProvider.changeStateToNew(instanceElementMigrateMap.get(acElement.getId()));
+ var instanceElementTargetDto =
+ CacheProvider.changeStateToNew(instanceElementTargetMap.get(acElement.getId()));
+
+ listenerMigrate(migrationMsg.getMessageId(), compositionElementDto, compositionElementTargetDto,
+ instanceElementDto, instanceElementTargetDto, migrationMsg.getStage(), rollback);
- listenerMigrate(messageId, compositionElementDto, compositionElementTargetDto, instanceElementDto,
- instanceElementMigrateDto, stage, rollback);
- } else {
- listenerMigrate(messageId, compositionElementMap.get(acElement.getId()),
+ } else if (MigrationState.REMOVED.equals(acElement.getMigrationState())) {
+ var compositionDtoTarget = new CompositionElementDto(migrationMsg.getCompositionTargetId(),
+ acElement.getDefinition(), Map.of(), Map.of(), ElementState.REMOVED);
+ var instanceElementDtoTarget = new InstanceElementDto(migrationMsg.getAutomationCompositionId(),
+ acElement.getId(), Map.of(), Map.of(), ElementState.REMOVED);
+ listenerMigrate(migrationMsg.getMessageId(), compositionElementMap.get(acElement.getId()),
+ compositionDtoTarget, instanceElementMap.get(acElement.getId()), instanceElementDtoTarget,
+ migrationMsg.getStage(), rollback);
+
+ } else { // DEFAULT case
+ listenerMigrate(migrationMsg.getMessageId(), compositionElementMap.get(acElement.getId()),
compositionElementTargetMap.get(acElement.getId()),
- instanceElementMap.get(acElement.getId()), instanceElementMigrateMap.get(acElement.getId()),
- stage, rollback);
+ instanceElementMap.get(acElement.getId()), instanceElementTargetMap.get(acElement.getId()),
+ migrationMsg.getStage(), rollback);
}
}
}
- if (stage == 0) {
- // Call migrate for removed elements
- List<UUID> removedElements = findElementsToRemove(acElements, acCopy.getElements());
- for (var elementId : removedElements) {
- var compositionDtoTarget = new CompositionElementDto(compositionTargetId,
- acCopy.getElements().get(elementId).getDefinition(), Map.of(), Map.of(), ElementState.REMOVED);
- var instanceDtoTarget = new InstanceElementDto(acCopy.getInstanceId(), elementId, Map.of(), Map.of(),
- ElementState.REMOVED);
- listenerMigrate(messageId, compositionElementMap.get(elementId), compositionDtoTarget,
- instanceElementMap.get(elementId), instanceDtoTarget, 0, rollback);
- }
- }
}
private void listenerMigrate(UUID messageId, CompositionElementDto compositionElement,
listener.rollback(messageId, compositionElement, compositionElementTarget, instanceElement,
instanceElementMigrate, stage);
} else {
+ LOGGER.info("Invoking migration of element on the participant for {}", instanceElement.elementId());
listener.migrate(messageId, compositionElement, compositionElementTarget, instanceElement,
instanceElementMigrate, stage);
}
message.setCompositionId(null);
message.setRevisionIdComposition(null);
} else {
- LOGGER.debug("Composition {} missing or outdated", message.getCompositionId());
+ LOGGER.info("Composition {} missing or outdated", message.getCompositionId());
result = false;
}
}
message.setCompositionTargetId(null);
message.setRevisionIdCompositionTarget(null);
} else {
- LOGGER.debug("Composition Target {} missing or outdated", message.getCompositionTargetId());
+ LOGGER.info("Composition Target {} missing or outdated", message.getCompositionTargetId());
result = false;
}
}
message.setInstanceId(null);
message.setRevisionIdInstance(null);
} else {
- LOGGER.debug("Instance {} missing or outdated", message.getInstanceId());
+ LOGGER.info("Instance {} missing or outdated", message.getInstanceId());
result = false;
}
}
LOGGER.debug("Ignore ParticipantSync message {}", participantSyncMsg.getMessageId());
return;
}
- LOGGER.debug("ParticipantSync message received for participantId {}", participantSyncMsg.getParticipantId());
acDefinitionHandler.handleParticipantSync(participantSyncMsg);
msgExecutor.check();
}
cleanExecution(instanceElement.elementId(), messageId);
var result = executor.submit(() -> this.deployProcess(compositionElement, instanceElement));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Deploy process successfully started on the participant for {}", instanceElement.elementId());
}
private void deployProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
}
/**
- * Handle an udeploy on a automation composition element.
+ * Handle an undeploy on a automation composition element.
*
* @param messageId the messageId
* @param compositionElement the information of the Automation Composition Definition Element
cleanExecution(instanceElement.elementId(), messageId);
var result = executor.submit(() -> this.undeployProcess(compositionElement, instanceElement));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Undeploy process successfully started on the participant for {}", instanceElement.elementId());
}
private void undeployProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
cleanExecution(instanceElement.elementId(), messageId);
var result = executor.submit(() -> this.deleteProcess(compositionElement, instanceElement));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Delete process successfully started on the participant for {}", instanceElement.elementId());
}
private void deleteProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
var result = executor.submit(() ->
this.updateProcess(compositionElement, instanceElement, instanceElementUpdated));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Update process successfully started on the participant for {}", instanceElement.elementId());
}
private void updateProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement,
cleanExecution(composition.compositionId(), messageId);
var result = executor.submit(() -> this.primeProcess(composition));
executionMap.put(composition.compositionId(), result);
+ LOGGER.info("Priming process successfully started on the participant for {}", composition.compositionId());
}
private void primeProcess(CompositionDto composition) {
listener.prime(composition);
executionMap.remove(composition.compositionId());
} catch (Exception e) {
- LOGGER.error("Composition Defintion prime failed {} {}", composition.compositionId(), e.getMessage());
+ LOGGER.error("Composition Definition prime failed {} {}", composition.compositionId(), e.getMessage());
intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.COMMISSIONED,
- StateChangeResult.FAILED, "Composition Defintion prime failed");
+ StateChangeResult.FAILED, "Composition Definition prime failed");
}
}
cleanExecution(composition.compositionId(), messageId);
var result = executor.submit(() -> this.deprimeProcess(composition));
executionMap.put(composition.compositionId(), result);
+ LOGGER.info("De-priming process successfully started on the participant for {}", composition.compositionId());
}
private void deprimeProcess(CompositionDto composition) {
listener.deprime(composition);
executionMap.remove(composition.compositionId());
} catch (Exception e) {
- LOGGER.error("Composition Defintion deprime failed {} {}", composition.compositionId(), e.getMessage());
+ LOGGER.error("Composition Definition deprime failed {} {}", composition.compositionId(), e.getMessage());
intermediaryApi.updateCompositionState(composition.compositionId(), AcTypeState.PRIMED,
- StateChangeResult.FAILED, "Composition Defintion deprime failed");
+ StateChangeResult.FAILED, "Composition Definition deprime failed");
}
}
this.migrateProcess(compositionElement, compositionElementTarget,
instanceElement, instanceElementMigrate, stage));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Migration process successfully started on the participant for {}", instanceElement.elementId());
}
private void migrateProcess(CompositionElementDto compositionElement,
this.migratePrecheckProcess(compositionElement, compositionElementTarget, instanceElement,
instanceElementMigrate));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Migration Precheck process successfully started on the participant for {}",
+ instanceElement.elementId());
}
private void migratePrecheckProcess(CompositionElementDto compositionElement,
cleanExecution(instanceElement.elementId(), messageId);
var result = executor.submit(() -> this.reviewProcess(compositionElement, instanceElement));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Review process successfully started on the participant for {}", instanceElement.elementId());
}
private void reviewProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement) {
cleanExecution(instanceElement.elementId(), messageId);
var result = executor.submit(() -> this.prepareProcess(compositionElement, instanceElement, stage));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Prepare process successfully started on the participant for {}", instanceElement.elementId());
}
private void prepareProcess(CompositionElementDto compositionElement, InstanceElementDto instanceElement,
this.rollbackProcess(compositionElement, compositionElementRollback, instanceElement,
instanceElementRollback, stage));
executionMap.put(instanceElement.elementId(), result);
+ LOGGER.info("Rollback process successfully started on the participant for {}", instanceElement.elementId());
}
private void rollbackProcess(CompositionElementDto compositionElement,
import org.onap.policy.models.base.PfUtils;
import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class CacheProvider {
+ private static final Logger LOGGER = LoggerFactory.getLogger(CacheProvider.class);
+
@Getter
private final UUID participantId;
acDefinition.getElements().put(acElementDefinition.getAcElementDefinitionId(), acElementDefinition);
}
acElementsDefinitions.put(compositionId, acDefinition);
+ LOGGER.info("Updated cache for the composition id {}", compositionId);
}
public void removeElementDefinition(@NonNull UUID compositionId) {
*/
public void initializeAutomationComposition(@NonNull UUID compositionId, @NonNull UUID instanceId,
ParticipantDeploy participantDeploy, UUID revisionId) {
- initializeAutomationComposition(compositionId, instanceId, participantDeploy,
+ initializeAutomationComposition(compositionId, null, instanceId, participantDeploy,
DeployState.DEPLOYING, SubState.NONE, revisionId);
+
}
/**
* @param subState the SubState
* @param revisionId the identification of the last update
*/
- public void initializeAutomationComposition(@NonNull UUID compositionId, @NonNull UUID instanceId,
+ public void initializeAutomationComposition(@NonNull UUID compositionId, UUID compositionTargetId,
+ @NonNull UUID instanceId,
ParticipantDeploy participantDeploy, DeployState deployState, SubState subState, UUID revisionId) {
- var acLast = automationCompositions.get(instanceId);
- Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
- for (var element : participantDeploy.getAcElementList()) {
- var acElement = createAutomationCompositionElement(element);
- acElement.setParticipantId(getParticipantId());
- acElement.setDeployState(deployState);
- acElement.setSubState(subState);
- var acElementLast = acLast != null ? acLast.getElements().get(element.getId()) : null;
- if (acElementLast != null) {
- acElement.setOutProperties(acElementLast.getOutProperties());
- acElement.setOperationalState(acElementLast.getOperationalState());
- acElement.setUseState(acElementLast.getUseState());
- }
- acElementMap.put(element.getId(), acElement);
- }
- var automationComposition = new AutomationComposition();
- automationComposition.setCompositionId(compositionId);
- automationComposition.setInstanceId(instanceId);
- automationComposition.setElements(acElementMap);
- automationComposition.setDeployState(deployState);
- automationComposition.setSubState(subState);
- automationComposition.setRevisionId(revisionId);
+
+ var automationComposition = createAcInstance(compositionId, compositionTargetId, instanceId, participantDeploy,
+ deployState, subState, revisionId);
+
automationCompositions.put(instanceId, automationComposition);
+ LOGGER.info("Initialized participant cache for the {} operation of the instance {}", deployState, instanceId);
+
}
/**
acElement.setUseState(element.getUseState());
acElement.setProperties(element.getProperties());
acElement.setOutProperties(element.getOutProperties());
+ acElement.setMigrationState(element.getMigrationState());
acElementMap.put(element.getId(), acElement);
}
-
var automationComposition = new AutomationComposition();
automationComposition.setCompositionId(compositionId);
automationComposition.setCompositionTargetId(participantRestartAc.getCompositionTargetId());
automationComposition.setStateChangeResult(participantRestartAc.getStateChangeResult());
automationComposition.setRevisionId(participantRestartAc.getRevisionId());
automationCompositions.put(automationComposition.getInstanceId(), automationComposition);
+ LOGGER.info("Updated participant cache for the instance id {}",
+ participantRestartAc.getAutomationCompositionId());
+ }
+
+ /**
+ * Create an AutomationComposition.
+ * @param compositionId compositionId
+ * @param compositionTargetId compositionTargetId
+ * @param instanceId instanceId
+ * @param participantDeploy participantDeploy
+ * @param deployState deployState
+ * @param subState subState
+ * @param revisionId revisionId
+ * @return AutomationComposition
+ */
+ public AutomationComposition createAcInstance(@NonNull UUID compositionId, UUID compositionTargetId,
+ @NonNull UUID instanceId, ParticipantDeploy participantDeploy,
+ DeployState deployState, SubState subState, UUID revisionId) {
+ var acLast = automationCompositions.get(instanceId);
+ Map<UUID, AutomationCompositionElement> acElementMap = new LinkedHashMap<>();
+ for (var element : participantDeploy.getAcElementList()) {
+ var acElement = createAutomationCompositionElement(element);
+ acElement.setParticipantId(getParticipantId());
+ acElement.setDeployState(deployState);
+ acElement.setSubState(subState);
+ var acElementLast = acLast != null ? acLast.getElements().get(element.getId()) : null;
+ if (acElementLast != null) {
+ acElement.setOutProperties(acElementLast.getOutProperties());
+ acElement.setOperationalState(acElementLast.getOperationalState());
+ acElement.setUseState(acElementLast.getUseState());
+ }
+ acElementMap.put(element.getId(), acElement);
+ }
+ var automationComposition = acLast != null ? acLast : new AutomationComposition();
+ automationComposition.setCompositionId(compositionId);
+ automationComposition.setInstanceId(instanceId);
+ if (acLast != null) {
+ automationComposition.getElements().putAll(acElementMap);
+ } else {
+ automationComposition.setElements(acElementMap);
+ }
+ automationComposition.setDeployState(deployState);
+ automationComposition.setSubState(subState);
+ automationComposition.setRevisionId(revisionId);
+ if (compositionTargetId != null) {
+ automationComposition.setCompositionTargetId(compositionTargetId);
+ }
+
+ return automationComposition;
}
/**
acElement.setProperties(element.getProperties());
acElement.setSubState(SubState.NONE);
acElement.setLockState(LockState.LOCKED);
+ acElement.setMigrationState(element.getMigrationState());
return acElement;
}
var acDefinition = acElementsDefinitions.get(compositionId);
Map<UUID, CompositionElementDto> map = new HashMap<>();
for (var element : automationComposition.getElements().values()) {
- var acDefinitionElement = acDefinition.getElements().get(element.getDefinition());
+ var acDefinitionElement = (acDefinition != null) ? acDefinition.getElements().get(element.getDefinition()) :
+ null;
var compositionElement = (acDefinitionElement != null)
? new CompositionElementDto(compositionId, element.getDefinition(),
acDefinitionElement.getAutomationCompositionElementToscaNodeTemplate().getProperties(),
import org.onap.policy.clamp.acm.participant.intermediary.main.parameters.CommonTestData;
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.AutomationCompositionElement;
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementDefinition;
import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.MigrationState;
import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy;
import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck;
void handleAutomationCompositionMigrationTest() {
var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
automationComposition.setCompositionId(UUID.randomUUID());
- automationComposition.setInstanceId(UUID.randomUUID());
+ var instanceId = UUID.randomUUID();
+ automationComposition.setInstanceId(instanceId);
automationComposition.setCompositionTargetId(UUID.randomUUID());
var definitions =
CommonTestData.createAutomationCompositionElementDefinitionList(automationComposition);
automationComposition.getElements().size(), false);
testMigration(cacheProviderRollback, automationComposition, 0,
automationComposition.getElements().size(), true);
+
+ // New participant with new elements added in Migration
+ cacheProvider.removeAutomationComposition(instanceId);
+ for (var element : automationComposition.getElements().entrySet()) {
+ element.getValue().setMigrationState(MigrationState.NEW);
+ }
+ testMigration(cacheProvider, automationComposition, 0,
+ automationComposition.getElements().size(), false);
}
@Test
var acMigrate = new AutomationComposition(automationComposition);
acMigrate.setCompositionTargetId(UUID.randomUUID());
- // replacing first element with new one
+ // remove element
var element = acMigrate.getElements().values().iterator().next();
- element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.0.0"));
- element.setId(UUID.randomUUID());
+ element.setMigrationState(MigrationState.REMOVED);
+
+ //Add element
+ var newElement = new AutomationCompositionElement(element);
+ newElement.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4"));
+ newElement.setId(UUID.randomUUID());
+ newElement.setMigrationState(MigrationState.NEW);
+
+ acMigrate.getElements().put(newElement.getId(), newElement);
var migrateDefinitions =
CommonTestData.createAutomationCompositionElementDefinitionList(acMigrate);
automationComposition.getInstanceId(), definitions,
acMigrate.getCompositionTargetId(), migrateDefinitions);
- testMigration(cacheProvider, acMigrate, 0, acMigrate.getElements().size() + 1, false);
- testMigration(cacheProviderRollback, acMigrate, 0, acMigrate.getElements().size() + 1, true);
+ testMigration(cacheProvider, acMigrate, 0, acMigrate.getElements().size(), false);
+ testMigration(cacheProviderRollback, acMigrate, 0, acMigrate.getElements().size(), true);
}
+
@Test
void handleAcMigrationStageTest() {
var automationComposition = CommonTestData.getTestAutomationCompositionMap().values().iterator().next();
var acMigrate = new AutomationComposition(automationComposition);
acMigrate.setCompositionTargetId(UUID.randomUUID());
- // replacing first element with new one
+ // remove element
var element = acMigrate.getElements().values().iterator().next();
- element.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4"));
- element.setId(UUID.randomUUID());
+ element.setMigrationState(MigrationState.REMOVED);
+
+ //Add element
+ var newElement = new AutomationCompositionElement(element);
+ newElement.setDefinition(new ToscaConceptIdentifier("policy.clamp.new.element", "1.2.4"));
+ newElement.setId(UUID.randomUUID());
+ newElement.setMigrationState(MigrationState.NEW);
+
+ acMigrate.getElements().put(newElement.getId(), newElement);
+
// replacing definition version
acMigrate.getElements().values().forEach(el -> el.setDefinition(
var messageId = UUID.randomUUID();
threadHandler.prime(messageId, composition);
verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.COMMISSIONED,
- StateChangeResult.FAILED, "Composition Defintion prime failed");
+ StateChangeResult.FAILED, "Composition Definition prime failed");
clearInvocations(listener);
doThrow(new PfModelException(Status.INTERNAL_SERVER_ERROR, "Error")).when(listener).deprime(composition);
threadHandler.deprime(messageId, composition);
verify(intermediaryApi, timeout(TIMEOUT)).updateCompositionState(compositionId, AcTypeState.PRIMED,
- StateChangeResult.FAILED, "Composition Defintion deprime failed");
+ StateChangeResult.FAILED, "Composition Definition deprime failed");
}
}
var deployState = DeployState.DEPLOYED;
var subState = SubState.NONE;
- assertThatThrownBy(() -> cacheProvider.initializeAutomationComposition(null, instanceId, participantDeploy,
- deployState, subState, null)).isInstanceOf(NullPointerException.class);
- assertThatThrownBy(() -> cacheProvider.initializeAutomationComposition(instanceId, null, participantDeploy,
- deployState, subState, null)).isInstanceOf(NullPointerException.class);
+ assertThatThrownBy(() -> cacheProvider.initializeAutomationComposition(null, instanceId, null,
+ participantDeploy, deployState, subState, null)).isInstanceOf(NullPointerException.class);
+ assertThatThrownBy(() -> cacheProvider.initializeAutomationComposition(instanceId, null, null,
+ participantDeploy, deployState, subState, null)).isInstanceOf(NullPointerException.class);
}
@Test
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation.
+ * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
acElement.setId(element.getId());
acElement.setDefinition(element.getDefinition());
acElement.setProperties(element.getProperties());
+ acElement.setMigrationState(element.getMigrationState());
participantDeploy.getAcElementList().add(acElement);
}
return participantDeploy;
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.concepts.MigrationState;
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.concepts.SubState;
var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
AcDefinitionProvider.checkPrimedComposition(acDefinition);
- var validationResult = validateAutomationComposition(automationComposition, acDefinition);
+ var validationResult = validateAutomationComposition(automationComposition, acDefinition, false);
if (!validationResult.isValid()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+ } else {
+ associateParticipantId(automationComposition, acDefinition, null);
}
encryptInstanceProperties(automationComposition, compositionId);
automationComposition = automationCompositionProvider.createAutomationComposition(automationComposition);
public InstantiationResponse updateAutomationComposition(UUID compositionId,
AutomationComposition automationComposition) {
var instanceId = automationComposition.getInstanceId();
- var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
- AutomationCompositionProvider.validateInstanceEndpoint(compositionId, acToUpdate);
+ var acFromDb = automationCompositionProvider.getAutomationComposition(instanceId);
+ AutomationCompositionProvider.validateInstanceEndpoint(compositionId, acFromDb);
var acDefinition = acDefinitionProvider.getAcDefinition(compositionId);
AcDefinitionProvider.checkPrimedComposition(acDefinition);
- if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
+ if (DeployState.UNDEPLOYED.equals(acFromDb.getDeployState())) {
LOGGER.info("Updating undeployed instance with id {}", instanceId);
- acToUpdate.setElements(automationComposition.getElements());
- acToUpdate.setName(automationComposition.getName());
- acToUpdate.setVersion(automationComposition.getVersion());
- acToUpdate.setDescription(automationComposition.getDescription());
- acToUpdate.setDerivedFrom(automationComposition.getDerivedFrom());
- var validationResult = validateAutomationComposition(acToUpdate, acDefinition);
+ acFromDb.setElements(automationComposition.getElements());
+ acFromDb.setName(automationComposition.getName());
+ acFromDb.setVersion(automationComposition.getVersion());
+ acFromDb.setDescription(automationComposition.getDescription());
+ acFromDb.setDerivedFrom(automationComposition.getDerivedFrom());
+ var validationResult = validateAutomationComposition(acFromDb, acDefinition, false);
if (!validationResult.isValid()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+ } else {
+ associateParticipantId(acFromDb, acDefinition, null);
}
- encryptInstanceProperties(acToUpdate, compositionId);
- automationComposition = automationCompositionProvider.updateAutomationComposition(acToUpdate);
+ encryptInstanceProperties(acFromDb, compositionId);
+ automationComposition = automationCompositionProvider.updateAutomationComposition(acFromDb);
return createInstantiationResponse(automationComposition);
}
}
}
var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
- acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
- acToUpdate.getStateChangeResult());
+ acFromDb.getDeployState(), acFromDb.getLockState(), acFromDb.getSubState(),
+ acFromDb.getStateChangeResult());
return switch (result) {
- case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate, acDefinition);
+ case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acFromDb, acDefinition);
- case "MIGRATE" -> migrateAutomationComposition(automationComposition, acToUpdate, acDefinition);
+ case "MIGRATE" -> migrateAutomationComposition(automationComposition, acFromDb, acDefinition);
- case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate, acDefinition);
+ case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acFromDb, acDefinition);
default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
- "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
+ "Not allowed to " + deployOrder + " in the state " + acFromDb.getDeployState());
};
}
AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
}
- var validationResult = validateAutomationComposition(acToBeUpdated, acDefinition);
+ var validationResult = validateAutomationComposition(acToBeUpdated, acDefinition, false);
if (!validationResult.isValid()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+ } else {
+ associateParticipantId(acToBeUpdated, acDefinition, null);
}
updateAcForProperties(acToBeUpdated);
}
private InstantiationResponse migrateAutomationComposition(
- AutomationComposition automationComposition, AutomationComposition acToBeUpdated,
+ AutomationComposition automationComposition, AutomationComposition acFromDb,
AutomationCompositionDefinition acDefinition) {
LOGGER.info("Migrating instance with id {}", automationComposition.getInstanceId());
- if (!DeployState.DEPLOYED.equals(acToBeUpdated.getDeployState())) {
+ if (!DeployState.DEPLOYED.equals(acFromDb.getDeployState())) {
throw new PfModelRuntimeException(Status.BAD_REQUEST,
- "Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
+ "Not allowed to migrate in the state " + acFromDb.getDeployState());
}
// make copy for rollback
- automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
+ automationCompositionProvider.copyAcElementsBeforeUpdate(acFromDb);
var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
// Iterate and update the element property values
- var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated, acDefinitionTarget);
+ updateElementsProperties(automationComposition, acFromDb, acDefinitionTarget, acDefinition);
- updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATING);
+ updateAcForMigration(acFromDb, acDefinitionTarget, DeployState.MIGRATING);
- var acToPublish = new AutomationComposition(acToBeUpdated);
- encryptInstanceProperties(acToBeUpdated, acToBeUpdated.getCompositionTargetId());
+ var acToPublish = new AutomationComposition(acFromDb);
+ encryptInstanceProperties(acFromDb, acFromDb.getCompositionTargetId());
- var ac = automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
- for (var element : elementsRemoved) {
- automationCompositionProvider.deleteAutomationCompositionElement(element.getId());
- }
+ var ac = automationCompositionProvider.updateAutomationComposition(acFromDb);
// Publish migrate event to the participants
- supervisionAcHandler.migrate(acToPublish, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId(),
- elementsRemoved);
+ supervisionAcHandler.migrate(acToPublish, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
return createInstantiationResponse(ac);
}
- private void updateAcForMigration(AutomationComposition acToBeUpdated,
+ private void updateAcForMigration(AutomationComposition acFromDb,
AutomationCompositionDefinition acDefinition, DeployState deployState) {
- AcmUtils.setCascadedState(acToBeUpdated, deployState, LockState.LOCKED);
- acToBeUpdated.setStateChangeResult(StateChangeResult.NO_ERROR);
- var stage = ParticipantUtils.getFirstStage(acToBeUpdated, acDefinition.getServiceTemplate());
- acToBeUpdated.setPhase(stage);
+ AcmUtils.setCascadedState(acFromDb, deployState, LockState.LOCKED);
+ acFromDb.setStateChangeResult(StateChangeResult.NO_ERROR);
+ var stage = ParticipantUtils.getFirstStage(acFromDb, acDefinition.getServiceTemplate());
+ acFromDb.setPhase(stage);
}
private void updateAcForProperties(AutomationComposition acToBeUpdated) {
var acDefinitionTarget = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
AcDefinitionProvider.checkPrimedComposition(acDefinitionTarget);
// Iterate and update the element property values
- var removedElements = updateElementsProperties(automationComposition, copyAc, acDefinitionTarget);
+ updateElementsProperties(automationComposition, copyAc, acDefinitionTarget, acDefinition);
// Publish migrate event to the participants
- supervisionAcHandler.migratePrecheck(copyAc, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId(),
- removedElements);
+ supervisionAcHandler.migratePrecheck(copyAc, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
AcmUtils.setCascadedState(acToBeUpdated, DeployState.DEPLOYED, LockState.LOCKED,
SubState.MIGRATION_PRECHECKING);
* @return the result of validation
*/
private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
- AutomationCompositionDefinition acDefinition) {
+ AutomationCompositionDefinition acDefinition, boolean migrateOperation) {
var result = new BeanValidationResult("AutomationComposition", automationComposition);
participantProvider.checkRegisteredParticipant(acDefinition);
result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
acDefinition.getServiceTemplate(),
- acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
+ acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName(), migrateOperation));
result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
- if (result.isValid()) {
- for (var element : automationComposition.getElements().values()) {
- var name = element.getDefinition().getName();
- var participantId = acDefinition.getElementStateMap().get(name).getParticipantId();
- element.setParticipantId(participantId);
- }
- }
-
return result;
}
public void rollback(UUID compositionId, UUID instanceId) {
LOGGER.info("Rollback automation composition request received for CompositionID: {} and InstanceID: {}",
compositionId, instanceId);
- var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
- AutomationCompositionProvider.validateInstanceEndpoint(compositionId, automationComposition);
+ var acFromDb = automationCompositionProvider.getAutomationComposition(instanceId);
+ AutomationCompositionProvider.validateInstanceEndpoint(compositionId, acFromDb);
if (!DeployOrder.MIGRATION_REVERT.name().equals(acInstanceStateResolver.resolve(
DeployOrder.MIGRATION_REVERT, LockOrder.NONE,
- SubOrder.NONE, automationComposition.getDeployState(), automationComposition.getLockState(),
- automationComposition.getSubState(), automationComposition.getStateChangeResult()))) {
+ SubOrder.NONE, acFromDb.getDeployState(), acFromDb.getLockState(),
+ acFromDb.getSubState(), acFromDb.getStateChangeResult()))) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, "Invalid state for rollback");
}
var automationCompositionToRollback =
automationCompositionProvider.getAutomationCompositionRollback(instanceId);
- var acToBeUpdated = new AutomationComposition(automationComposition);
- acToBeUpdated.setCompositionTargetId(automationCompositionToRollback.getCompositionId());
- acToBeUpdated.setElements(automationCompositionToRollback.getElements().values().stream()
+ var acFromDbCopy = new AutomationComposition(acFromDb);
+ acFromDbCopy.setCompositionTargetId(automationCompositionToRollback.getCompositionId());
+ acFromDbCopy.setElements(automationCompositionToRollback.getElements().values().stream()
.collect(Collectors.toMap(AutomationCompositionElement::getId, AutomationCompositionElement::new)));
- var acDefinitionTarget = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionTargetId());
- var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
+ var acDefinitionTarget = acDefinitionProvider.getAcDefinition(acFromDbCopy.getCompositionTargetId());
+ var validationResult = validateAutomationComposition(acFromDbCopy, acDefinitionTarget, true);
if (!validationResult.isValid()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
}
-
- updateAcForMigration(acToBeUpdated, acDefinitionTarget, DeployState.MIGRATION_REVERTING);
- var elementsRemoved = getElementRemoved(automationComposition, acToBeUpdated);
- automationCompositionProvider.updateAutomationComposition(acToBeUpdated);
- for (var element : elementsRemoved) {
- automationCompositionProvider.deleteAutomationCompositionElement(element.getId());
+ // Include new elements from migration for the participant undeploy
+ for (var element : acFromDb.getElements().values()) {
+ if (MigrationState.NEW.equals(element.getMigrationState())) {
+ acFromDbCopy.getElements().put(element.getId(), element);
+ }
+ if (MigrationState.REMOVED.equals(element.getMigrationState())) {
+ acFromDbCopy.getElements().get(element.getId()).setMigrationState(MigrationState.REMOVED);
+ }
}
- var acDefinition = acDefinitionProvider.getAcDefinition(acToBeUpdated.getCompositionId());
- supervisionAcHandler.migrate(acToBeUpdated, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId(),
- elementsRemoved);
+
+ updateAcForMigration(acFromDbCopy, acDefinitionTarget, DeployState.MIGRATION_REVERTING);
+ automationCompositionProvider.updateAutomationComposition(acFromDbCopy);
+ var acDefinition = acDefinitionProvider.getAcDefinition(acFromDbCopy.getCompositionId());
+ supervisionAcHandler.migrate(acFromDbCopy, acDefinition.getRevisionId(), acDefinitionTarget.getRevisionId());
}
- private List<AutomationCompositionElement> updateElementsProperties(AutomationComposition automationComposition,
- AutomationComposition acToBeUpdated, AutomationCompositionDefinition acDefinitionTarget) {
+ private void updateElementsProperties(AutomationComposition automationComposition,
+ AutomationComposition acFromDb, AutomationCompositionDefinition acDefinitionTarget,
+ AutomationCompositionDefinition acDefinition) {
for (var element : automationComposition.getElements().entrySet()) {
var elementId = element.getKey();
- var dbAcElement = acToBeUpdated.getElements().get(elementId);
- // Add additional elements if present for migration
+ var dbAcElement = acFromDb.getElements().get(elementId);
if (dbAcElement == null) {
LOGGER.info("New Ac element {} added in Migration", elementId);
- acToBeUpdated.getElements().put(elementId, element.getValue());
+ element.getValue().setMigrationState(MigrationState.NEW);
+ acFromDb.getElements().put(elementId, element.getValue());
} else {
AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
var newDefinition = element.getValue().getDefinition().asConceptKey();
dbAcElement.setDefinition(element.getValue().getDefinition());
}
}
- // Remove elements which are not present in the new Ac instance
- var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
- elementsRemoved.forEach(element -> acToBeUpdated.getElements().remove(element.getId()));
+ // Update migrationState for the removed elements
+ var elementsRemoved = getElementRemoved(acFromDb, automationComposition);
+ elementsRemoved.forEach(element -> acFromDb.getElements().get(element.getId())
+ .setMigrationState(MigrationState.REMOVED));
- var validationResult = validateAutomationComposition(acToBeUpdated, acDefinitionTarget);
+ var validationResult = validateAutomationComposition(acFromDb, acDefinitionTarget, true);
if (!validationResult.isValid()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+ } else {
+ associateParticipantId(acFromDb, acDefinitionTarget, acDefinition);
+ }
+ acFromDb.setCompositionTargetId(automationComposition.getCompositionTargetId());
+ }
+
+ private void associateParticipantId(AutomationComposition acFromDb,
+ AutomationCompositionDefinition acDefinitionTarget,
+ AutomationCompositionDefinition oldAcDefinition) {
+ for (var element : acFromDb.getElements().values()) {
+ var name = element.getDefinition().getName();
+ var migrationState = element.getMigrationState();
+ if (MigrationState.REMOVED.equals(migrationState) && oldAcDefinition != null) {
+ var participantId = oldAcDefinition.getElementStateMap().get(name).getParticipantId();
+ element.setParticipantId(participantId);
+ } else {
+ var participantId = acDefinitionTarget.getElementStateMap().get(name).getParticipantId();
+ element.setParticipantId(participantId);
+ }
}
- acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
- return elementsRemoved;
}
private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
import io.opentelemetry.context.Context;
import jakarta.ws.rs.core.Response;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import org.onap.policy.clamp.models.acm.concepts.AcElementDeployAck;
import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
-import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
import org.onap.policy.clamp.models.acm.concepts.DeployState;
import org.onap.policy.clamp.models.acm.concepts.LockState;
import org.onap.policy.clamp.models.acm.concepts.MigrationState;
AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYING, LockState.NONE);
}
automationComposition.setStateChangeResult(StateChangeResult.NO_ERROR);
- automationComposition.setCompositionTargetId(null);
var startPhase = ParticipantUtils.getFirstStartPhase(automationComposition, acDefinition.getServiceTemplate());
automationComposition.setPhase(startPhase);
automationCompositionProvider.updateAutomationComposition(automationComposition);
* @param revisionIdCompositionTarget the last Update from Composition Target
*/
public void migrate(AutomationComposition automationComposition, UUID revisionIdComposition,
- UUID revisionIdCompositionTarget, List<AutomationCompositionElement> removedElements) {
+ UUID revisionIdCompositionTarget) {
executor.execute(() -> {
encryptionUtils.decryptInstanceProperties(automationComposition);
acCompositionMigrationPublisher.send(automationComposition, automationComposition.getPhase(),
- revisionIdComposition, revisionIdCompositionTarget, removedElements);
+ revisionIdComposition, revisionIdCompositionTarget);
});
}
* @param revisionIdCompositionTarget the last Update from Composition Target
*/
public void migratePrecheck(AutomationComposition automationComposition, UUID revisionIdComposition,
- UUID revisionIdCompositionTarget, List<AutomationCompositionElement> removedElements) {
+ UUID revisionIdCompositionTarget) {
executor.execute(() -> acCompositionMigrationPublisher.send(automationComposition, 0,
- revisionIdComposition, revisionIdCompositionTarget, removedElements));
+ revisionIdComposition, revisionIdCompositionTarget));
}
}
import io.micrometer.core.annotation.Timed;
import java.time.Instant;
-import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
propertiesUpdate.setTimestamp(Instant.now());
propertiesUpdate.setRevisionIdInstance(automationComposition.getRevisionId());
propertiesUpdate.setRevisionIdComposition(revisionIdComposition);
- var participantUpdatesList = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.UPDATE,
- List.of());
+ var participantUpdatesList = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.UPDATE);
propertiesUpdate.setParticipantUpdatesList(participantUpdatesList);
propertiesUpdate.setParticipantIdList(participantUpdatesList.stream()
.map(ParticipantDeploy::getParticipantId).collect(Collectors.toSet()));
import io.micrometer.core.annotation.Timed;
import java.time.Instant;
-import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
var acPrepare = createAutomationCompositionPrepare(automationComposition.getCompositionId(),
automationComposition.getInstanceId());
acPrepare.setStage(stage);
- var participantUpdatesList = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.NONE,
- List.of());
+ var participantUpdatesList = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.NONE);
acPrepare.setParticipantList(participantUpdatesList);
acPrepare.setParticipantIdList(participantUpdatesList.stream()
.map(ParticipantDeploy::getParticipantId).collect(Collectors.toSet()));
package org.onap.policy.clamp.acm.runtime.supervision.comm;
import io.micrometer.core.annotation.Timed;
-import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
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.DeployState;
import org.onap.policy.clamp.models.acm.concepts.ParticipantDeploy;
import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration;
value = "publisher.automation_composition_migration",
description = "AUTOMATION_COMPOSITION_MIGRATION messages published")
public void send(AutomationComposition automationComposition, int stage, UUID revisionIdComposition,
- UUID revisionIdCompositionTarget, List<AutomationCompositionElement> removedElements) {
+ UUID revisionIdCompositionTarget) {
var acMigration = new AutomationCompositionMigration();
acMigration.setRollback(DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState()));
acMigration.setPrecheck(Boolean.TRUE.equals(automationComposition.getPrecheck()));
acMigration.setRevisionIdInstance(automationComposition.getRevisionId());
acMigration.setRevisionIdComposition(revisionIdComposition);
acMigration.setRevisionIdCompositionTarget(revisionIdCompositionTarget);
- var participantUpdatesList = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.MIGRATE,
- removedElements);
+ var participantUpdatesList = AcmUtils.createParticipantDeployList(automationComposition, DeployOrder.MIGRATE);
acMigration.setParticipantUpdatesList(participantUpdatesList);
acMigration.setParticipantIdList(participantUpdatesList.stream()
.map(ParticipantDeploy::getParticipantId).collect(Collectors.toSet()));
import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublisher;
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.MigrationState;
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.concepts.SubState;
// migration scenario
automationComposition.setCompositionId(automationComposition.getCompositionTargetId());
automationComposition.setCompositionTargetId(null);
+
+ for (var acElement : automationComposition.getElements().values()) {
+ if (MigrationState.NEW.equals(acElement.getMigrationState())) {
+ acElement.setMigrationState(MigrationState.DEFAULT);
+ }
+ }
}
automationComposition.setDeployState(AcmUtils.deployCompleted(deployState));
automationComposition.setLockState(AcmUtils.lockCompleted(deployState, automationComposition.getLockState()));
private UpdateSync handleAcStateChange(AutomationComposition automationComposition, DocMessage message) {
var result = new UpdateSync();
var element = automationComposition.getElements().get(message.getInstanceElementId());
- if (element == null && isMigration(automationComposition)
- && StateChangeResult.FAILED.equals(message.getStateChangeResult())) {
- // fail delete element during migration
- automationComposition.setStateChangeResult(StateChangeResult.FAILED);
- result.setUpdated(true);
- result.setToBeSync(true);
- return result;
- }
- if (element == null || !validateStateMessage(automationComposition, message)) {
+ if (element == null) {
+ LOGGER.warn("Not a valid message, element is null for the element id {}", message.getInstanceElementId());
return result;
}
result.setUpdated(true);
return result;
}
- private boolean isMigration(AutomationComposition automationComposition) {
- return DeployState.MIGRATING.equals(automationComposition.getDeployState())
- || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState());
- }
-
- private boolean validateStateMessage(AutomationComposition automationComposition, DocMessage message) {
- return !DeployState.DELETED.equals(message.getDeployState())
- || (DeployState.DELETING.equals(automationComposition.getDeployState()));
- }
-
private UpdateSync handleOutProperties(AutomationComposition automationComposition, DocMessage message) {
var element = automationComposition.getElements().get(message.getInstanceElementId());
var result = new UpdateSync();
package org.onap.policy.clamp.acm.runtime.supervision.scanner;
+import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.UUID;
import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup;
import org.onap.policy.clamp.acm.runtime.main.utils.EncryptionUtils;
import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublisher;
import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition;
+import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElement;
import org.onap.policy.clamp.models.acm.concepts.DeployState;
+import org.onap.policy.clamp.models.acm.concepts.MigrationState;
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.concepts.SubState;
import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider;
import org.onap.policy.clamp.models.acm.utils.AcmUtils;
AutomationCompositionDefinition acDefinition, UpdateSync updateSync, UUID revisionIdComposition) {
var completed = true;
var minStageNotCompleted = 1000; // min stage not completed
+ List<UUID> elementsDeleted = new ArrayList<>();
for (var element : automationComposition.getElements().values()) {
if (AcmUtils.isInTransitionalState(element.getDeployState(), element.getLockState(),
element.getSubState())) {
- var toscaNodeTemplate = acDefinition.getServiceTemplate().getToscaTopologyTemplate().getNodeTemplates()
- .get(element.getDefinition().getName());
- var stageSet = DeployState.MIGRATING.equals(automationComposition.getDeployState())
- || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState())
- ? ParticipantUtils.findStageSetMigrate(toscaNodeTemplate.getProperties())
- : ParticipantUtils.findStageSetPrepare(toscaNodeTemplate.getProperties());
- var minStage = stageSet.stream().min(Comparator.comparing(Integer::valueOf)).orElse(0);
+ var minStage = calculateMinStage(element, automationComposition, acDefinition);
int stage = element.getStage() != null ? element.getStage() : minStage;
minStageNotCompleted = Math.min(minStageNotCompleted, stage);
completed = false;
+ } else if (DeployState.DELETED.equals(element.getDeployState())
+ && automationComposition.getStateChangeResult().equals(StateChangeResult.NO_ERROR)) {
+ // Migration with successful removal of element
+ elementsDeleted.add(element.getId());
}
}
-
+ removeDeletedElements(automationComposition, elementsDeleted, updateSync);
if (completed) {
complete(automationComposition, updateSync);
} else {
- LOGGER.debug("automation composition scan: transition from state {} to {} not completed",
- automationComposition.getDeployState(), automationComposition.getLockState());
+ processNextStage(automationComposition, updateSync, minStageNotCompleted, revisionIdComposition,
+ acDefinition);
+ }
+ }
- if (minStageNotCompleted != automationComposition.getPhase()) {
- savePhase(automationComposition, minStageNotCompleted);
- updateSync.setUpdated(true);
- saveAndSync(automationComposition, updateSync);
- LOGGER.debug("retry message AutomationCompositionMigration");
- var acToSend = new AutomationComposition(automationComposition);
- decryptInstanceProperties(acToSend);
- sendNextStage(acToSend, minStageNotCompleted, revisionIdComposition, acDefinition);
- } else {
- handleTimeout(automationComposition, updateSync);
- }
+ private void processNextStage(AutomationComposition automationComposition, UpdateSync updateSync,
+ int minStageNotCompleted, UUID revisionIdComposition,
+ AutomationCompositionDefinition acDefinition) {
+ LOGGER.debug("automation composition scan: transition from state {} to {} not completed",
+ automationComposition.getDeployState(), automationComposition.getLockState());
+
+ if (minStageNotCompleted != automationComposition.getPhase()) {
+ savePhase(automationComposition, minStageNotCompleted);
+ updateSync.setUpdated(true);
+ saveAndSync(automationComposition, updateSync);
+ LOGGER.debug("retry message AutomationCompositionMigration");
+ var acToSend = new AutomationComposition(automationComposition);
+ decryptInstanceProperties(acToSend);
+ sendNextStage(acToSend, minStageNotCompleted, revisionIdComposition, acDefinition);
+ } else {
+ handleTimeout(automationComposition, updateSync);
+ }
+ }
+
+ private Integer calculateMinStage(AutomationCompositionElement element, AutomationComposition automationComposition,
+ AutomationCompositionDefinition acDefinition) {
+ Set<Integer> stageSet = new HashSet<>();
+ if (! MigrationState.REMOVED.equals(element.getMigrationState())) {
+ var toscaNodeTemplate = acDefinition.getServiceTemplate().getToscaTopologyTemplate().getNodeTemplates()
+ .get(element.getDefinition().getName());
+ stageSet = DeployState.MIGRATING.equals(automationComposition.getDeployState())
+ || DeployState.MIGRATION_REVERTING.equals(automationComposition.getDeployState())
+ ? ParticipantUtils.findStageSetMigrate(toscaNodeTemplate.getProperties())
+ : ParticipantUtils.findStageSetPrepare(toscaNodeTemplate.getProperties());
+ }
+ return stageSet.stream().min(Comparator.comparing(Integer::valueOf)).orElse(0);
+ }
+
+ private void removeDeletedElements(AutomationComposition automationComposition, List<UUID> elementsDeleted,
+ UpdateSync updateSync) {
+ for (var elementId : elementsDeleted) {
+ LOGGER.info("Deleting element {} in Migration ", elementId);
+ automationComposition.getElements().remove(elementId);
+ acProvider.deleteAutomationCompositionElement(elementId);
+ updateSync.setUpdated(true);
}
}
LOGGER.debug("retry message AutomationCompositionMigration");
// acDefinition for migration is the Composition target
acMigrationPublisher.send(automationComposition, minStageNotCompleted, revisionIdComposition,
- acDefinition.getRevisionId(), List.of());
+ acDefinition.getRevisionId());
}
if (SubState.PREPARING.equals(automationComposition.getSubState())) {
LOGGER.debug("retry message AutomationCompositionPrepare");
automationCompositionTarget.setPrecheck(true);
var preCheckResponse = instantiationProvider.updateAutomationComposition(compositionId,
automationCompositionTarget);
- verify(supervisionAcHandler).migratePrecheck(any(), any(), any(), any());
+ verify(supervisionAcHandler).migratePrecheck(any(), any(), any());
InstantiationUtils.assertInstantiationResponse(preCheckResponse, automationCompositionTarget);
automationCompositionTarget.setPrecheck(false);
var instantiationResponse = instantiationProvider.updateAutomationComposition(compositionId,
automationCompositionTarget);
- verify(supervisionAcHandler).migrate(any(), any(), any(), any());
+ verify(supervisionAcHandler).migrate(any(), any(), any());
InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationCompositionTarget);
}
var instantiationResponse = instantiationProvider
.updateAutomationComposition(automationComposition.getCompositionId(), automationComposition);
- verify(supervisionAcHandler).migrate(any(), any(), any(), any());
+ verify(supervisionAcHandler).migrate(any(), any(), any());
verify(acProvider).updateAutomationComposition(automationComposition);
InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationComposition);
}
var instantiationResponse = instantiationProvider
.updateAutomationComposition(automationComposition.getCompositionId(), automationComposition);
- verify(supervisionAcHandler).migratePrecheck(any(), any(), any(), any());
+ verify(supervisionAcHandler).migratePrecheck(any(), any(), any());
verify(acProvider).updateAutomationComposition(automationComposition);
InstantiationUtils.assertInstantiationResponse(instantiationResponse, automationComposition);
/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation.
+ * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
-import java.util.ArrayList;
-import java.util.UUID;
import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
import org.onap.policy.common.utils.coder.Coder;
// add suffix to name
automationComposition.setName(automationComposition.getName() + suffix);
- var elements = new ArrayList<>(automationComposition.getElements().values());
- automationComposition.getElements().clear();
- for (var element : elements) {
- // set unique UUID to the element
- element.setId(UUID.randomUUID());
- automationComposition.getElements().put(element.getId(), element);
- }
return automationComposition;
} catch (CoderException e) {
fail("Cannot read or decode " + path);
import static org.mockito.Mockito.when;
import static org.onap.policy.clamp.acm.runtime.util.CommonTestData.TOSCA_SERVICE_TEMPLATE_YAML;
-import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
assert automationComposition != null;
automationComposition.setPhase(0);
- handler.migrate(automationComposition, UUID.randomUUID(), UUID.randomUUID(), List.of());
+ handler.migrate(automationComposition, UUID.randomUUID(), UUID.randomUUID());
verify(acCompositionMigrationPublisher, timeout(1000))
- .send(any(AutomationComposition.class), anyInt(), any(UUID.class), any(UUID.class), any());
+ .send(any(AutomationComposition.class), anyInt(), any(UUID.class), any(UUID.class));
}
@Test
mock(AcPreparePublisher.class), mock(MessageProvider.class), mock(EncryptionUtils.class));
var automationComposition =
InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_CREATE_JSON, "Migrate");
- handler.migratePrecheck(automationComposition, UUID.randomUUID(), UUID.randomUUID(), List.of());
+ handler.migratePrecheck(automationComposition, UUID.randomUUID(), UUID.randomUUID());
verify(acCompositionMigrationPublisher, timeout(1000))
- .send(any(AutomationComposition.class), anyInt(), any(UUID.class), any(UUID.class), any());
+ .send(any(AutomationComposition.class), anyInt(), any(UUID.class), any(UUID.class));
}
@Test
package org.onap.policy.clamp.acm.runtime.supervision;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.onap.policy.clamp.acm.runtime.util.CommonTestData.TOSCA_SERVICE_TEMPLATE_YAML;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
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.main.utils.EncryptionUtils;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AcPreparePublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionMigrationPublisher;
+import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublisher;
import org.onap.policy.clamp.acm.runtime.supervision.scanner.AcDefinitionScanner;
import org.onap.policy.clamp.acm.runtime.supervision.scanner.MonitoringScanner;
import org.onap.policy.clamp.acm.runtime.supervision.scanner.PhaseScanner;
import org.onap.policy.clamp.acm.runtime.supervision.scanner.SimpleScanner;
import org.onap.policy.clamp.acm.runtime.supervision.scanner.StageScanner;
import org.onap.policy.clamp.acm.runtime.supervision.scanner.UpdateSync;
+import org.onap.policy.clamp.acm.runtime.util.CommonTestData;
import org.onap.policy.clamp.models.acm.concepts.AcTypeState;
import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
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.MigrationState;
import org.onap.policy.clamp.models.acm.concepts.NodeTemplateState;
import org.onap.policy.clamp.models.acm.concepts.StateChangeResult;
import org.onap.policy.clamp.models.acm.concepts.SubState;
verify(messageProvider).removeJob(JOB_ID);
}
+ @Test
+ void testAcInstanceForMigrationSuccess() {
+ var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud");
+ automationComposition.setDeployState(DeployState.MIGRATING);
+ automationComposition.setInstanceId(INSTANCE_ID);
+ automationComposition.setCompositionId(COMPOSITION_ID);
+ var compositionTargetId = UUID.randomUUID();
+ automationComposition.setCompositionTargetId(compositionTargetId);
+ automationComposition.setLockState(LockState.LOCKED);
+ automationComposition.setLastMsg(TimestampHelper.now());
+ automationComposition.setPhase(0);
+ List<UUID> elementIds = new ArrayList<>(automationComposition.getElements().keySet());
+
+ Map<UUID, MigrationState> migrationStateMap = new HashMap<>();
+ List<MigrationState> states = List.of(MigrationState.REMOVED, MigrationState.NEW, MigrationState.DEFAULT);
+
+ for (int i = 0; i < elementIds.size(); i++) {
+ migrationStateMap.put(elementIds.get(i), states.get(i));
+ }
+
+ for (var entry : automationComposition.getElements().entrySet()) {
+ entry.getValue().setMigrationState(migrationStateMap.get(entry.getKey()));
+ }
+
+ for (var element : automationComposition.getElements().values()) {
+ if (MigrationState.REMOVED.equals(migrationStateMap.get(element.getId()))) {
+ element.setDeployState(DeployState.DELETED);
+ element.setLockState(LockState.LOCKED);
+ } else {
+ element.setDeployState(DeployState.DEPLOYED);
+ element.setLockState(LockState.LOCKED);
+ }
+ }
+
+ var automationCompositionProvider = mock(AutomationCompositionProvider.class);
+ Set<UUID> set = new HashSet<>();
+ set.add(automationComposition.getInstanceId());
+ when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(set);
+ when(automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId()))
+ .thenReturn(Optional.of(automationComposition));
+
+ var acDefinitionTarget = createAutomationCompositionDefinition(AcTypeState.PRIMED);
+ acDefinitionTarget.setCompositionId(compositionTargetId);
+ var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMED);
+ when(acDefinitionProvider.getAcDefinition(compositionTargetId)).thenReturn(acDefinitionTarget);
+ var acDefinition = new AutomationCompositionDefinition();
+ acDefinition.setCompositionId(COMPOSITION_ID);
+ when(acDefinitionProvider.getAcDefinition(COMPOSITION_ID)).thenReturn(acDefinition);
+ var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner");
+ var stageScanner = new StageScanner(automationCompositionProvider, mock(ParticipantSyncPublisher.class),
+ mock(AutomationCompositionMigrationPublisher.class), mock(AcPreparePublisher.class),
+ acRuntimeParameterGroup, mock(EncryptionUtils.class));
+
+ var messageProvider = mock(MessageProvider.class);
+ when(messageProvider.createJob(automationComposition.getInstanceId())).thenReturn(Optional.of(JOB_ID));
+ var monitoringScanner = new MonitoringScanner(automationCompositionProvider, acDefinitionProvider,
+ mock(AcDefinitionScanner.class), stageScanner, mock(SimpleScanner.class), mock(PhaseScanner.class),
+ messageProvider);
+ var supervisionScanner = new SupervisionScanner(automationCompositionProvider, acDefinitionProvider,
+ messageProvider, monitoringScanner);
+
+ supervisionScanner.run();
+ assertEquals(2, automationComposition.getElements().size());
+ assertEquals(DeployState.DEPLOYED, automationComposition.getDeployState());
+ for (var entry : automationComposition.getElements().entrySet()) {
+ assertEquals(MigrationState.DEFAULT, entry.getValue().getMigrationState());
+ }
+ verify(messageProvider).removeJob(JOB_ID);
+ }
+
@Test
void testAcDefinitionJobExist() {
var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMING);
publisher.active(topicSink);
var automationComposition =
InstantiationUtils.getAutomationCompositionFromResource(AC_INSTANTIATION_UPDATE_JSON, "Crud");
- publisher.send(automationComposition, 0, UUID.randomUUID(), UUID.randomUUID(), List.of());
+ publisher.send(automationComposition, 0, UUID.randomUUID(), UUID.randomUUID());
verify(topicSink).send(anyString());
}
assertFalse(result.isUpdated());
assertFalse(result.isToBeSync());
- // wrong Delete State
+ // Delete response from participant
docMessage.setMessageType(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
docMessage.setInstanceElementId(elementId);
docMessage.setDeployState(DeployState.DELETED);
result = simpleScanner.scanMessage(automationComposition, docMessage);
- assertFalse(result.isUpdated());
+ assertTrue(result.isUpdated());
assertFalse(result.isToBeSync());
}
@Test
void testScanMessageMigrationFail() {
var automationComposition = createAutomationComposition(DeployState.MIGRATING, LockState.LOCKED);
- var elementId = UUID.randomUUID();
+ var elementId = automationComposition.getElements().entrySet().iterator().next().getKey();
var docMessage = new DocMessage();
docMessage.setMessageType(ParticipantMessageType.AUTOMATION_COMPOSITION_STATECHANGE_ACK);
docMessage.setStateChangeResult(StateChangeResult.FAILED);