Make a configurable timeout for operations in ACM-R 79/141179/1
authorFrancescoFioraEst <francesco.fiora@est.tech>
Tue, 10 Jun 2025 10:36:50 +0000 (11:36 +0100)
committerFrancescoFioraEst <francesco.fiora@est.tech>
Tue, 10 Jun 2025 10:38:23 +0000 (11:38 +0100)
Issue-ID: POLICY-5370
Change-Id: I10f64c1ccdeb5ed0e6cfaaf3b2d63eb9d956f85e
Signed-off-by: FrancescoFioraEst <francesco.fiora@est.tech>
examples/src/main/resources/clamp/acm/pmsh/funtional-pmsh-usecase.yaml
models/src/main/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtils.java
models/src/test/java/org/onap/policy/clamp/models/acm/concepts/ParticipantUtilsTest.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AbstractScanner.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScanner.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/SupervisionScannerTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/supervision/scanner/AcDefinitionScannerTest.java
runtime-acm/src/test/resources/rest/acm/AutomationComposition.json

index 4587e31..3896dfa 100644 (file)
@@ -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
index 5cb5d3f..ded715b 100644 (file)
@@ -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<DeployState, String> 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<String, Object> 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.
      *
index 3f692b5..c460d4d 100644 (file)
@@ -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);
+    }
 }
index a4c05ce..655abcd 100644 (file)
@@ -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);
index e390dfa..1502da8 100644 (file)
@@ -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);
index 2f75ba0..dd015b9 100644 (file)
@@ -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);
index 66c4715..fbdcb1f 100644 (file)
@@ -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);
index 0e6988d..b8fa8b2 100644 (file)
             },
             "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",
             },
             "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",
             },
             "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"
         }
     }
 }