summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhh <jorge.hernandez-herrero@att.com>2021-01-11 07:39:17 -0600
committerjhh <jorge.hernandez-herrero@att.com>2021-01-11 07:39:17 -0600
commitb73ceb906a6b8feabe88383ed35121dffbc20201 (patch)
tree1ad749ff10e6d9abadc8a74b6280443ab88b3230
parenta4e03e4efd11858f4ea69ea97c4c273e0792daa4 (diff)
sort deploy and undeploy policy lists
An order is imposed in the deployment and undeployment actions when the list of active policies is retrieved from PAP. This is to ensure that the operations are applied in a sane way, for example to try to prevent to undeploy policies before deleting a controller, etc .. The deployment order is 1) native controller, 2) native rule, and 3) non-native policies. The undeployment order is 1) non-native, 2) native rule, and 3) native controller policies. Issue-ID: POLICY-2762 Signed-off-by: jhh <jorge.hernandez-herrero@att.com> Change-Id: Icb15dcec87fd5d9917ee152ab15ca7277e13590a
-rw-r--r--feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java66
-rw-r--r--feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java172
2 files changed, 235 insertions, 3 deletions
diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java
index ef47e1d6..5478136f 100644
--- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java
+++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* ONAP
* ================================================================================
- * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
* Modifications Copyright (C) 2021 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +22,7 @@
package org.onap.policy.drools.lifecycle;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -347,13 +348,61 @@ public class LifecycleFsm implements Startable {
protected List<ToscaPolicy> getDeployablePoliciesAction(@NonNull List<ToscaPolicy> policies) {
List<ToscaPolicy> deployPolicies = new ArrayList<>(policies);
deployPolicies.removeAll(policiesMap.values());
- return deployPolicies;
+
+ // Ensure that the sequence of policy deployments is sane to minimize potential errors,
+ // First policies to deploy are the controller related ones, those that affect the lifecycle of
+ // controllers, starting with the ones that affect the existence of the controller (native controller),
+ // second the ones that "brain" the controller with application logic (native artifacts).
+ // Lastly the application specific ones such as operational policies.
+
+ // group policies by policy types
+ Map<String, List<ToscaPolicy>> policyTypeGroups = groupPoliciesByPolicyType(deployPolicies);
+
+ // place native controller policies at the start of the list
+ List<ToscaPolicy> orderedDeployableList =
+ new ArrayList<>(policyTypeGroups.getOrDefault(POLICY_TYPE_DROOLS_NATIVE_CONTROLLER.getName(),
+ Collections.EMPTY_LIST));
+
+ // add to the working list the native controller policies
+ orderedDeployableList.addAll(
+ policyTypeGroups.getOrDefault(POLICY_TYPE_DROOLS_NATIVE_RULES.getName(), Collections.EMPTY_LIST));
+
+ // place non-native policies to place at the end of the list
+ orderedDeployableList.addAll(getNonNativePolicies(policyTypeGroups));
+
+ return orderedDeployableList;
}
protected List<ToscaPolicy> getUndeployablePoliciesAction(@NonNull List<ToscaPolicy> policies) {
List<ToscaPolicy> undeployPolicies = new ArrayList<>(policiesMap.values());
undeployPolicies.removeAll(policies);
- return undeployPolicies;
+ if (undeployPolicies.isEmpty()) {
+ return undeployPolicies;
+ }
+
+ // Ensure that the sequence of policy undeployments is sane to minimize potential errors,
+ // as it is assumed not smart ordering from the policies sent by the PAP.
+ // First policies to undeploy are those that are only of relevance within a drools container,
+ // such as the operational policies. The next set of policies to undeploy are those that
+ // affect the overall PDP-D application support, firstly the ones that supports the
+ // application software wiring (native rules policies), and second those that relate
+ // to the PDP-D controllers lifecycle.
+
+ // group policies by policy types
+ Map<String, List<ToscaPolicy>> policyTypeGroups = groupPoliciesByPolicyType(undeployPolicies);
+
+ // place controller only (non-native policies) at the start of the list of the undeployment list
+ List<ToscaPolicy> orderedUndeployableList = getNonNativePolicies(policyTypeGroups);
+
+ // add to the working list the native rules policies if any
+ orderedUndeployableList.addAll(
+ policyTypeGroups.getOrDefault(POLICY_TYPE_DROOLS_NATIVE_RULES.getName(), Collections.EMPTY_LIST));
+
+ // finally add to the working list native controller policies if any
+ orderedUndeployableList.addAll(
+ policyTypeGroups.getOrDefault(POLICY_TYPE_DROOLS_NATIVE_CONTROLLER.getName(), Collections.EMPTY_LIST));
+
+ return orderedUndeployableList;
}
protected void deployedPolicyAction(@NonNull ToscaPolicy policy) {
@@ -378,6 +427,17 @@ public class LifecycleFsm implements Startable {
return policyTypesMap.get(policyType);
}
+ protected Map<String, List<ToscaPolicy>> groupPoliciesByPolicyType(List<ToscaPolicy> deployPolicies) {
+ return deployPolicies.stream().collect(Collectors.groupingBy(policy -> policy.getTypeIdentifier().getName()));
+ }
+
+ protected List<ToscaPolicy> getNonNativePolicies(@NonNull Map<String, List<ToscaPolicy>> policyTypeGroups) {
+ return policyTypeGroups.entrySet().stream()
+ .filter(entry -> !entry.getKey().equals(POLICY_TYPE_DROOLS_NATIVE_RULES.getName())
+ && !entry.getKey().equals(POLICY_TYPE_DROOLS_NATIVE_CONTROLLER.getName()))
+ .flatMap(entry -> entry.getValue().stream()).collect(Collectors.toList());
+ }
+
/**
* Do I support the mandatory policy types?.
*/
diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java
new file mode 100644
index 00000000..b5c4f1b5
--- /dev/null
+++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/LifecycleFsmTest.java
@@ -0,0 +1,172 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * =============LICENSE_END========================================================
+ */
+
+package org.onap.policy.drools.lifecycle;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.common.utils.time.PseudoScheduledExecutorService;
+import org.onap.policy.common.utils.time.TestTimeMulti;
+import org.onap.policy.drools.persistence.SystemPersistenceConstants;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+
+/**
+ * Lifecycle FSM Test.
+ */
+public class LifecycleFsmTest {
+
+ private static final String EXAMPLE_NATIVE_CONTROLLER_POLICY_NAME = "example.controller";
+ private static final String EXAMPLE_NATIVE_CONTROLLER_POLICY_JSON =
+ "src/test/resources/tosca-policy-native-controller-example.json";
+
+ private static final String EXAMPLE_NATIVE_ARTIFACT_POLICY_NAME = "example.artifact";
+ private static final String EXAMPLE_NATIVE_ARTIFACT_POLICY_JSON =
+ "src/test/resources/tosca-policy-native-artifact-example.json";
+
+ private static final String EXAMPLE_OTHER_UNVAL_POLICY_NAME = "other-unvalidated";
+ private static final String EXAMPLE_OTHER_UNVAL_POLICY_JSON =
+ "src/test/resources/tosca-policy-other-unvalidated.json";
+
+ private static final String EXAMPLE_OTHER_VAL_POLICY_NAME = "other-validated";
+ private static final String EXAMPLE_OTHER_VAL_POLICY_JSON =
+ "src/test/resources/tosca-policy-other-validated.json";
+
+ private static final String VCPE_OP_POLICY_NAME = "operational.restart";
+ private static final String VCPE_OPERATIONAL_DROOLS_POLICY_JSON =
+ "policies/vCPE.policy.operational.input.tosca.json";
+
+ private static final String VFW_OP_POLICY_NAME = "operational.modifyconfig";
+ private static final String VFW_OPERATIONAL_DROOLS_POLICY_JSON =
+ "policies/vFirewall.policy.operational.input.tosca.json";
+
+ private static final String USECASES_NATIVE_CONTROLLER_POLICY_NAME = "usecases";
+ private static final String USECASES_NATIVE_CONTROLLER_JSON =
+ "policies/usecases.native.controller.policy.input.tosca.json";
+
+ private static final String USECASES_NATIVE_ARTIFACT_POLICY_NAME = "usecases.artifacts";
+ private static final String USECASES_NATIVE_ARTIFACT_JSON =
+ "policies/usecases.native.artifact.policy.input.tosca.json";
+
+ private static final StandardCoder coder = new StandardCoder();
+
+ protected LifecycleFsm fsm;
+ private ToscaPolicy opPolicy;
+ private ToscaPolicy op2Policy;
+ private ToscaPolicy valPolicy;
+ private ToscaPolicy unvalPolicy;
+ private ToscaPolicy controllerPolicy;
+ private ToscaPolicy controller2Policy;
+ private ToscaPolicy artifactPolicy;
+ private ToscaPolicy artifact2Policy;
+
+ /**
+ * Test initialization.
+ */
+ @Before
+ public void init() throws CoderException, IOException {
+ LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "INFO");
+ LoggerUtil.setLevel("org.onap.policy.common.endpoints", "WARN");
+ LoggerUtil.setLevel("org.onap.policy.drools", "INFO");
+ SystemPersistenceConstants.getManager().setConfigurationDir("target/test-classes");
+
+ fsm = new LifecycleFsm() {
+ @Override
+ protected ScheduledExecutorService makeExecutor() {
+ return new PseudoScheduledExecutorService(new TestTimeMulti());
+ }
+ };
+
+ opPolicy = getExamplesPolicy(VFW_OPERATIONAL_DROOLS_POLICY_JSON, VFW_OP_POLICY_NAME);
+ op2Policy = getExamplesPolicy(VCPE_OPERATIONAL_DROOLS_POLICY_JSON, VCPE_OP_POLICY_NAME);
+ controllerPolicy =
+ getPolicyFromFile(EXAMPLE_NATIVE_CONTROLLER_POLICY_JSON, EXAMPLE_NATIVE_CONTROLLER_POLICY_NAME);
+ controller2Policy = getExamplesPolicy(USECASES_NATIVE_CONTROLLER_JSON, USECASES_NATIVE_CONTROLLER_POLICY_NAME);
+ artifactPolicy =
+ getPolicyFromFile(EXAMPLE_NATIVE_ARTIFACT_POLICY_JSON, EXAMPLE_NATIVE_ARTIFACT_POLICY_NAME);
+ artifact2Policy = getExamplesPolicy(USECASES_NATIVE_ARTIFACT_JSON, USECASES_NATIVE_ARTIFACT_POLICY_NAME);
+ valPolicy =
+ getPolicyFromFile(EXAMPLE_OTHER_VAL_POLICY_JSON, EXAMPLE_OTHER_VAL_POLICY_NAME);
+ unvalPolicy =
+ getPolicyFromFile(EXAMPLE_OTHER_UNVAL_POLICY_JSON, EXAMPLE_OTHER_UNVAL_POLICY_NAME);
+ }
+
+ @Test
+ public void testGetDeployableActions() {
+ List<ToscaPolicy> expectedDeployOrder =
+ List.of(controllerPolicy, controller2Policy, artifact2Policy, artifactPolicy,
+ op2Policy, opPolicy, unvalPolicy, valPolicy);
+
+ assertEquals(expectedDeployOrder, fsm.getDeployablePoliciesAction(expectedDeployOrder));
+ assertEquals(expectedDeployOrder,
+ fsm.getDeployablePoliciesAction(
+ List.of(op2Policy, artifact2Policy, valPolicy, opPolicy, unvalPolicy, artifactPolicy,
+ controllerPolicy, controller2Policy)));
+ assertEquals(expectedDeployOrder,
+ fsm.getDeployablePoliciesAction(
+ List.of(artifact2Policy, op2Policy, artifactPolicy, controllerPolicy, opPolicy,
+ controller2Policy, valPolicy, unvalPolicy)));
+ }
+
+ @Test
+ public void testGetUndeployableActions() {
+ fsm.deployedPolicyAction(controllerPolicy);
+ fsm.deployedPolicyAction(controller2Policy);
+ fsm.deployedPolicyAction(artifactPolicy);
+ fsm.deployedPolicyAction(artifact2Policy);
+ fsm.deployedPolicyAction(opPolicy);
+ fsm.deployedPolicyAction(valPolicy);
+ fsm.deployedPolicyAction(unvalPolicy);
+ fsm.deployedPolicyAction(op2Policy);
+
+ List<ToscaPolicy> expectedUndeployOrder =
+ List.of(opPolicy, op2Policy, unvalPolicy, valPolicy, artifactPolicy,
+ artifact2Policy, controller2Policy, controllerPolicy);
+
+ assertEquals(expectedUndeployOrder, fsm.getUndeployablePoliciesAction(Collections.EMPTY_LIST));
+ assertEquals(expectedUndeployOrder, fsm.getUndeployablePoliciesAction(Collections.EMPTY_LIST));
+ assertEquals(expectedUndeployOrder, fsm.getUndeployablePoliciesAction(Collections.EMPTY_LIST));
+ }
+
+ protected ToscaPolicy getPolicyFromFile(String filePath, String policyName) throws CoderException, IOException {
+ String policyJson = Files.readString(Paths.get(filePath));
+ ToscaServiceTemplate serviceTemplate = coder.decode(policyJson, ToscaServiceTemplate.class);
+ return serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).get(policyName);
+ }
+
+ protected ToscaPolicy getExamplesPolicy(String resourcePath, String policyName) throws CoderException {
+ String policyJson = ResourceUtils.getResourceAsString(resourcePath);
+ ToscaServiceTemplate serviceTemplate = new StandardCoder().decode(policyJson, ToscaServiceTemplate.class);
+ return serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).get(policyName);
+ }
+
+} \ No newline at end of file