From ee6ff41f54f53baa375d0a69119bb00f9e3c90ed Mon Sep 17 00:00:00 2001 From: FrancescoFioraEst Date: Tue, 10 Jun 2025 11:36:50 +0100 Subject: [PATCH] Make a configurable timeout for operations in ACM-R Issue-ID: POLICY-5370 Change-Id: I10f64c1ccdeb5ed0e6cfaaf3b2d63eb9d956f85e Signed-off-by: FrancescoFioraEst --- .../clamp/acm/pmsh/funtional-pmsh-usecase.yaml | 5 ++- .../models/acm/concepts/ParticipantUtils.java | 50 ++++++++++++++++++++++ .../models/acm/concepts/ParticipantUtilsTest.java | 31 ++++++++++++++ .../supervision/scanner/AbstractScanner.java | 8 +++- .../supervision/scanner/AcDefinitionScanner.java | 8 +++- .../supervision/SupervisionScannerTest.java | 1 + .../scanner/AcDefinitionScannerTest.java | 1 + .../resources/rest/acm/AutomationComposition.json | 21 +++++++-- 8 files changed, 118 insertions(+), 7 deletions(-) diff --git a/examples/src/main/resources/clamp/acm/pmsh/funtional-pmsh-usecase.yaml b/examples/src/main/resources/clamp/acm/pmsh/funtional-pmsh-usecase.yaml index 4587e31e8..3896dfa66 100644 --- a/examples/src/main/resources/clamp/acm/pmsh/funtional-pmsh-usecase.yaml +++ b/examples/src/main/resources/clamp/acm/pmsh/funtional-pmsh-usecase.yaml @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (C) 2022-2023 Nordix Foundation. +# 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. @@ -3373,3 +3373,6 @@ topology_template: eventProtocolParameters: eventProtocol: JSON eventNameFilter: CDSResponseStatusEvent +metadata: + primeTimeoutMs: 200000 + deprimeTimeoutMs: 100000 diff --git a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtils.java b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtils.java index 5cb5d3f48..ded715b67 100644 --- a/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtils.java +++ b/models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtils.java @@ -33,6 +33,20 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; public final class ParticipantUtils { private static final String STAGE_MIGRATE = "migrate"; private static final String STAGE_PREPARE = "prepare"; + public static final String DEFAULT_TIMEOUT = "maxOperationWaitMs"; + public static final String PRIME_TIMEOUT = "primeTimeoutMs"; + public static final String DEPRIME_TIMEOUT = "deprimeTimeoutMs"; + public static final String DEPLOY_TIMEOUT = "deployTimeoutMs"; + public static final String UNDEPLOY_TIMEOUT = "undeployTimeoutMs"; + public static final String UPDATE_TIMEOUT = "updateTimeoutMs"; + public static final String MIGRATE_TIMEOUT = "migrateTimeoutMs"; + public static final String DELETE_TIMEOUT = "deleteTimeoutMs"; + + public static final Map MAP_TIMEOUT = Map.of(DeployState.DEPLOYING, DEPLOY_TIMEOUT, + DeployState.UNDEPLOYING, UNDEPLOY_TIMEOUT, + DeployState.UPDATING, UPDATE_TIMEOUT, + DeployState.MIGRATING, MIGRATE_TIMEOUT, + DeployState.DELETING, DELETE_TIMEOUT); /** * Get the First StartPhase. @@ -112,6 +126,42 @@ public final class ParticipantUtils { return Set.of(0); } + /** + * Get timeout value from properties by name operation, return default value if not present. + * + * @param properties instance properties + * @param name the operation name + * @param defaultValue the default value + * @return the timeout value + */ + public static long getTimeout(Map properties, String name, long defaultValue) { + var objTimeout = properties.get(name); + if (objTimeout != null) { + return Long.parseLong(objTimeout.toString()); + } + return defaultValue; + } + + /** + * Get operation name of a composition definition. + * + * @param state the state of the composition definition + * @return the operation name + */ + public static String getOpName(AcTypeState state) { + return AcTypeState.PRIMING.equals(state) ? PRIME_TIMEOUT : DEPRIME_TIMEOUT; + } + + /** + * Get operation name of a AutomationComposition. + * + * @param deployState the state of the AutomationComposition + * @return the operation name + */ + public static String getOpName(DeployState deployState) { + return MAP_TIMEOUT.getOrDefault(deployState, DEFAULT_TIMEOUT); + } + /** * Finds stage from a map of properties for Migrate. * diff --git a/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtilsTest.java b/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtilsTest.java index 3f692b5ac..c460d4deb 100644 --- a/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtilsTest.java +++ b/models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtilsTest.java @@ -21,6 +21,7 @@ package org.onap.policy.clamp.models.acm.concepts; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Map; import org.junit.jupiter.api.Test; @@ -151,4 +152,34 @@ class ParticipantUtilsTest { result = ParticipantUtils.findStageSetMigrate(map); assertThat(result).hasSize(2).contains(2).contains(3); } + + @Test + void testGetTimeout() { + var result = ParticipantUtils.getTimeout(Map.of(), ParticipantUtils.DEPLOY_TIMEOUT, 1000); + assertEquals(1000, result); + + result = ParticipantUtils.getTimeout(Map.of(ParticipantUtils.DEPLOY_TIMEOUT, 20000), + ParticipantUtils.DEPLOY_TIMEOUT, 1000); + assertEquals(20000, result); + } + + @Test + void testGetOpName() { + var result = ParticipantUtils.getOpName(AcTypeState.PRIMING); + assertEquals(ParticipantUtils.PRIME_TIMEOUT, result); + result = ParticipantUtils.getOpName(AcTypeState.DEPRIMING); + assertEquals(ParticipantUtils.DEPRIME_TIMEOUT, result); + result = ParticipantUtils.getOpName(DeployState.DEPLOYING); + assertEquals(ParticipantUtils.DEPLOY_TIMEOUT, result); + result = ParticipantUtils.getOpName(DeployState.UNDEPLOYING); + assertEquals(ParticipantUtils.UNDEPLOY_TIMEOUT, result); + result = ParticipantUtils.getOpName(DeployState.UPDATING); + assertEquals(ParticipantUtils.UPDATE_TIMEOUT, result); + result = ParticipantUtils.getOpName(DeployState.DELETING); + assertEquals(ParticipantUtils.DELETE_TIMEOUT, result); + result = ParticipantUtils.getOpName(DeployState.MIGRATING); + assertEquals(ParticipantUtils.MIGRATE_TIMEOUT, result); + result = ParticipantUtils.getOpName(DeployState.DEPLOYED); + assertEquals(ParticipantUtils.DEFAULT_TIMEOUT, result); + } } diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AbstractScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AbstractScanner.java index a4c05ce0f..655abcde9 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AbstractScanner.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AbstractScanner.java @@ -25,6 +25,7 @@ import org.onap.policy.clamp.acm.runtime.main.utils.EncryptionUtils; import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublisher; import org.onap.policy.clamp.models.acm.concepts.AutomationComposition; import org.onap.policy.clamp.models.acm.concepts.DeployState; +import org.onap.policy.clamp.models.acm.concepts.ParticipantUtils; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.concepts.SubState; import org.onap.policy.clamp.models.acm.persistence.provider.AutomationCompositionProvider; @@ -96,9 +97,14 @@ public abstract class AbstractScanner { saveAndSync(automationComposition, updateSync); return; } + var name = ParticipantUtils.getOpName(automationComposition.getDeployState()); + var element = automationComposition.getElements().values().stream() + .filter(el -> automationComposition.getDeployState().equals(el.getDeployState())).findFirst(); + var maxWaitMs = element.map(automationCompositionElement -> ParticipantUtils.getTimeout( + automationCompositionElement.getProperties(), name, maxOperationWaitMs)).orElse(maxOperationWaitMs); var now = TimestampHelper.nowEpochMilli(); var lastMsg = TimestampHelper.toEpochMilli(automationComposition.getLastMsg()); - if ((now - lastMsg) > maxOperationWaitMs) { + if ((now - lastMsg) > maxWaitMs) { LOGGER.debug("Report timeout for the ac instance {}", automationComposition.getInstanceId()); automationComposition.setStateChangeResult(StateChangeResult.TIMEOUT); updateSync.setUpdated(true); diff --git a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScanner.java b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScanner.java index e390dfab4..1502da8b2 100644 --- a/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScanner.java +++ b/runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScanner.java @@ -24,6 +24,7 @@ import org.onap.policy.clamp.acm.runtime.main.parameters.AcRuntimeParameterGroup import org.onap.policy.clamp.acm.runtime.supervision.comm.ParticipantSyncPublisher; 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.ParticipantUtils; import org.onap.policy.clamp.models.acm.concepts.StateChangeResult; import org.onap.policy.clamp.models.acm.document.concepts.DocMessage; import org.onap.policy.clamp.models.acm.persistence.provider.AcDefinitionProvider; @@ -143,9 +144,12 @@ public class AcDefinitionScanner { LOGGER.debug("The ac definition is in timeout {}", acDefinition.getCompositionId()); return result; } - var now = TimestampHelper.nowEpochMilli(); + var name = ParticipantUtils.getOpName(acDefinition.getState()); + var maxWaitMs = ParticipantUtils + .getTimeout(acDefinition.getServiceTemplate().getMetadata(), name, maxOperationWaitMs); var lastMsg = TimestampHelper.toEpochMilli(acDefinition.getLastMsg()); - if ((now - lastMsg) > maxOperationWaitMs) { + var now = TimestampHelper.nowEpochMilli(); + if ((now - lastMsg) > maxWaitMs) { LOGGER.debug("Report timeout for the ac definition {}", acDefinition.getCompositionId()); acDefinition.setStateChangeResult(StateChangeResult.TIMEOUT); result.setUpdated(true); 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 2f75ba0ad..dd015b968 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 @@ -67,6 +67,7 @@ class SupervisionScannerTest { private AutomationCompositionDefinition createAutomationCompositionDefinition(AcTypeState acTypeState) { var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); + serviceTemplate.setMetadata(Map.of("compositionId", COMPOSITION_ID)); var acDefinition = new AutomationCompositionDefinition(); acDefinition.setState(acTypeState); acDefinition.setStateChangeResult(StateChangeResult.NO_ERROR); diff --git a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScannerTest.java b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScannerTest.java index 66c471521..fbdcb1f15 100644 --- a/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScannerTest.java +++ b/runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScannerTest.java @@ -158,6 +158,7 @@ class AcDefinitionScannerTest { private AutomationCompositionDefinition createAutomationCompositionDefinition(AcTypeState acTypeState, StateChangeResult stateChangeResult) { var serviceTemplate = InstantiationUtils.getToscaServiceTemplate(TOSCA_SERVICE_TEMPLATE_YAML); + serviceTemplate.setMetadata(Map.of("compositionId", COMPOSITION_ID)); var acDefinition = new AutomationCompositionDefinition(); acDefinition.setState(acTypeState); acDefinition.setStateChangeResult(stateChangeResult); diff --git a/runtime-acm/src/test/resources/rest/acm/AutomationComposition.json b/runtime-acm/src/test/resources/rest/acm/AutomationComposition.json index 0e6988d9b..b8fa8b25b 100644 --- a/runtime-acm/src/test/resources/rest/acm/AutomationComposition.json +++ b/runtime-acm/src/test/resources/rest/acm/AutomationComposition.json @@ -14,7 +14,12 @@ }, "deployState": "UNDEPLOYED", "lockState": "NONE", - "description": "Automation composition element for the K8S microservice for PMSH" + "description": "Automation composition element for the K8S microservice for PMSH", + "deployTimeoutMs": "200000", + "undeployTimeoutMs": "150000", + "updateTimeoutMs": "200000", + "migrateTimeoutMs": "200000", + "deleteTimeoutMs": "100000" }, "709c62b3-8918-41b9-a747-d21eb79c6c21": { "id": "709c62b3-8918-41b9-a747-d21eb79c6c21", @@ -24,7 +29,12 @@ }, "deployState": "UNDEPLOYED", "lockState": "NONE", - "description": "Automation composition element for the http requests of PMSH microservice" + "description": "Automation composition element for the http requests of PMSH microservice", + "deployTimeoutMs": "200000", + "undeployTimeoutMs": "150000", + "updateTimeoutMs": "200000", + "migrateTimeoutMs": "200000", + "deleteTimeoutMs": "100000" }, "709c62b3-8918-41b9-a747-d21eb79c6c22": { "id": "709c62b3-8918-41b9-a747-d21eb79c6c22", @@ -34,7 +44,12 @@ }, "deployState": "UNDEPLOYED", "lockState": "NONE", - "description": "Automation composition element for the operational policy for Performance Management Subscription Handling" + "description": "Automation composition element for the operational policy for Performance Management Subscription Handling", + "deployTimeoutMs": "200000", + "undeployTimeoutMs": "150000", + "updateTimeoutMs": "200000", + "migrateTimeoutMs": "200000", + "deleteTimeoutMs": "100000" } } } -- 2.16.6