/*-
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2024 Nordix Foundation.
+ * Copyright (C) 2022-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.
private Map<String, NodeTemplateState> elementStateMap = new HashMap<>();
/**
- * Copy contructor, does a deep copy.
+ * Copy constructor, does a deep copy.
*
* @param otherAcmDefinition the other element to copy from
*/
import lombok.Data;\r
import lombok.NoArgsConstructor;\r
import lombok.NonNull;\r
-import lombok.ToString;\r
import org.onap.policy.models.base.PfUtils;\r
\r
@NoArgsConstructor\r
this.compositionId = otherAcmRollback.compositionId;\r
this.elements = PfUtils.mapMap(otherAcmRollback.elements, UnaryOperator.identity());\r
}\r
+\r
+ /**\r
+ * Create a copy from an automation composition.\r
+ *\r
+ * @param automationComposition the composition being migrated that needs a copy\r
+ */\r
+ public AutomationCompositionRollback(final AutomationComposition automationComposition) {\r
+ this.instanceId = automationComposition.getInstanceId();\r
+ this.compositionId = automationComposition.getCompositionId();\r
+ var originalElements = automationComposition.getElements();\r
+\r
+ this.elements = new LinkedHashMap<>();\r
+ originalElements.forEach((uuid, element) ->\r
+ this.elements.put(uuid.toString(), element));\r
+ }\r
}\r
import org.onap.policy.models.base.Validated;
/**
- * Class to represent a automation composition definition in the database.
+ * Class to represent an automation composition definition in the database.
*/
@Entity
@Table(name = "AutomationCompositionDefinition")
import lombok.NonNull;
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.AutomationCompositionRollback;
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.SubState;
import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
+import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
+import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
import org.onap.policy.clamp.models.acm.utils.AcmUtils;
import org.onap.policy.common.parameters.BeanValidationResult;
import org.onap.policy.common.parameters.ValidationStatus;
private final AutomationCompositionRepository automationCompositionRepository;
private final AutomationCompositionElementRepository acElementRepository;
+ private final AutomationCompositionRollbackRepository acRollbackRepository;
/**
* Get automation composition.
*/
@Transactional(readOnly = true)
public Optional<AutomationComposition> findAutomationComposition(
- final ToscaConceptIdentifier automationCompositionId) {
+ final ToscaConceptIdentifier automationCompositionId) {
return automationCompositionRepository
- .findOne(createExample(null, automationCompositionId.getName(), automationCompositionId.getVersion()))
- .map(JpaAutomationComposition::toAuthorative);
+ .findOne(createExample(null, automationCompositionId.getName(), automationCompositionId.getVersion()))
+ .map(JpaAutomationComposition::toAuthorative);
}
/**
* Create automation composition.
*
* @param automationComposition the automation composition to create
- * @return the create automation composition
+ * @return the created automation composition
*/
public AutomationComposition createAutomationComposition(final AutomationComposition automationComposition) {
automationComposition.setInstanceId(UUID.randomUUID());
AcmUtils.setCascadedState(automationComposition, DeployState.UNDEPLOYED, LockState.NONE);
var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
- JpaAutomationComposition::new, "automation composition"));
+ JpaAutomationComposition::new, "automation composition"));
// Return the saved automation composition
return result.toAuthorative();
* @return the updated automation composition
*/
public AutomationComposition updateAutomationComposition(
- @NonNull final AutomationComposition automationComposition) {
+ @NonNull final AutomationComposition automationComposition) {
var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition,
- JpaAutomationComposition::new, "automation composition"));
+ JpaAutomationComposition::new, "automation composition"));
automationCompositionRepository.flush();
// Return the saved automation composition
return result.toAuthorative();
@Transactional(readOnly = true)
public List<AutomationComposition> getAcInstancesByCompositionId(UUID compositionId) {
return ProviderUtils
- .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
+ .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString()));
}
/**
- * Get all automation compositions in transition..
+ * Get all automation compositions in transition.
*
* @return all automation compositions found
*/
jpaList.addAll(automationCompositionRepository.findByLockStateIn(
List.of(LockState.LOCKING, LockState.UNLOCKING)));
jpaList.addAll(automationCompositionRepository.findBySubStateIn(
- List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
+ List.of(SubState.PREPARING, SubState.MIGRATION_PRECHECKING, SubState.REVIEWING)));
return jpaList.stream().map(JpaAutomationComposition::getInstanceId)
- .map(UUID::fromString).collect(Collectors.toSet());
+ .map(UUID::fromString).collect(Collectors.toSet());
}
/**
* Get automation compositions.
*
- * @param name the name of the automation composition to get, null to get all automation compositions
- * @param version the version of the automation composition to get, null to get all automation compositions
+ * @param name the name of the automation composition to get, null to get all automation compositions
+ * @param version the version of the automation composition to get, null to get all automation compositions
* @param pageable the Pageable
* @return the automation compositions found
*/
@Transactional(readOnly = true)
public List<AutomationComposition> getAutomationCompositions(@NonNull final UUID compositionId, final String name,
- final String version, @NonNull final Pageable pageable) {
+ final String version,
+ @NonNull final Pageable pageable) {
return ProviderUtils.asEntityList(automationCompositionRepository
- .findAll(createExample(compositionId, name, version), pageable).toList());
+ .findAll(createExample(compositionId, name, version), pageable).toList());
}
private Example<JpaAutomationComposition> createExample(final UUID compositionId, final String name,
- final String version) {
+ final String version) {
var example = new JpaAutomationComposition();
example.setCompositionId(compositionId != null ? compositionId.toString() : null);
example.setName(name);
var jpaDeleteAutomationComposition = automationCompositionRepository.findById(instanceId.toString());
if (jpaDeleteAutomationComposition.isEmpty()) {
var errorMessage = "delete of automation composition \"" + instanceId
- + "\" failed, automation composition does not exist";
+ + "\" failed, automation composition does not exist";
throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage);
}
}
return result;
}
+
+ /**
+ * Save a copy of an automation composition to the copy table in case of a rollback.
+ *
+ * @param automationComposition the composition to be copied
+ */
+ public void copyAcElementsBeforeUpdate(AutomationComposition automationComposition) {
+ var copy = new AutomationCompositionRollback(automationComposition);
+ var jpaCopy = new JpaAutomationCompositionRollback(copy);
+ acRollbackRepository.save(jpaCopy);
+ acRollbackRepository.flush();
+ }
}
import org.onap.policy.models.base.PfUtils;\r
\r
\r
-public class JpaAutomationCompositionRollbackTest {\r
+class JpaAutomationCompositionRollbackTest {\r
\r
private static final String NULL_INSTANCE_ID_ERROR = "instanceId is marked .*ull but is null";\r
private static final String NULL_ERROR = " is marked .*ull but is null";\r
import org.onap.policy.clamp.models.acm.concepts.LockState;
import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationComposition;
import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionElement;
+import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionRollback;
import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository;
import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRepository;
+import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionRollbackRepository;
import org.onap.policy.common.utils.coder.Coder;
import org.onap.policy.common.utils.coder.StandardCoder;
import org.onap.policy.common.utils.resources.ResourceUtils;
-import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
private static final Coder CODER = new StandardCoder();
private static final String AUTOMATION_COMPOSITION_JSON =
- "src/test/resources/providers/TestAutomationCompositions.json";
+ "src/test/resources/providers/TestAutomationCompositions.json";
private AutomationCompositions inputAutomationCompositions;
private List<JpaAutomationComposition> inputAutomationCompositionsJpa;
private final String originalJson = ResourceUtils.getResourceAsString(AUTOMATION_COMPOSITION_JSON);
+ private AutomationCompositionProvider automationCompositionProvider;
+ private AutomationCompositionRepository automationCompositionRepository;
+ private AutomationCompositionElementRepository acElementRepository;
+ private AutomationCompositionRollbackRepository acRollbackRepository;
+
@BeforeEach
void beforeSetupDao() throws Exception {
inputAutomationCompositions = CODER.decode(originalJson, AutomationCompositions.class);
inputAutomationCompositionsJpa =
- ProviderUtils.getJpaAndValidateList(inputAutomationCompositions.getAutomationCompositionList(),
- JpaAutomationComposition::new, "automation compositions");
+ ProviderUtils.getJpaAndValidateList(inputAutomationCompositions.getAutomationCompositionList(),
+ JpaAutomationComposition::new, "automation compositions");
+
+ // set mocks
+ automationCompositionRepository = mock(AutomationCompositionRepository.class);
+ acElementRepository = mock(AutomationCompositionElementRepository.class);
+ acRollbackRepository = mock(AutomationCompositionRollbackRepository.class);
+ automationCompositionProvider =
+ new AutomationCompositionProvider(automationCompositionRepository, acElementRepository,
+ acRollbackRepository);
}
@Test
void testAutomationCompositionCreate() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
when(automationCompositionRepository.save(any(JpaAutomationComposition.class)))
- .thenReturn(inputAutomationCompositionsJpa.get(0));
+ .thenReturn(inputAutomationCompositionsJpa.get(0));
var inputAc = inputAutomationCompositions.getAutomationCompositionList().get(0);
var createdAutomationComposition = automationCompositionProvider.createAutomationComposition(inputAc);
@Test
void testAutomationCompositionUpdate() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
assertThatThrownBy(() -> automationCompositionProvider.updateAutomationComposition(null))
- .hasMessageMatching(AC_IS_NULL);
+ .hasMessageMatching(AC_IS_NULL);
when(automationCompositionRepository.save(inputAutomationCompositionsJpa.get(0)))
- .thenReturn(inputAutomationCompositionsJpa.get(0));
+ .thenReturn(inputAutomationCompositionsJpa.get(0));
var createdAutomationComposition = automationCompositionProvider
- .updateAutomationComposition(inputAutomationCompositions.getAutomationCompositionList().get(0));
+ .updateAutomationComposition(inputAutomationCompositions.getAutomationCompositionList().get(0));
assertEquals(inputAutomationCompositions.getAutomationCompositionList().get(0), createdAutomationComposition);
}
@Test
void testGetAutomationCompositionsWithNull() {
- var automationCompositionProvider = new AutomationCompositionProvider(
- mock(AutomationCompositionRepository.class), mock(AutomationCompositionElementRepository.class));
-
assertThatThrownBy(() -> automationCompositionProvider
- .getAutomationCompositions(UUID.randomUUID(), null, null, null))
- .hasMessage("pageable is marked non-null but is null");
+ .getAutomationCompositions(UUID.randomUUID(), null, null, null))
+ .hasMessage("pageable is marked non-null but is null");
assertThatThrownBy(() -> automationCompositionProvider
- .getAutomationCompositions(null, null, null, Pageable.unpaged()))
- .hasMessage("compositionId is marked non-null but is null");
+ .getAutomationCompositions(null, null, null, Pageable.unpaged()))
+ .hasMessage("compositionId is marked non-null but is null");
}
@Test
void testGetAutomationCompositions() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
when(automationCompositionRepository
- .findAll(Mockito.<Example<JpaAutomationComposition>>any(), any(Pageable.class)))
- .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
+ .findAll(Mockito.any(), any(Pageable.class)))
+ .thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
var acList = automationCompositionProvider.getAutomationCompositions(UUID.randomUUID(),
- automationComposition.getName(), automationComposition.getVersion(), Pageable.unpaged());
+ automationComposition.getName(), automationComposition.getVersion(), Pageable.unpaged());
assertThat(acList).hasSize(2);
acList = automationCompositionProvider.getAutomationCompositions(automationComposition.getCompositionId(), null,
- null, Pageable.unpaged());
+ null, Pageable.unpaged());
assertThat(acList).hasSize(2);
when(automationCompositionRepository
- .findAll(Mockito.<Example<JpaAutomationComposition>>any(), Mockito.any(Pageable.class)))
+ .findAll(Mockito.any(), Mockito.any(Pageable.class)))
.thenReturn(new PageImpl<>(inputAutomationCompositionsJpa));
acList = automationCompositionProvider.getAutomationCompositions(automationComposition.getCompositionId(), null,
null, PageRequest.of(0, 10));
@Test
void testGetAutomationComposition() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
assertThatThrownBy(
- () -> automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId()))
- .hasMessageMatching("AutomationComposition not found");
+ () -> automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId()))
+ .hasMessageMatching("AutomationComposition not found");
when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
- .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+ .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
var ac = automationCompositionProvider.getAutomationComposition(automationComposition.getInstanceId());
assertEquals(automationComposition, ac);
}
@Test
void testFindAutomationComposition() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
var acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId());
assertThat(acOpt).isEmpty();
assertThat(acOpt).isEmpty();
when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
- .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+ .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getInstanceId());
assertEquals(automationComposition, acOpt.get());
- when(automationCompositionRepository.findOne(Mockito.<Example<JpaAutomationComposition>>any()))
- .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+ when(automationCompositionRepository.findOne(Mockito.any()))
+ .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
acOpt = automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
assertEquals(automationComposition, acOpt.get());
}
@Test
void testGetAcInstancesByCompositionId() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
when(automationCompositionRepository.findByCompositionId(automationComposition.getCompositionId().toString()))
- .thenReturn(inputAutomationCompositionsJpa);
+ .thenReturn(inputAutomationCompositionsJpa);
var acList =
- automationCompositionProvider.getAcInstancesByCompositionId(automationComposition.getCompositionId());
+ automationCompositionProvider.getAcInstancesByCompositionId(automationComposition.getCompositionId());
assertEquals(inputAutomationCompositions.getAutomationCompositionList(), acList);
}
List<JpaAutomationComposition> res1 = new ArrayList<>();
res1.add(inputAutomationCompositionsJpa.get(0));
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
+
when(automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING,
DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING)))
.thenReturn(res1);
.thenReturn(List.of(inputAutomationCompositionsJpa.get(1)));
var acList = automationCompositionProvider.getAcInstancesInTransition();
assertThat(acList).hasSize(2)
- .contains(inputAutomationCompositions.getAutomationCompositionList().get(0).getInstanceId())
- .contains(inputAutomationCompositions.getAutomationCompositionList().get(1).getInstanceId());
+ .contains(inputAutomationCompositions.getAutomationCompositionList().get(0).getInstanceId())
+ .contains(inputAutomationCompositions.getAutomationCompositionList().get(1).getInstanceId());
}
@Test
void testDeleteAutomationComposition() {
- var automationCompositionRepository = mock(AutomationCompositionRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(automationCompositionRepository,
- mock(AutomationCompositionElementRepository.class));
-
assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationComposition(UUID.randomUUID()))
- .hasMessageMatching(".*.failed, automation composition does not exist");
+ .hasMessageMatching(".*.failed, automation composition does not exist");
var automationComposition = inputAutomationCompositions.getAutomationCompositionList().get(0);
when(automationCompositionRepository.findById(automationComposition.getInstanceId().toString()))
- .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
+ .thenReturn(Optional.of(inputAutomationCompositionsJpa.get(0)));
var deletedAc =
- automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
+ automationCompositionProvider.deleteAutomationComposition(automationComposition.getInstanceId());
assertEquals(automationComposition, deletedAc);
}
@Test
void testDeleteElementById() {
- var acElementRepository = mock(AutomationCompositionElementRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(
- mock(AutomationCompositionRepository.class), acElementRepository);
assertThatThrownBy(() -> automationCompositionProvider.deleteAutomationCompositionElement(null))
- .hasMessageMatching(ACELEMENT_ID_IS_NULL);
+ .hasMessageMatching(ACELEMENT_ID_IS_NULL);
var elementId = UUID.randomUUID();
automationCompositionProvider.deleteAutomationCompositionElement(elementId);
verify(acElementRepository).deleteById(elementId.toString());
@Test
void testValidateElementIds() {
- var acElementRepository = mock(AutomationCompositionElementRepository.class);
- var automationCompositionProvider = new AutomationCompositionProvider(
- mock(AutomationCompositionRepository.class), acElementRepository);
-
var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
var result = automationCompositionProvider.validateElementIds(ac);
result = automationCompositionProvider.validateElementIds(ac);
assertThat(result.isValid()).isTrue();
}
+
+ @Test
+ void testCopyAcElements() {
+ var ac = inputAutomationCompositions.getAutomationCompositionList().get(0);
+ automationCompositionProvider.copyAcElementsBeforeUpdate(ac);
+
+ verify(acRollbackRepository).save(any(JpaAutomationCompositionRollback.class));
+ }
}
import org.springframework.transaction.annotation.Transactional;
/**
- * This class provides the create, read and delete actions on Commissioning of automation composition concepts in the
+ * This class provides the creation, read and delete actions on Commissioning of automation composition concepts in the
* database to the callers.
*/
@Service
case DEPRIME:
deprime(acmDefinition);
-
break;
default:
private static final String DO_NOT_MATCH = " do not match with ";
private static final String ELEMENT_ID_NOT_PRESENT = "Element id not present ";
private static final String NOT_VALID_ORDER =
- "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
+ "Not valid order %s; DeployState: %s; LockState: %s; SubState: %s; StateChangeResult: %s";
private static final Logger LOGGER = LoggerFactory.getLogger(AutomationCompositionInstantiationProvider.class);
/**
* Create automation composition.
*
- * @param compositionId The UUID of the automation composition definition
+ * @param compositionId The UUID of the automation composition definition
* @param automationComposition the automation composition
* @return the result of the instantiation operation
*/
public InstantiationResponse createAutomationComposition(UUID compositionId,
- AutomationComposition automationComposition) {
- if (!compositionId.equals(automationComposition.getCompositionId())) {
- throw new PfModelRuntimeException(Status.BAD_REQUEST,
- automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
- }
+ AutomationComposition automationComposition) {
+ validateCompositionRequested(compositionId, automationComposition);
var checkAutomationCompositionOpt =
- automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
+ automationCompositionProvider.findAutomationComposition(automationComposition.getKey().asIdentifier());
if (checkAutomationCompositionOpt.isPresent()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST,
- automationComposition.getKey().asIdentifier() + " already defined");
+ automationComposition.getKey().asIdentifier() + " already defined");
}
var validationResult = validateAutomationComposition(automationComposition);
/**
* Update automation composition.
*
- * @param compositionId The UUID of the automation composition definition
+ * @param compositionId The UUID of the automation composition definition
* @param automationComposition the automation composition
* @return the result of the update
*/
public InstantiationResponse updateAutomationComposition(UUID compositionId,
- AutomationComposition automationComposition) {
+ AutomationComposition automationComposition) {
var instanceId = automationComposition.getInstanceId();
var acToUpdate = automationCompositionProvider.getAutomationComposition(instanceId);
- if (!compositionId.equals(acToUpdate.getCompositionId())) {
- throw new PfModelRuntimeException(Status.BAD_REQUEST,
- automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
- }
+ validateCompositionRequested(compositionId, acToUpdate);
if (DeployState.UNDEPLOYED.equals(acToUpdate.getDeployState())) {
acToUpdate.setElements(automationComposition.getElements());
acToUpdate.setName(automationComposition.getName());
}
}
var result = acInstanceStateResolver.resolve(deployOrder, LockOrder.NONE, subOrder,
- acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
- acToUpdate.getStateChangeResult());
+ acToUpdate.getDeployState(), acToUpdate.getLockState(), acToUpdate.getSubState(),
+ acToUpdate.getStateChangeResult());
return switch (result) {
case "UPDATE" -> updateDeployedAutomationComposition(automationComposition, acToUpdate);
case "MIGRATE_PRECHECK" -> migratePrecheckAc(automationComposition, acToUpdate);
default -> throw new PfModelRuntimeException(Status.BAD_REQUEST,
- "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
+ "Not allowed to " + deployOrder + " in the state " + acToUpdate.getDeployState());
};
}
* Update deployed AC Element properties.
*
* @param automationComposition the automation composition
- * @param acToBeUpdated the composition to be updated
+ * @param acToBeUpdated the composition to be updated
* @return the result of the update
*/
private InstantiationResponse updateDeployedAutomationComposition(
- AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+ AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+ // save copy in case of a rollback
+ automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
// Iterate and update the element property values
for (var element : automationComposition.getElements().entrySet()) {
throw new PfModelRuntimeException(Status.BAD_REQUEST,
"Not allowed to migrate in the state " + acToBeUpdated.getDeployState());
}
+ // make copy for rollback
+ automationCompositionProvider.copyAcElementsBeforeUpdate(acToBeUpdated);
// Iterate and update the element property values
- for (var element : automationComposition.getElements().entrySet()) {
- var elementId = element.getKey();
- var dbAcElement = acToBeUpdated.getElements().get(elementId);
- // Add additional elements if present for migration
- if (dbAcElement == null) {
- LOGGER.info("New Ac element {} added in Migration", elementId);
- acToBeUpdated.getElements().put(elementId, element.getValue());
- } else {
- AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
- var newDefinition = element.getValue().getDefinition().asConceptKey();
- var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
- checkCompatibility(newDefinition, dbElementDefinition, automationComposition.getInstanceId());
- dbAcElement.setDefinition(element.getValue().getDefinition());
- }
- }
- // Remove element which is not present in the new Ac instance
- var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
- elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
-
- var validationResult =
- validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
- if (!validationResult.isValid()) {
- throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
- }
- acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
+ var elementsRemoved = updateElementsProperties(automationComposition, acToBeUpdated);
var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionTargetId());
updateAcForMigration(acToBeUpdated, acDefinition);
private List<UUID> getElementRemoved(AutomationComposition acFromDb, AutomationComposition acFromMigration) {
return acFromDb.getElements().keySet().stream()
- .filter(id -> acFromMigration.getElements().get(id) == null).toList();
+ .filter(id -> acFromMigration.getElements().get(id) == null).toList();
}
void checkCompatibility(PfConceptKey newDefinition, PfConceptKey dbElementDefinition,
var compatibility = newDefinition.getCompatibility(dbElementDefinition);
if (PfKey.Compatibility.DIFFERENT.equals(compatibility)) {
throw new PfModelRuntimeException(Status.BAD_REQUEST,
- dbElementDefinition + " is not compatible with " + newDefinition);
+ dbElementDefinition + " is not compatible with " + newDefinition);
}
if (PfKey.Compatibility.MAJOR.equals(compatibility) || PfKey.Compatibility.MINOR
- .equals(compatibility)) {
+ .equals(compatibility)) {
LOGGER.warn("Migrate {}: Version {} has {} compatibility with {} ", instanceId, newDefinition,
- compatibility, dbElementDefinition);
+ compatibility, dbElementDefinition);
}
}
private InstantiationResponse migratePrecheckAc(
- AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
+ AutomationComposition automationComposition, AutomationComposition acToBeUpdated) {
acToBeUpdated.setPrecheck(true);
var copyAc = new AutomationComposition(acToBeUpdated);
// Iterate and update the element property values
- for (var element : automationComposition.getElements().entrySet()) {
- var elementId = element.getKey();
- var copyElement = copyAc.getElements().get(elementId);
- // Add additional elements if present for migration
- if (copyElement == null) {
- LOGGER.info("New Ac element {} added in Migration", elementId);
- copyAc.getElements().put(elementId, element.getValue());
- } else {
- AcmUtils.recursiveMerge(copyElement.getProperties(), element.getValue().getProperties());
- var newDefinition = element.getValue().getDefinition().asConceptKey();
- var copyElementDefinition = copyElement.getDefinition().asConceptKey();
- checkCompatibility(newDefinition, copyElementDefinition, automationComposition.getInstanceId());
- copyElement.setDefinition(element.getValue().getDefinition());
- }
- }
- // Remove element which is not present in the new Ac instance
- var elementsRemoved = getElementRemoved(copyAc, automationComposition);
- elementsRemoved.forEach(uuid -> copyAc.getElements().remove(uuid));
-
- var validationResult =
- validateAutomationComposition(copyAc, automationComposition.getCompositionTargetId());
- if (!validationResult.isValid()) {
- throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
- }
- copyAc.setCompositionTargetId(automationComposition.getCompositionTargetId());
+ updateElementsProperties(automationComposition, copyAc);
// Publish migrate event to the participants
supervisionAcHandler.migratePrecheck(copyAc);
* Validate AutomationComposition.
*
* @param automationComposition AutomationComposition to validate
- * @param compositionId the composition id
+ * @param compositionId the composition id
* @return the result of validation
*/
private BeanValidationResult validateAutomationComposition(AutomationComposition automationComposition,
- UUID compositionId) {
+ UUID compositionId) {
var result = new BeanValidationResult("AutomationComposition", automationComposition);
var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
if (acDefinitionOpt.isEmpty()) {
result.addResult(new ObjectValidationResult("ServiceTemplate", compositionId, ValidationStatus.INVALID,
- "Commissioned automation composition definition not found"));
+ "Commissioned automation composition definition not found"));
return result;
}
if (!AcTypeState.PRIMED.equals(acDefinitionOpt.get().getState())) {
result.addResult(new ObjectValidationResult("ServiceTemplate.state", acDefinitionOpt.get().getState(),
- ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
+ ValidationStatus.INVALID, "Commissioned automation composition definition not primed"));
return result;
}
var participantIds = acDefinitionOpt.get().getElementStateMap().values().stream()
- .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
+ .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
participantProvider.verifyParticipantState(participantIds);
result.addResult(AcmUtils.validateAutomationComposition(automationComposition,
- acDefinitionOpt.get().getServiceTemplate(),
- acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
+ acDefinitionOpt.get().getServiceTemplate(),
+ acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()));
result.addResult(automationCompositionProvider.validateElementIds(automationComposition));
if (encryptionUtils.encryptionEnabled()) {
var acDefinitionOpt = acDefinitionProvider.findAcDefinition(compositionId);
acDefinitionOpt.ifPresent(acDefinition
- -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
+ -> encryptionUtils.findAndEncryptSensitiveData(acDefinition, automationComposition));
}
}
* Get Automation Composition.
*
* @param compositionId The UUID of the automation composition definition
- * @param instanceId The UUID of the automation composition instance
+ * @param instanceId The UUID of the automation composition instance
* @return the Automation Composition
*/
@Transactional(readOnly = true)
public AutomationComposition getAutomationComposition(@NonNull UUID compositionId, UUID instanceId) {
var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
if (!compositionId.equals(automationComposition.getCompositionId())
- && !compositionId.equals(automationComposition.getCompositionTargetId())) {
+ && !compositionId.equals(automationComposition.getCompositionTargetId())) {
throw new PfModelRuntimeException(Status.BAD_REQUEST,
- automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
+ automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
}
return automationComposition;
}
* Delete the automation composition with the given name and version.
*
* @param compositionId The UUID of the automation composition definition
- * @param instanceId The UUID of the automation composition instance
+ * @param instanceId The UUID of the automation composition instance
* @return the result of the deletion
*/
public InstantiationResponse deleteAutomationComposition(UUID compositionId, UUID instanceId) {
var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
- if (!compositionId.equals(automationComposition.getCompositionId())) {
- throw new PfModelRuntimeException(Status.BAD_REQUEST,
- automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
- }
- var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
- var participantIds = acDefinition.getElementStateMap().values().stream()
- .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
- participantProvider.verifyParticipantState(participantIds);
+ var acDefinition = getAcDefinition(compositionId, automationComposition);
var result = acInstanceStateResolver.resolve(DeployOrder.DELETE,
- null, null,
- automationComposition.getDeployState(), automationComposition.getLockState(),
- automationComposition.getSubState(), automationComposition.getStateChangeResult());
+ null, null,
+ automationComposition.getDeployState(), automationComposition.getLockState(),
+ automationComposition.getSubState(), automationComposition.getStateChangeResult());
if (!DeployOrder.DELETE.name().equals(result)) {
var msg = String.format(NOT_VALID_ORDER, DeployOrder.DELETE,
- automationComposition.getDeployState(), automationComposition.getLockState(),
- automationComposition.getSubState(), automationComposition.getStateChangeResult());
+ automationComposition.getDeployState(), automationComposition.getLockState(),
+ automationComposition.getSubState(), automationComposition.getStateChangeResult());
throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
}
supervisionAcHandler.delete(automationComposition, acDefinition);
/**
* Get the requested automation compositions.
*
- * @param name the name of the automation composition to get, null for all automation compositions
- * @param version the version of the automation composition to get, null for all automation compositions
+ * @param name the name of the automation composition to get, null for all automation compositions
+ * @param version the version of the automation composition to get, null for all automation compositions
* @param pageable the Pageable
* @return the automation compositions
*/
@Transactional(readOnly = true)
public AutomationCompositions getAutomationCompositions(@NonNull final UUID compositionId,
- final String name, final String version, @NonNull final Pageable pageable) {
+ final String name, final String version,
+ @NonNull final Pageable pageable) {
var automationCompositions = new AutomationCompositions();
automationCompositions.setAutomationCompositionList(
- automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
+ automationCompositionProvider.getAutomationCompositions(compositionId, name, version, pageable));
return automationCompositions;
}
/**
* Handle Composition Instance State.
*
- * @param compositionId the compositionId
- * @param instanceId the instanceId
+ * @param compositionId the compositionId
+ * @param instanceId the instanceId
* @param acInstanceStateUpdate the AcInstanceStateUpdate
*/
public void compositionInstanceState(UUID compositionId, UUID instanceId,
- @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
+ @Valid AcInstanceStateUpdate acInstanceStateUpdate) {
var automationComposition = automationCompositionProvider.getAutomationComposition(instanceId);
- if (!compositionId.equals(automationComposition.getCompositionId())) {
- throw new PfModelRuntimeException(Status.BAD_REQUEST,
- automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
- }
- var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
-
- var participantIds = acDefinition.getElementStateMap().values().stream()
- .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
-
- participantProvider.verifyParticipantState(participantIds);
+ var acDefinition = getAcDefinition(compositionId, automationComposition);
var result = acInstanceStateResolver.resolve(acInstanceStateUpdate.getDeployOrder(),
- acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
- automationComposition.getDeployState(), automationComposition.getLockState(),
- automationComposition.getSubState(), automationComposition.getStateChangeResult());
+ acInstanceStateUpdate.getLockOrder(), acInstanceStateUpdate.getSubOrder(),
+ automationComposition.getDeployState(), automationComposition.getLockState(),
+ automationComposition.getSubState(), automationComposition.getStateChangeResult());
switch (result) {
case "DEPLOY":
supervisionAcHandler.deploy(automationComposition, acDefinition);
default:
var msg = String.format(NOT_VALID_ORDER, acInstanceStateUpdate,
- automationComposition.getDeployState(), automationComposition.getLockState(),
- automationComposition.getSubState(), automationComposition.getStateChangeResult());
+ automationComposition.getDeployState(), automationComposition.getLockState(),
+ automationComposition.getSubState(), automationComposition.getStateChangeResult());
throw new PfModelRuntimeException(Status.BAD_REQUEST, msg);
}
}
+
+ private List<UUID> updateElementsProperties(AutomationComposition automationComposition,
+ AutomationComposition acToBeUpdated) {
+ for (var element : automationComposition.getElements().entrySet()) {
+ var elementId = element.getKey();
+ var dbAcElement = acToBeUpdated.getElements().get(elementId);
+ // Add additional elements if present for migration
+ if (dbAcElement == null) {
+ LOGGER.info("New Ac element {} added in Migration", elementId);
+ acToBeUpdated.getElements().put(elementId, element.getValue());
+ } else {
+ AcmUtils.recursiveMerge(dbAcElement.getProperties(), element.getValue().getProperties());
+ var newDefinition = element.getValue().getDefinition().asConceptKey();
+ var dbElementDefinition = dbAcElement.getDefinition().asConceptKey();
+ checkCompatibility(newDefinition, dbElementDefinition, automationComposition.getInstanceId());
+ dbAcElement.setDefinition(element.getValue().getDefinition());
+ }
+ }
+ // Remove element which is not present in the new Ac instance
+ var elementsRemoved = getElementRemoved(acToBeUpdated, automationComposition);
+ elementsRemoved.forEach(uuid -> acToBeUpdated.getElements().remove(uuid));
+
+ var validationResult =
+ validateAutomationComposition(acToBeUpdated, automationComposition.getCompositionTargetId());
+ if (!validationResult.isValid()) {
+ throw new PfModelRuntimeException(Status.BAD_REQUEST, validationResult.getResult());
+ }
+ acToBeUpdated.setCompositionTargetId(automationComposition.getCompositionTargetId());
+ return elementsRemoved;
+ }
+
+ private static void validateCompositionRequested(UUID compositionId,
+ AutomationComposition automationComposition) {
+ if (!compositionId.equals(automationComposition.getCompositionId())) {
+ throw new PfModelRuntimeException(Status.BAD_REQUEST,
+ automationComposition.getCompositionId() + DO_NOT_MATCH + compositionId);
+ }
+ }
+
+ private AutomationCompositionDefinition getAcDefinition(UUID compositionId,
+ AutomationComposition automationComposition) {
+ validateCompositionRequested(compositionId, automationComposition);
+ var acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId());
+
+ var participantIds = acDefinition.getElementStateMap().values().stream()
+ .map(NodeTemplateState::getParticipantId).collect(Collectors.toSet());
+
+ participantProvider.verifyParticipantState(participantIds);
+ return acDefinition;
+ }
}
# ============LICENSE_START=======================================================
-# Copyright (C) 2022-2023,2025 OpenInfra Foundation Europe. All rights reserved.
+# Copyright (C) 2022-2023, 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.
description: This value is assigned by the service provider
tags:
- name: Participant Monitoring
- description: Pariticipant Monitoring Controller, for monitoring of and requesting information from participants
+ description: Participant Monitoring Controller, for monitoring of and requesting information from participants
- name: Automation Composition Definition
description: Automation Composition Definition Controller, for definition and management of Automation Composition Types
- name: Automation Composition Instance
get:
tags:
- Participant Monitoring
- summary: Query Particicpants
+ summary: Query Participants
description: Query the participants that are registered on the ACM runtime
operationId: queryParticipants
parameters:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
put:
tags:
- Participant Monitoring
- summary: Order an immendiate Participant Report from all participants
+ summary: Order an immediate Participant Report from all participants
description: Requests all participants to immediately generate a heartbeat report with their information and status
and the information and status of all their AC Element Types and Instances. The results are published on subsequent
GET REST requests on the "participants" endpoint.
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
x-codegen-request-body-name: body
/participants/{participantId}:
get:
- Participant Monitoring
summary: Get details of the requested participant
definitions
- description: Get details of the requested commissioned participant, returning all pariticipant details
+ description: Get details of the requested commissioned participant, returning all participant details
operationId: getParticipant
parameters:
- name : participantId
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
put:
tags:
- Participant Monitoring
- summary: Order an immendiate Participant Report from a participant
+ summary: Order an immediate Participant Report from a participant
description: Requests the participants to immediately generate a heartbeat report with its information and status
and the information and status of all its AC Element Types and Instances. The results are published on subsequent
GET REST requests on the "participants" endpoint.
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
x-codegen-request-body-name: body
/compositions:
get:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
post:
tags:
- Automation Composition Definition
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
x-codegen-request-body-name: body
/compositions/{compositionId}:
get:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
put:
tags:
- Automation Composition Definition
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
x-codegen-request-body-name: body
delete:
tags:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
/compositions/{compositionId}/instances:
get:
tags:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
post:
tags:
- Automation Composition Instance
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
x-codegen-request-body-name: body
/compositions/{compositionId}/instances/{instanceId}:
get:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
put:
tags:
- Automation Composition Instance
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
x-codegen-request-body-name: body
delete:
tags:
security:
- basicAuth: []
x-interface info:
- api-version: 1.0.0
- last-mod-release: London
+ api-version: 8.2.1
+ last-mod-release: Paris
components:
securitySchemes: