From b75038fab6ae0816413ed9f925639f3befe4fddb Mon Sep 17 00:00:00 2001 From: FrancescoFioraEst Date: Thu, 14 Dec 2023 17:33:57 +0000 Subject: Update compositions and instances monitoring Improved performance scanning only compositions and instances that are in transition. Issue-ID: POLICY-4906 Change-Id: I7a849e921f1d97509f67ff624c715c893a1432ab Signed-off-by: FrancescoFioraEst --- .../persistence/provider/AcDefinitionProvider.java | 50 ++++++++- .../provider/AutomationCompositionProvider.java | 18 +++- .../AutomationCompositionDefinitionRepository.java | 11 +- .../AutomationCompositionRepository.java | 13 ++- .../provider/AcDefinitionProviderTest.java | 81 ++++++++++----- .../AutomationCompositionProviderTest.java | 26 ++++- .../handler/AutomationCompositionHandler.java | 12 +++ .../handler/AutomationCompositionHandlerTest.java | 14 ++- .../runtime/supervision/SupervisionAcHandler.java | 2 - .../runtime/supervision/SupervisionHandler.java | 15 ++- .../supervision/SupervisionParticipantHandler.java | 3 - .../runtime/supervision/SupervisionScanner.java | 69 +++++++++---- .../acm/runtime/supervision/TimeoutHandler.java | 18 +++- .../supervision/SupervisionHandlerTest.java | 48 ++++++++- .../supervision/SupervisionScannerTest.java | 115 +++++++++++++++------ 15 files changed, 383 insertions(+), 112 deletions(-) diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java index a9b9a0cfd..9eb5e7a32 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProvider.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,10 +28,14 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition; +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.document.base.ToscaServiceTemplateValidation; import org.onap.policy.clamp.models.acm.document.concepts.DocToscaServiceTemplate; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionDefinition; +import org.onap.policy.clamp.models.acm.persistence.concepts.JpaNodeTemplateState; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionDefinitionRepository; +import org.onap.policy.clamp.models.acm.persistence.repository.NodeTemplateStateRepository; import org.onap.policy.clamp.models.acm.utils.AcmUtils; import org.onap.policy.common.parameters.BeanValidationResult; import org.onap.policy.models.base.PfModelRuntimeException; @@ -47,6 +51,7 @@ import org.springframework.transaction.annotation.Transactional; public class AcDefinitionProvider { private final AutomationCompositionDefinitionRepository acmDefinitionRepository; + private final NodeTemplateStateRepository nodeTemplateStateRepository; /** * Create Automation Composition Definition. @@ -124,6 +129,43 @@ public class AcDefinitionProvider { acmDefinitionRepository.flush(); } + /** + * Update Ac Definition AcTypeState, StateChangeResult and restarting. + * + * @param compositionId The UUID of the automation composition definition to update + * @param state the AcTypeState + * @param stateChangeResult the StateChangeResult + * @param restarting restarting process + */ + public void updateAcDefinitionState(UUID compositionId, AcTypeState state, StateChangeResult stateChangeResult, + Boolean restarting) { + var jpaUpdate = acmDefinitionRepository.findById(compositionId.toString()); + if (jpaUpdate.isEmpty()) { + String errorMessage = "update of Automation Composition Definition \"" + compositionId + + "\" failed, Automation Composition Definition does not exist"; + throw new PfModelRuntimeException(Response.Status.NOT_FOUND, errorMessage); + } + var acDefinition = jpaUpdate.get(); + acDefinition.setState(state); + acDefinition.setStateChangeResult(stateChangeResult); + acDefinition.setRestarting(restarting); + acmDefinitionRepository.save(acDefinition); + acmDefinitionRepository.flush(); + } + + /** + * Update Ac DefinitionElement. + * + * @param nodeTemplateState the NodeTemplateState + * @param compositionId The UUID of the automation composition definition + */ + public void updateAcDefinitionElement(NodeTemplateState nodeTemplateState, UUID compositionId) { + var jpaNodeTemplateState = new JpaNodeTemplateState( + nodeTemplateState.getNodeTemplateStateId().toString(), compositionId.toString()); + jpaNodeTemplateState.fromAuthorative(nodeTemplateState); + nodeTemplateStateRepository.save(jpaNodeTemplateState); + } + /** * Delete Automation Composition Definition. * @@ -173,13 +215,13 @@ public class AcDefinitionProvider { } /** - * Get Automation Composition Definitions. + * Get Automation Composition Definitions in transition. * * @return the Automation Composition Definitions found */ @Transactional(readOnly = true) - public List getAllAcDefinitions() { - var jpaList = acmDefinitionRepository.findAll(); + public List getAllAcDefinitionsInTransition() { + var jpaList = acmDefinitionRepository.findByStateIn(List.of(AcTypeState.PRIMING, AcTypeState.DEPRIMING)); return ProviderUtils.asEntityList(jpaList); } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java index 1ffcc1b6e..8be12960b 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProvider.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -127,7 +127,7 @@ public class AutomationCompositionProvider { @NonNull final AutomationComposition automationComposition) { var result = automationCompositionRepository.save(ProviderUtils.getJpaAndValidate(automationComposition, JpaAutomationComposition::new, "automation composition")); - + automationCompositionRepository.flush(); // Return the saved automation composition return result.toAuthorative(); } @@ -144,6 +144,20 @@ public class AutomationCompositionProvider { .asEntityList(automationCompositionRepository.findByCompositionId(compositionId.toString())); } + /** + * Get all automation compositions in transition.. + * + * @return all automation compositions found + */ + @Transactional(readOnly = true) + public List getAcInstancesInTransition() { + var jpaList = automationCompositionRepository.findByDeployStateIn(List.of(DeployState.DEPLOYING, + DeployState.UNDEPLOYING, DeployState.DELETING, DeployState.UPDATING, DeployState.MIGRATING)); + jpaList.addAll(automationCompositionRepository.findByLockStateIn( + List.of(LockState.LOCKING, LockState.UNLOCKING))); + return ProviderUtils.asEntityList(jpaList); + } + /** * Get automation compositions. * diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionDefinitionRepository.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionDefinitionRepository.java index df4d7dffa..86de60bf2 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionDefinitionRepository.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionDefinitionRepository.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation. + * Copyright (C) 2022,2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,13 +20,16 @@ package org.onap.policy.clamp.models.acm.persistence.repository; +import java.util.Collection; +import java.util.List; +import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionDefinition; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.repository.query.QueryByExampleExecutor; import org.springframework.stereotype.Repository; @Repository public interface AutomationCompositionDefinitionRepository - extends JpaRepository, - QueryByExampleExecutor { + extends JpaRepository { + + List findByStateIn(Collection states); } diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionRepository.java b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionRepository.java index bb8b3e6d9..d61dfb41b 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionRepository.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/persistence/repository/AutomationCompositionRepository.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation. + * Copyright (C) 2021-2022,2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,20 @@ package org.onap.policy.clamp.models.acm.persistence.repository; +import java.util.Collection; import java.util.List; +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.persistence.concepts.JpaAutomationComposition; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.repository.query.QueryByExampleExecutor; import org.springframework.stereotype.Repository; @Repository -public interface AutomationCompositionRepository - extends JpaRepository, QueryByExampleExecutor { +public interface AutomationCompositionRepository extends JpaRepository { List findByCompositionId(String compositionId); + + List findByDeployStateIn(Collection deployStates); + + List findByLockStateIn(Collection lockStates); } diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java index 78095c907..1e067c8f6 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AcDefinitionProviderTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,9 +38,12 @@ import org.mockito.Mockito; import org.onap.policy.clamp.models.acm.concepts.AcTypeState; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionDefinition; 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.document.concepts.DocToscaServiceTemplate; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionDefinition; +import org.onap.policy.clamp.models.acm.persistence.concepts.JpaNodeTemplateState; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionDefinitionRepository; +import org.onap.policy.clamp.models.acm.persistence.repository.NodeTemplateStateRepository; import org.onap.policy.clamp.models.acm.utils.CommonTestData; import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; @@ -91,7 +94,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.save(any(JpaAutomationCompositionDefinition.class))) .thenReturn(new JpaAutomationCompositionDefinition(acmDefinition)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var result = acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, ELEMENT_NAME, NODE_TYPE); @@ -101,11 +104,9 @@ class AcDefinitionProviderTest { @Test void testToscaWithInvalidElement() { - var docServiceTemplate = new DocToscaServiceTemplate(inputServiceTemplate); - var acmDefinition = getAcDefinition(docServiceTemplate); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); assertThatThrownBy(() -> acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, INVALID_ELEMENT_NAME, NODE_TYPE)) @@ -114,11 +115,9 @@ class AcDefinitionProviderTest { @Test void testToscaWithInvalidNodeType() { - var docServiceTemplate = new DocToscaServiceTemplate(inputServiceTemplate); - var acmDefinition = getAcDefinition(docServiceTemplate); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); assertThatThrownBy(() -> acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, ELEMENT_NAME, INVALID_NODE_TYPE)) @@ -135,7 +134,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.save(any(JpaAutomationCompositionDefinition.class))) .thenReturn(new JpaAutomationCompositionDefinition(acmDefinition)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); inputServiceTemplate.setMetadata(new HashMap<>()); var result = acDefinitionProvider .createAutomationCompositionDefinition(inputServiceTemplate, ELEMENT_NAME, NODE_TYPE); @@ -147,7 +146,7 @@ class AcDefinitionProviderTest { @Test void testUpdateServiceTemplate() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); acDefinitionProvider.updateServiceTemplate(UUID.randomUUID(), inputServiceTemplate, ELEMENT_NAME, NODE_TYPE); verify(acmDefinitionRepository).save(any(JpaAutomationCompositionDefinition.class)); } @@ -155,19 +154,45 @@ class AcDefinitionProviderTest { @Test void testUpdateAcDefinition() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var acmDefinition = getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate)); acDefinitionProvider.updateAcDefinition(acmDefinition, NODE_TYPE); verify(acmDefinitionRepository).save(any(JpaAutomationCompositionDefinition.class)); } + @Test + void testUpdateAcDefinitionState() { + var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var acmDefinition = getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate)); + acmDefinition.setState(AcTypeState.PRIMING); + var jpa = new JpaAutomationCompositionDefinition(acmDefinition); + when(acmDefinitionRepository.findById(acmDefinition.getCompositionId().toString())) + .thenReturn(Optional.of(jpa)); + acDefinitionProvider.updateAcDefinitionState(acmDefinition.getCompositionId(), AcTypeState.PRIMED, + StateChangeResult.NO_ERROR, false); + verify(acmDefinitionRepository).save(jpa); + } + + @Test + void testUpdateAcDefinitionElement() { + var nodeTemplateState = new NodeTemplateState(); + nodeTemplateState.setNodeTemplateId(new ToscaConceptIdentifier("name", "1.0.0")); + nodeTemplateState.setNodeTemplateStateId(UUID.randomUUID()); + nodeTemplateState.setState(AcTypeState.PRIMED); + var nodeTemplateStateRepository = mock(NodeTemplateStateRepository.class); + var acDefinitionProvider = new AcDefinitionProvider(null, nodeTemplateStateRepository); + acDefinitionProvider.updateAcDefinitionElement(nodeTemplateState, UUID.randomUUID()); + verify(nodeTemplateStateRepository).save(any(JpaNodeTemplateState.class)); + } + @Test void testGetAcDefinition() { var jpa = new JpaAutomationCompositionDefinition(); jpa.fromAuthorative(getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate))); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); when(acmDefinitionRepository.findById(jpa.getCompositionId())).thenReturn(Optional.of(jpa)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var result = acDefinitionProvider.getAcDefinition(UUID.fromString(jpa.getCompositionId())); assertThat(result).isNotNull(); } @@ -175,7 +200,7 @@ class AcDefinitionProviderTest { @Test void testGetAcDefinitionNotFound() { var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var compositionId = UUID.randomUUID(); assertThatThrownBy(() -> acDefinitionProvider.getAcDefinition(compositionId)) .hasMessage("Get serviceTemplate \"" + compositionId + "\" failed, serviceTemplate does not exist"); @@ -187,20 +212,24 @@ class AcDefinitionProviderTest { jpa.fromAuthorative(getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate))); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); when(acmDefinitionRepository.findById(jpa.getCompositionId())).thenReturn(Optional.of(jpa)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); - var result = acDefinitionProvider.findAcDefinition(UUID.fromString(jpa.getCompositionId())); - assertThat(result).isNotNull(); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var compositionId = UUID.fromString(jpa.getCompositionId()); + var result = acDefinitionProvider.findAcDefinition(compositionId); + assertThat(result).isNotEmpty(); } @Test - void testGetAllAcDefinitions() { + void getAllAcDefinitionsInTransition() { + var acDefinition = getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate)); + acDefinition.setState(AcTypeState.PRIMING); var jpa = new JpaAutomationCompositionDefinition(); - jpa.fromAuthorative(getAcDefinition(new DocToscaServiceTemplate(inputServiceTemplate))); + jpa.fromAuthorative(acDefinition); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - when(acmDefinitionRepository.findAll()).thenReturn(List.of(jpa)); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); - var result = acDefinitionProvider.getAllAcDefinitions(); - assertThat(result).hasSize(1); + when(acmDefinitionRepository.findByStateIn(List.of(AcTypeState.PRIMING, AcTypeState.DEPRIMING))) + .thenReturn(List.of(jpa)); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); + var result = acDefinitionProvider.getAllAcDefinitionsInTransition(); + assertThat(result).isNotEmpty(); } @Test @@ -212,7 +241,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.findById(acmDefinition.getCompositionId().toString())) .thenReturn(Optional.of(new JpaAutomationCompositionDefinition(acmDefinition))); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var result = acDefinitionProvider.deleteAcDefintion(acmDefinition.getCompositionId()); assertThat(result).isEqualTo(docServiceTemplate.toAuthorative()); @@ -222,7 +251,7 @@ class AcDefinitionProviderTest { void testDeleteServiceTemplateEmpty() { var compositionId = UUID.randomUUID(); var acmDefinitionRepository = mock(AutomationCompositionDefinitionRepository.class); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); assertThatThrownBy(() -> acDefinitionProvider.deleteAcDefintion(compositionId)) .hasMessage("delete of Automation Composition Definition \"" + compositionId + "\" failed, Automation Composition Definition does not exist"); @@ -236,7 +265,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.findAll(Mockito.>any())) .thenReturn(List.of(new JpaAutomationCompositionDefinition(acmDefinition))); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var result = acDefinitionProvider.getServiceTemplateList(inputServiceTemplate.getName(), inputServiceTemplate.getVersion()); @@ -252,7 +281,7 @@ class AcDefinitionProviderTest { when(acmDefinitionRepository.findAll(Mockito.>any())) .thenReturn(List.of(new JpaAutomationCompositionDefinition(acmDefinition))); - var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository); + var acDefinitionProvider = new AcDefinitionProvider(acmDefinitionRepository, null); var result = acDefinitionProvider.getServiceTemplateList(null, inputServiceTemplate.getVersion()); diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java index b09ddda74..463e958f3 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/persistence/provider/AutomationCompositionProviderTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -40,6 +41,8 @@ import org.mockito.Mockito; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionElementInfo; import org.onap.policy.clamp.models.acm.concepts.AutomationCompositionInfo; 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.persistence.concepts.JpaAutomationComposition; import org.onap.policy.clamp.models.acm.persistence.concepts.JpaAutomationCompositionElement; import org.onap.policy.clamp.models.acm.persistence.repository.AutomationCompositionElementRepository; @@ -176,6 +179,27 @@ class AutomationCompositionProviderTest { assertEquals(inputAutomationCompositions.getAutomationCompositionList(), acList); } + @Test + void testGetAcInstancesInTransition() { + inputAutomationCompositions.getAutomationCompositionList().get(0).setDeployState(DeployState.DEPLOYING); + inputAutomationCompositions.getAutomationCompositionList().get(1).setLockState(LockState.LOCKING); + inputAutomationCompositionsJpa.get(0).setDeployState(DeployState.DEPLOYING); + inputAutomationCompositionsJpa.get(1).setLockState(LockState.LOCKING); + + List 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); + when(automationCompositionRepository.findByLockStateIn(List.of(LockState.LOCKING, LockState.UNLOCKING))) + .thenReturn(List.of(inputAutomationCompositionsJpa.get(1))); + var acList = automationCompositionProvider.getAcInstancesInTransition(); + assertEquals(inputAutomationCompositions.getAutomationCompositionList(), acList); + } + @Test void testDeleteAutomationComposition() { var automationCompositionRepository = mock(AutomationCompositionRepository.class); diff --git a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java index fd82c37ba..fefa637da 100644 --- a/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java +++ b/participant/participant-intermediary/src/main/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandler.java @@ -40,6 +40,7 @@ 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.ParticipantRestartAc; +import org.onap.policy.clamp.models.acm.concepts.ParticipantState; import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeploy; @@ -47,6 +48,7 @@ import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCom import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange; import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantMessageType; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder; @@ -428,6 +430,16 @@ public class AutomationCompositionHandler { var acElementsDefinitions = cacheProvider.getAcElementsDefinitions().get(compositionId); if (acElementsDefinitions == null) { // this participant does not handle this composition + var participantPrimeAck = new ParticipantPrimeAck(); + participantPrimeAck.setCompositionId(compositionId); + participantPrimeAck.setMessage("Already deprimed or never primed"); + participantPrimeAck.setResult(true); + participantPrimeAck.setResponseTo(messageId); + participantPrimeAck.setCompositionState(AcTypeState.COMMISSIONED); + participantPrimeAck.setStateChangeResult(StateChangeResult.NO_ERROR); + participantPrimeAck.setParticipantId(cacheProvider.getParticipantId()); + participantPrimeAck.setState(ParticipantState.ON_LINE); + publisher.sendParticipantPrimeAck(participantPrimeAck); return; } var list = new ArrayList<>(acElementsDefinitions.values()); diff --git a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java index 661c009f6..b8fd3b42d 100644 --- a/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java +++ b/participant/participant-intermediary/src/test/java/org/onap/policy/clamp/acm/participant/intermediary/handler/AutomationCompositionHandlerTest.java @@ -47,6 +47,7 @@ import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCom import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionDeployAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionMigration; import org.onap.policy.clamp.models.acm.messages.kafka.participant.AutomationCompositionStateChange; +import org.onap.policy.clamp.models.acm.messages.kafka.participant.ParticipantPrimeAck; import org.onap.policy.clamp.models.acm.messages.kafka.participant.PropertiesUpdate; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.DeployOrder; import org.onap.policy.clamp.models.acm.messages.rest.instantiation.LockOrder; @@ -273,7 +274,7 @@ class AutomationCompositionHandlerTest { } @Test - void handleComposiotDeprimeTest() { + void handleCompositionDeprimeTest() { var acElementDefinition = new AutomationCompositionElementDefinition(); acElementDefinition.setAcElementDefinitionId(new ToscaConceptIdentifier("key", "1.0.0")); var toscaNodeTemplate = new ToscaNodeTemplate(); @@ -291,6 +292,17 @@ class AutomationCompositionHandlerTest { verify(listener).deprime(any(UUID.class), any(CompositionDto.class)); } + @Test + void handleCompositionAlreadyDeprimedTest() { + var messageId = UUID.randomUUID(); + var compositionId = UUID.randomUUID(); + var participantMessagePublisher = mock(ParticipantMessagePublisher.class); + var ach = new AutomationCompositionHandler(mock(CacheProvider.class), participantMessagePublisher, + mock(ThreadHandler.class)); + ach.deprime(messageId, compositionId); + verify(participantMessagePublisher).sendParticipantPrimeAck(any(ParticipantPrimeAck.class)); + } + @Test void restartedTest() { var acElementDefinition = new AutomationCompositionElementDefinition(); diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java index a5dc0e78e..d6fa5d8d7 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionAcHandler.java @@ -204,7 +204,6 @@ public class SupervisionAcHandler { description = "AUTOMATION_COMPOSITION_DEPLOY_ACK messages received") public void handleAutomationCompositionUpdateAckMessage( AutomationCompositionDeployAck automationCompositionAckMessage) { - LOGGER.debug("AutomationComposition Update Ack message received {}", automationCompositionAckMessage); setAcElementStateInDb(automationCompositionAckMessage); } @@ -219,7 +218,6 @@ public class SupervisionAcHandler { description = "AUTOMATION_COMPOSITION_STATECHANGE_ACK messages received") public void handleAutomationCompositionStateChangeAckMessage( AutomationCompositionDeployAck automationCompositionAckMessage) { - LOGGER.debug("AutomationComposition StateChange Ack message received {}", automationCompositionAckMessage); setAcElementStateInDb(automationCompositionAckMessage); } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java index 660cb28a5..963e4830e 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandler.java @@ -52,7 +52,6 @@ public class SupervisionHandler { */ @Timed(value = "listener.participant_prime_ack", description = "PARTICIPANT_PRIME_ACK messages received") public void handleParticipantMessage(ParticipantPrimeAck participantPrimeAckMessage) { - LOGGER.debug("Participant Prime Ack message received {}", participantPrimeAckMessage); var acDefinitionOpt = acDefinitionProvider.findAcDefinition(participantPrimeAckMessage.getCompositionId()); if (acDefinitionOpt.isEmpty()) { LOGGER.warn("AC Definition not found in database {}", participantPrimeAckMessage.getCompositionId()); @@ -74,8 +73,10 @@ public class SupervisionHandler { || AcTypeState.PRIMED.equals(acDefinition.getState()) ? AcTypeState.PRIMED : AcTypeState.COMMISSIONED; var msgInErrors = StateChangeResult.FAILED.equals(participantPrimeAckMessage.getStateChangeResult()); boolean inProgress = !StateChangeResult.FAILED.equals(acDefinition.getStateChangeResult()); + boolean toUpdate = false; if (inProgress && msgInErrors) { acDefinition.setStateChangeResult(StateChangeResult.FAILED); + toUpdate = true; } boolean completed = true; @@ -85,6 +86,7 @@ public class SupervisionHandler { element.setMessage(participantPrimeAckMessage.getMessage()); element.setState(participantPrimeAckMessage.getCompositionState()); element.setRestarting(null); + acDefinitionProvider.updateAcDefinitionElement(element, acDefinition.getCompositionId()); } if (!finalState.equals(element.getState())) { completed = false; @@ -95,16 +97,19 @@ public class SupervisionHandler { } if (inProgress && !msgInErrors && completed) { + toUpdate = true; acDefinition.setState(finalState); if (StateChangeResult.TIMEOUT.equals(acDefinition.getStateChangeResult())) { acDefinition.setStateChangeResult(StateChangeResult.NO_ERROR); } } - if (!restarting) { + if (!restarting && acDefinition.getRestarting() != null) { + toUpdate = true; acDefinition.setRestarting(null); } - acDefinitionProvider.updateAcDefinition(acDefinition, - acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()); + if (toUpdate) { + acDefinitionProvider.updateAcDefinitionState(acDefinition.getCompositionId(), acDefinition.getState(), + acDefinition.getStateChangeResult(), acDefinition.getRestarting()); + } } - } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionParticipantHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionParticipantHandler.java index 7a2c58d50..24c256fa4 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionParticipantHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionParticipantHandler.java @@ -74,7 +74,6 @@ public class SupervisionParticipantHandler { @MessageIntercept @Timed(value = "listener.participant_register", description = "PARTICIPANT_REGISTER messages received") public void handleParticipantMessage(ParticipantRegister participantRegisterMsg) { - LOGGER.debug("Participant Register received {}", participantRegisterMsg); var participantOpt = participantProvider.findParticipant(participantRegisterMsg.getParticipantId()); if (participantOpt.isPresent()) { @@ -100,7 +99,6 @@ public class SupervisionParticipantHandler { @MessageIntercept @Timed(value = "listener.participant_deregister", description = "PARTICIPANT_DEREGISTER messages received") public void handleParticipantMessage(ParticipantDeregister participantDeregisterMsg) { - LOGGER.debug("Participant Deregister received {}", participantDeregisterMsg); var participantOpt = participantProvider.findParticipant(participantDeregisterMsg.getParticipantId()); if (participantOpt.isPresent()) { @@ -120,7 +118,6 @@ public class SupervisionParticipantHandler { @MessageIntercept @Timed(value = "listener.participant_status", description = "PARTICIPANT_STATUS messages received") public void handleParticipantMessage(ParticipantStatus participantStatusMsg) { - LOGGER.debug("Participant Status received {}", participantStatusMsg); var participantOpt = participantProvider.findParticipant(participantStatusMsg.getParticipantId()); if (participantOpt.isEmpty()) { diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java index 33118fab7..881969a90 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScanner.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. * ================================================================================ @@ -23,8 +23,11 @@ package org.onap.policy.clamp.acm.runtime.supervision; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionDeployPublisher; import org.onap.policy.clamp.acm.runtime.supervision.comm.AutomationCompositionStateChangePublisher; @@ -56,7 +59,6 @@ public class SupervisionScanner { private final AcDefinitionProvider acDefinitionProvider; private final AutomationCompositionStateChangePublisher automationCompositionStateChangePublisher; private final AutomationCompositionDeployPublisher automationCompositionDeployPublisher; - private final AcRuntimeParameterGroup acRuntimeParameterGroup; /** * Constructor for instantiating SupervisionScanner. @@ -76,7 +78,6 @@ public class SupervisionScanner { this.acDefinitionProvider = acDefinitionProvider; this.automationCompositionStateChangePublisher = automationCompositionStateChangePublisher; this.automationCompositionDeployPublisher = automationCompositionDeployPublisher; - this.acRuntimeParameterGroup = acRuntimeParameterGroup; acTimeout.setMaxWaitMs(acRuntimeParameterGroup.getParticipantParameters().getMaxStatusWaitMs()); } @@ -87,20 +88,27 @@ public class SupervisionScanner { public void run() { LOGGER.debug("Scanning automation compositions in the database . . ."); - var list = acDefinitionProvider.getAllAcDefinitions(); - for (var acDefinition : list) { - if (AcTypeState.PRIMING.equals(acDefinition.getState()) - || AcTypeState.DEPRIMING.equals(acDefinition.getState())) { - scanAutomationCompositionDefinition(acDefinition); - } else { - acTimeout.clear(acDefinition.getCompositionId()); - var acList = - automationCompositionProvider.getAcInstancesByCompositionId(acDefinition.getCompositionId()); - for (var automationComposition : acList) { - scanAutomationComposition(automationComposition, acDefinition.getServiceTemplate()); - } + var acDefinitionList = acDefinitionProvider.getAllAcDefinitionsInTransition(); + for (var acDefinition : acDefinitionList) { + scanAutomationCompositionDefinition(acDefinition); + } + Set set = new HashSet<>(); + set.addAll(acDefinitionList + .stream().map(AutomationCompositionDefinition::getCompositionId).collect(Collectors.toSet())); + + var acList = automationCompositionProvider.getAcInstancesInTransition(); + HashMap acDefinitionMap = new HashMap<>(); + for (var automationComposition : acList) { + var acDefinition = acDefinitionMap.get(automationComposition.getCompositionId()); + if (acDefinition == null) { + acDefinition = acDefinitionProvider.getAcDefinition(automationComposition.getCompositionId()); + acDefinitionMap.put(acDefinition.getCompositionId(), acDefinition); } + scanAutomationComposition(automationComposition, acDefinition.getServiceTemplate()); } + set.addAll( + acList.stream().map(AutomationComposition::getInstanceId).collect(Collectors.toSet())); + acTimeout.removeIfNotPresent(set); LOGGER.debug("Automation composition scan complete . . ."); } @@ -110,7 +118,7 @@ public class SupervisionScanner { LOGGER.debug("automation definition {} scanned, OK", acDefinition.getCompositionId()); // Clear Timeout on ac Definition - acTimeout.clear(acDefinition.getCompositionId()); + acTimeout.remove(acDefinition.getCompositionId()); return; } @@ -121,7 +129,21 @@ public class SupervisionScanner { acTimeout.clear(acDefinition.getCompositionId()); } - handleTimeout(acDefinition); + boolean completed = true; + var finalState = AcTypeState.PRIMING.equals(acDefinition.getState()) + || AcTypeState.PRIMED.equals(acDefinition.getState()) ? AcTypeState.PRIMED : AcTypeState.COMMISSIONED; + for (var element : acDefinition.getElementStateMap().values()) { + if (!finalState.equals(element.getState())) { + completed = false; + } + } + if (completed) { + acDefinitionProvider.updateAcDefinitionState(acDefinition.getCompositionId(), finalState, + StateChangeResult.NO_ERROR, null); + acTimeout.remove(acDefinition.getCompositionId()); + } else { + handleTimeout(acDefinition); + } } private void scanAutomationComposition(final AutomationComposition automationComposition, @@ -134,7 +156,7 @@ public class SupervisionScanner { LOGGER.debug("automation composition {} scanned, OK", automationComposition.getInstanceId()); // Clear Timeout on automation composition - clearTimeout(automationComposition, true); + removeTimeout(automationComposition); return; } @@ -214,7 +236,7 @@ public class SupervisionScanner { } // Clear timeout on automation composition - clearTimeout(automationComposition, true); + removeTimeout(automationComposition); } private void clearTimeout(AutomationComposition automationComposition, boolean cleanPhase) { @@ -224,6 +246,11 @@ public class SupervisionScanner { } } + private void removeTimeout(AutomationComposition automationComposition) { + acTimeout.remove(automationComposition.getInstanceId()); + phaseMap.remove(automationComposition.getInstanceId()); + } + private void handleTimeout(AutomationCompositionDefinition acDefinition) { var compositionId = acDefinition.getCompositionId(); if (acTimeout.isTimeout(compositionId)) { @@ -235,8 +262,8 @@ public class SupervisionScanner { LOGGER.debug("Report timeout for the ac definition {}", acDefinition.getCompositionId()); acTimeout.setTimeout(compositionId); acDefinition.setStateChangeResult(StateChangeResult.TIMEOUT); - acDefinitionProvider.updateAcDefinition(acDefinition, - acRuntimeParameterGroup.getAcmParameters().getToscaCompositionName()); + acDefinitionProvider.updateAcDefinitionState(acDefinition.getCompositionId(), + acDefinition.getState(), acDefinition.getStateChangeResult(), acDefinition.getRestarting()); } } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java index 976c91438..3b34252bf 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/TimeoutHandler.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation. + * Copyright (C) 2023-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,8 +33,8 @@ public class TimeoutHandler { @Setter private long maxWaitMs; - private Set mapTimeout = new HashSet<>(); - private Map mapTimer = new HashMap<>(); + private final Set mapTimeout = new HashSet<>(); + private final Map mapTimer = new HashMap<>(); public long getDuration(K id) { mapTimer.putIfAbsent(id, getEpochMilli()); @@ -61,6 +61,18 @@ public class TimeoutHandler { mapTimer.remove(id); } + /** + * Remove elements that are not present in set. + * + * @param set the elements that should be present + */ + public void removeIfNotPresent(final Set set) { + var res = mapTimeout.stream().filter(el -> !set.contains(el)).toList(); + if (!res.isEmpty()) { + res.forEach(this::remove); + } + } + public void setTimeout(K id) { mapTimeout.add(id); } diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java index 4028f57f6..448666f8f 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionHandlerTest.java @@ -22,6 +22,7 @@ package org.onap.policy.clamp.acm.runtime.supervision; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.onap.policy.clamp.acm.runtime.util.CommonTestData.TOSCA_SERVICE_TEMPLATE_YAML; @@ -77,13 +78,16 @@ class SupervisionHandlerTest { void testParticipantPrimeAck() { var participantPrimeAckMessage = new ParticipantPrimeAck(); participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); + participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); participantPrimeAckMessage.setState(ParticipantState.ON_LINE); var acDefinition = CommonTestData.createAcDefinition( InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMING); + acDefinition.setStateChangeResult(StateChangeResult.NO_ERROR); participantPrimeAckMessage.setCompositionId(acDefinition.getCompositionId()); - acDefinition.getElementStateMap().values().iterator().next() - .setParticipantId(CommonTestData.getParticipantId()); + for (var element : acDefinition.getElementStateMap().values()) { + element.setParticipantId(CommonTestData.getParticipantId()); + } var acDefinitionProvider = mock(AcDefinitionProvider.class); when(acDefinitionProvider.findAcDefinition(acDefinition.getCompositionId())) @@ -93,7 +97,10 @@ class SupervisionHandlerTest { handler.handleParticipantMessage(participantPrimeAckMessage); verify(acDefinitionProvider).findAcDefinition(any()); - verify(acDefinitionProvider).updateAcDefinition(any(), any()); + verify(acDefinitionProvider, times(acDefinition.getElementStateMap().size())) + .updateAcDefinitionElement(any(), any()); + verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), AcTypeState.PRIMED, + StateChangeResult.NO_ERROR, null); } @Test @@ -117,6 +124,39 @@ class SupervisionHandlerTest { handler.handleParticipantMessage(participantPrimeAckMessage); verify(acDefinitionProvider).findAcDefinition(any()); - verify(acDefinitionProvider).updateAcDefinition(any(), any()); + verify(acDefinitionProvider).updateAcDefinitionElement(any(), any()); + verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), AcTypeState.PRIMING, + StateChangeResult.FAILED, null); + } + + @Test + void testParticipantPrimeAckRestarted() { + var participantPrimeAckMessage = new ParticipantPrimeAck(); + participantPrimeAckMessage.setParticipantId(CommonTestData.getParticipantId()); + participantPrimeAckMessage.setCompositionState(AcTypeState.PRIMED); + participantPrimeAckMessage.setState(ParticipantState.ON_LINE); + + var acDefinition = CommonTestData.createAcDefinition( + InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML), AcTypeState.PRIMED); + acDefinition.setStateChangeResult(StateChangeResult.TIMEOUT); + acDefinition.setRestarting(true); + participantPrimeAckMessage.setCompositionId(acDefinition.getCompositionId()); + for (var element : acDefinition.getElementStateMap().values()) { + element.setParticipantId(CommonTestData.getParticipantId()); + element.setRestarting(true); + } + + var acDefinitionProvider = mock(AcDefinitionProvider.class); + when(acDefinitionProvider.findAcDefinition(acDefinition.getCompositionId())) + .thenReturn(Optional.of(acDefinition)); + + var handler = new SupervisionHandler(acDefinitionProvider, CommonTestData.getTestParamaterGroup()); + + handler.handleParticipantMessage(participantPrimeAckMessage); + verify(acDefinitionProvider).findAcDefinition(any()); + verify(acDefinitionProvider, times(acDefinition.getElementStateMap().size())) + .updateAcDefinitionElement(any(), any()); + verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), AcTypeState.PRIMED, + StateChangeResult.NO_ERROR, null); } } diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java index a1fad46b1..7d0b4252a 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java @@ -1,6 +1,6 @@ /*- * ============LICENSE_START======================================================= - * Copyright (C) 2021-2023 Nordix Foundation. + * Copyright (C) 2021-2024 Nordix Foundation. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -46,6 +47,7 @@ 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.NodeTemplateState; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider; import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider; @@ -57,82 +59,131 @@ class SupervisionScannerTest { private static final UUID compositionId = UUID.randomUUID(); - private AcDefinitionProvider createAcDefinitionProvider(AcTypeState acTypeState, - StateChangeResult stateChangeResult) { + private AutomationCompositionDefinition createAutomationCompositionDefinition(AcTypeState acTypeState, + StateChangeResult stateChangeResult) { var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); var acDefinition = new AutomationCompositionDefinition(); acDefinition.setState(acTypeState); acDefinition.setStateChangeResult(stateChangeResult); acDefinition.setCompositionId(compositionId); acDefinition.setServiceTemplate(serviceTemplate); + var node = new NodeTemplateState(); + node.setState(AcTypeState.PRIMING); + node.setNodeTemplateStateId(UUID.randomUUID()); + acDefinition.setElementStateMap(Map.of(node.getNodeTemplateStateId().toString(), node)); + return acDefinition; + } + + private AcDefinitionProvider createAcDefinitionProvider(AutomationCompositionDefinition acDefinition) { var acDefinitionProvider = mock(AcDefinitionProvider.class); - when(acDefinitionProvider.getAllAcDefinitions()).thenReturn(List.of(Objects.requireNonNull(acDefinition))); + var acTypeState = acDefinition.getState(); + if (AcTypeState.PRIMING.equals(acTypeState) || AcTypeState.DEPRIMING.equals(acTypeState)) { + when(acDefinitionProvider.getAllAcDefinitionsInTransition()) + .thenReturn(List.of(Objects.requireNonNull(acDefinition))); + } + when(acDefinitionProvider.getAcDefinition(compositionId)).thenReturn(acDefinition); return acDefinitionProvider; } + private AcDefinitionProvider createAcDefinitionProvider(AcTypeState acTypeState, + StateChangeResult stateChangeResult) { + return createAcDefinitionProvider(createAutomationCompositionDefinition(acTypeState, stateChangeResult)); + } + private AcDefinitionProvider createAcDefinitionProvider() { return createAcDefinitionProvider(AcTypeState.PRIMED, StateChangeResult.NO_ERROR); } @Test - void testScannerOrderedFailed() { + void testAcDefinitionPrimeFailed() { var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMING, StateChangeResult.FAILED); var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner"); var supervisionScanner = new SupervisionScanner(mock(AutomationCompositionProvider.class), acDefinitionProvider, mock(AutomationCompositionStateChangePublisher.class), mock(AutomationCompositionDeployPublisher.class), acRuntimeParameterGroup); supervisionScanner.run(); - verify(acDefinitionProvider, times(0)).updateAcDefinition(any(AutomationCompositionDefinition.class), - eq(CommonTestData.TOSCA_COMP_NAME)); + verify(acDefinitionProvider, times(0)).updateAcDefinitionState(any(), any(), any(), any()); } @Test - void testScannerOrderedPriming() { - var acDefinitionProvider = createAcDefinitionProvider(AcTypeState.PRIMING, StateChangeResult.NO_ERROR); + void testAcDefinitionPrimeTimeout() { + var acDefinition = createAutomationCompositionDefinition(AcTypeState.PRIMING, StateChangeResult.NO_ERROR); + var acDefinitionProvider = createAcDefinitionProvider(acDefinition); var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner"); var supervisionScanner = new SupervisionScanner(mock(AutomationCompositionProvider.class), acDefinitionProvider, mock(AutomationCompositionStateChangePublisher.class), mock(AutomationCompositionDeployPublisher.class), acRuntimeParameterGroup); supervisionScanner.run(); - verify(acDefinitionProvider, times(0)).updateAcDefinition(any(AutomationCompositionDefinition.class), - eq(CommonTestData.TOSCA_COMP_NAME)); + // Ac Definition in Priming state + verify(acDefinitionProvider, times(0)).updateAcDefinitionState(any(), any(), any(), any()); acRuntimeParameterGroup.getParticipantParameters().setMaxStatusWaitMs(-1); supervisionScanner = new SupervisionScanner(mock(AutomationCompositionProvider.class), acDefinitionProvider, mock(AutomationCompositionStateChangePublisher.class), mock(AutomationCompositionDeployPublisher.class), acRuntimeParameterGroup); supervisionScanner.run(); - verify(acDefinitionProvider).updateAcDefinition(any(AutomationCompositionDefinition.class), - eq(CommonTestData.TOSCA_COMP_NAME)); + // set Timeout + verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), acDefinition.getState(), + StateChangeResult.TIMEOUT, null); + + clearInvocations(acDefinitionProvider); + acDefinition.setStateChangeResult(StateChangeResult.TIMEOUT); + supervisionScanner.run(); + // already in Timeout + verify(acDefinitionProvider, times(0)).updateAcDefinitionState(any(), any(), any(), any()); + + clearInvocations(acDefinitionProvider); + // retry by the user + acDefinition.setStateChangeResult(StateChangeResult.NO_ERROR); + supervisionScanner.run(); + // set Timeout + verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), acDefinition.getState(), + StateChangeResult.TIMEOUT, null); + + clearInvocations(acDefinitionProvider); + for (var element : acDefinition.getElementStateMap().values()) { + element.setState(AcTypeState.PRIMED); + } + supervisionScanner.run(); + // completed + verify(acDefinitionProvider).updateAcDefinitionState(acDefinition.getCompositionId(), AcTypeState.PRIMED, + StateChangeResult.NO_ERROR, null); } @Test - void testScannerOrderedStateEqualsToState() { + void testAcNotInTransitionOrFailed() { var automationCompositionProvider = mock(AutomationCompositionProvider.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var acRuntimeParameterGroup = CommonTestData.geParameterGroup("dbScanner"); var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + automationComposition.setCompositionId(compositionId); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var supervisionScanner = new SupervisionScanner(automationCompositionProvider, createAcDefinitionProvider(), automationCompositionStateChangePublisher, automationCompositionDeployPublisher, acRuntimeParameterGroup); + + // not in transition supervisionScanner.run(); + verify(automationCompositionProvider, times(0)).updateAutomationComposition(any(AutomationComposition.class)); + automationComposition.setDeployState(DeployState.DEPLOYING); + automationComposition.setStateChangeResult(StateChangeResult.FAILED); + supervisionScanner.run(); + // failed verify(automationCompositionProvider, times(0)).updateAutomationComposition(any(AutomationComposition.class)); } @Test - void testScannerOrderedStateDifferentToState() { + void testAcUndeployCompleted() { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.UNDEPLOYING); automationComposition.setLockState(LockState.NONE); + automationComposition.setCompositionId(compositionId); var automationCompositionProvider = mock(AutomationCompositionProvider.class); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); @@ -147,13 +198,13 @@ class SupervisionScannerTest { } @Test - void testScannerDelete() { + void testAcDeleted() { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.DELETING); automationComposition.setLockState(LockState.NONE); + automationComposition.setCompositionId(compositionId); var automationCompositionProvider = mock(AutomationCompositionProvider.class); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); @@ -171,8 +222,8 @@ class SupervisionScannerTest { void testScanner() { var automationCompositionProvider = mock(AutomationCompositionProvider.class); var automationComposition = new AutomationComposition(); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + automationComposition.setCompositionId(compositionId); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); @@ -191,12 +242,12 @@ class SupervisionScannerTest { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.DEPLOYING); automationComposition.setLockState(LockState.NONE); + automationComposition.setCompositionId(compositionId); for (Map.Entry entry : automationComposition.getElements().entrySet()) { entry.getValue().setDeployState(DeployState.DEPLOYING); } var automationCompositionProvider = mock(AutomationCompositionProvider.class); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); @@ -225,6 +276,7 @@ class SupervisionScannerTest { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.DEPLOYING); automationComposition.setLockState(LockState.NONE); + automationComposition.setCompositionId(compositionId); for (var element : automationComposition.getElements().values()) { if ("org.onap.domain.database.Http_PMSHMicroserviceAutomationCompositionElement" .equals(element.getDefinition().getName())) { @@ -237,8 +289,7 @@ class SupervisionScannerTest { } var automationCompositionProvider = mock(AutomationCompositionProvider.class); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); @@ -258,6 +309,7 @@ class SupervisionScannerTest { void testSendAutomationCompositionMigrate() { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.MIGRATING); + automationComposition.setCompositionId(compositionId); var compositionTargetId = UUID.randomUUID(); automationComposition.setCompositionTargetId(compositionTargetId); automationComposition.setLockState(LockState.LOCKED); @@ -267,8 +319,7 @@ class SupervisionScannerTest { } var automationCompositionProvider = mock(AutomationCompositionProvider.class); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); @@ -289,6 +340,7 @@ class SupervisionScannerTest { var automationComposition = InstantiationUtils.getAutomationCompositionFromResource(AC_JSON, "Crud"); automationComposition.setDeployState(DeployState.DEPLOYED); automationComposition.setLockState(LockState.UNLOCKING); + automationComposition.setCompositionId(compositionId); for (var element : automationComposition.getElements().values()) { if ("org.onap.domain.database.Http_PMSHMicroserviceAutomationCompositionElement" .equals(element.getDefinition().getName())) { @@ -301,8 +353,7 @@ class SupervisionScannerTest { } var automationCompositionProvider = mock(AutomationCompositionProvider.class); - when(automationCompositionProvider.getAcInstancesByCompositionId(compositionId)) - .thenReturn(List.of(automationComposition)); + when(automationCompositionProvider.getAcInstancesInTransition()).thenReturn(List.of(automationComposition)); var automationCompositionDeployPublisher = mock(AutomationCompositionDeployPublisher.class); var automationCompositionStateChangePublisher = mock(AutomationCompositionStateChangePublisher.class); -- cgit 1.2.3-korg