Sync controller capabilities as controllers bounce 61/104861/4
authorjhh <jorge.hernandez-herrero@att.com>
Wed, 1 Apr 2020 02:05:14 +0000 (21:05 -0500)
committerjhh <jorge.hernandez-herrero@att.com>
Wed, 1 Apr 2020 15:59:29 +0000 (10:59 -0500)
As native policies introduce temporality in policy types
supported as they are removed and added, the associated
policy types that can be honored at a a given time, may
need to adjust.

A significan portion of this review is dedicated to multi-policy
junits and telemetry instrumentation.

Issue-ID: POLICY-2459
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
Change-Id: I62bbc03411446849eaa55c9b1524220dc13c2cb0
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java
feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java
feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsController.java
feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsController.java
feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java
feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java
feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java
feature-lifecycle/src/test/resources/lifecycle.kmodule
policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java
policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java

index d920597..12828e0 100644 (file)
@@ -23,6 +23,7 @@ package org.onap.policy.drools.lifecycle;
 import org.onap.policy.drools.features.DroolsControllerFeatureApi;
 import org.onap.policy.drools.features.PolicyControllerFeatureApi;
 import org.onap.policy.drools.features.PolicyEngineFeatureApi;
+import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
 import org.onap.policy.drools.system.PolicyController;
 import org.onap.policy.drools.system.PolicyEngine;
 
@@ -52,7 +53,9 @@ public class LifecycleFeature
     }
 
     @Override
-    public boolean afterPatch(PolicyController controller, boolean success) {
+    public boolean afterPatch(
+        PolicyController controller, DroolsConfiguration oldConfiguration,
+        DroolsConfiguration newConfiguration, boolean success) {
         return fsmPatch(controller);
     }
 
index 3ecb4b3..ac76883 100644 (file)
@@ -31,6 +31,7 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.Setter;
@@ -189,6 +190,7 @@ public class LifecycleFsm implements Startable {
                 PolicyTypeDroolsController ptDroolsController = (PolicyTypeDroolsController) policyTypesMap.get(id);
                 if (ptDroolsController == null) {
                     policyTypesMap.put(id, new PolicyTypeDroolsController(this, id, controller));
+                    logger.info("policy-type {} added", id);
                 } else {
                     ptDroolsController.add(controller);
                 }
@@ -219,14 +221,19 @@ public class LifecycleFsm implements Startable {
      */
     public synchronized void stop(@NonNull PolicyController controller) {
         logger.info("lifecycle event: stop controller: {}", controller.getName());
-        for (ToscaPolicyTypeIdentifier id : controller.getPolicyTypes()) {
-            if (!policyTypesMap.containsKey(id)) {
-                continue;
-            }
-            PolicyTypeDroolsController ptDroolsController = (PolicyTypeDroolsController) policyTypesMap.get(id);
-            ptDroolsController.remove(controller);
-            if (ptDroolsController.controllers().isEmpty()) {
-                policyTypesMap.remove(id);
+
+        List<PolicyTypeDroolsController> opControllers =
+            policyTypesMap.values().stream()
+                .filter(typeController -> typeController instanceof PolicyTypeDroolsController)
+                .map(typeController -> (PolicyTypeDroolsController) typeController)
+                .filter(opController -> opController.getControllers().containsKey(controller.getName()))
+                .collect(Collectors.toList());
+
+        for (PolicyTypeDroolsController opController : opControllers) {
+            opController.remove(controller);
+            if (opController.controllers().isEmpty()) {
+                policyTypesMap.remove(opController.getPolicyType());
+                logger.info("policy-type {} removed", opController.getPolicyType());
             }
         }
     }
index 2772d85..8dfbf2f 100644 (file)
@@ -52,6 +52,7 @@ public class PolicyTypeDroolsController implements PolicyTypeController {
 
     private static final Logger logger = LoggerFactory.getLogger(PolicyTypeController.class);
 
+    @Getter
     protected final Map<String, PolicyController> controllers = new ConcurrentHashMap<>();
 
     @Getter
index 8255c02..e74b289 100644 (file)
@@ -84,14 +84,23 @@ public class PolicyTypeNativeDroolsController implements PolicyTypeController {
 
         PolicyController controller;
         try {
-            controller = PolicyEngineConstants.getManager()
-                                 .createPolicyController(controllerConfig.getControllerName(), controllerProps);
+            controller =
+                PolicyEngineConstants.getManager()
+                    .createPolicyController(controllerConfig.getControllerName(), controllerProps);
         } catch (RuntimeException e) {
-            logger.warn("failed deploy (cannot create controller) for policy: {}", policy);
+            logger.warn("failed deploy (cannot create controller) for policy: {}", policy, e);
             return false;
         }
 
-        return controller != null;
+        try {
+            controller.start();
+        } catch (RuntimeException e) {
+            logger.warn("failed deploy (cannot start ontroller) for policy: {}", policy, e);
+            PolicyEngineConstants.getManager().removePolicyController(controller);
+            return false;
+        }
+
+        return true;
     }
 
     @Override
index 3e55a10..5c8f9dc 100644 (file)
@@ -21,9 +21,13 @@ package org.onap.policy.drools.server.restful;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import java.util.List;
 import java.util.Properties;
+import java.util.stream.Collectors;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -33,12 +37,18 @@ import javax.ws.rs.core.Response;
 import org.onap.policy.common.endpoints.event.comm.TopicSink;
 import org.onap.policy.common.endpoints.event.comm.TopicSource;
 import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.drools.lifecycle.LifecycleFeature;
 import org.onap.policy.drools.lifecycle.PolicyTypeController;
 import org.onap.policy.models.pdp.concepts.PdpStateChange;
+import org.onap.policy.models.pdp.concepts.PdpUpdate;
 import org.onap.policy.models.pdp.enums.PdpState;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * REST Lifecycle Manager.
@@ -50,6 +60,10 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifi
 @Api
 public class RestLifecycleManager {
 
+    private static final Logger logger = LoggerFactory.getLogger(RestLifecycleManager.class);
+
+    private static final StandardCoder coder = new StandardCoder();
+
     /**
      * GET group.
      */
@@ -213,16 +227,23 @@ public class RestLifecycleManager {
      */
 
     @GET
-    @Path("policyTypes/{policyType}/{policyVersion}")
+    @Path("policyTypes/{policyType}/{policyTypeVersion}")
     @ApiOperation(value = "Entities associated with a policy type",
             notes = "Lifecycle policy Types", response = PolicyTypeController.class)
     public Response policyType(
-        @ApiParam(value = "Policy Type", required = true) @PathParam("policyType") String policyType,
-        @ApiParam(value = "Policy Type Version", required = true) @PathParam("policyVersion") String policyVersion) {
+        @ApiParam(value = "Policy Type", required = true)
+            @PathParam("policyType") String policyType,
+        @ApiParam(value = "Policy Type Version", required = true)
+            @PathParam("policyTypeVersion") String policyTypeVersion) {
+        PolicyTypeController typeController =
+            LifecycleFeature.fsm.getPolicyTypesMap()
+                    .get(new ToscaPolicyTypeIdentifier(policyType, policyTypeVersion));
+        if (typeController == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
         return Response.status(Response.Status.OK)
-                       .entity(LifecycleFeature.fsm
-                                .getPolicyTypesMap()
-                                .get(new ToscaPolicyTypeIdentifier(policyType, policyVersion)))
+                       .entity(typeController)
                        .build();
     }
 
@@ -232,8 +253,7 @@ public class RestLifecycleManager {
 
     @GET
     @Path("policies")
-    @ApiOperation(value = "List of tracked policies",
-            notes = "Lifecycle Policies", responseContainer = "List")
+    @ApiOperation(value = "List of policies", responseContainer = "List")
     public Response policies() {
         return Response.status(Response.Status.OK)
                        .entity(LifecycleFeature.fsm.getPoliciesMap().keySet())
@@ -241,29 +261,161 @@ public class RestLifecycleManager {
 
     }
 
+    /**
+     * POST a Policy.
+     */
+
+    @POST
+    @Path("policies")
+    @ApiOperation(value = "Deploy a policy", response = Boolean.class)
+    public Response deployTrackedPolicy(
+            @ApiParam(value = "Tosca Policy", required = true) String policy) {
+
+        ToscaPolicy toscaPolicy = getToscaPolicy(policy);
+        if (toscaPolicy == null) {
+            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+        }
+
+        PolicyTypeController typeController = getPolicyTypeController(toscaPolicy);
+        if (typeController == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        List<ToscaPolicy> policies =
+                LifecycleFeature.fsm.getPoliciesMap().values().stream().collect(Collectors.toList());
+        policies.add(toscaPolicy);
+        return Response.status(Response.Status.OK)
+                       .entity(LifecycleFeature.fsm.update(getPolicyUpdate(policies)))
+                       .build();
+    }
+
     /**
      * GET a policy.
      */
 
     @GET
-    @Path("policies/{policy}/{policyVersion}")
-    @ApiOperation(value = "Lifecycle tracked policy",
-            notes = "Lifecycle Tracked Policy", response = ToscaPolicy.class)
+    @Path("policies/{policyName}/{policyVersion}")
+    @ApiOperation(value = "Retrieves a policy", response = ToscaPolicy.class)
     public Response policy(
+            @ApiParam(value = "Policy Name", required = true) @PathParam("policyName") String policyName,
+            @ApiParam(value = "Policy Version", required = true) @PathParam("policyVersion") String policyVersion) {
+
+        ToscaPolicy policy;
+        try {
+            policy =
+                LifecycleFeature.fsm.getPoliciesMap().get(new ToscaPolicyIdentifier(policyName, policyVersion));
+        } catch (RuntimeException r) {
+            logger.debug("policy {}:{} has not been found", policyName, policyVersion, r);
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        if (policy == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        return Response.status(Response.Status.OK).entity(policy).build();
+    }
+
+    /**
+     * DELETE a policy.
+     */
+
+    @DELETE
+    @Path("policies/{policyName}/{policyVersion}")
+    @ApiOperation(value = "Deletes a Lifecycle tracked policy", response = Boolean.class)
+    public Response undeployPolicy(
             @ApiParam(value = "Policy", required = true) @PathParam("policyName") String policyName,
             @ApiParam(value = "Policy Version", required = true) @PathParam("policyVersion") String policyVersion) {
 
-        ToscaPolicy policy = LifecycleFeature.fsm
-                                     .getPoliciesMap()
-                                     .get(new ToscaPolicyTypeIdentifier(policyName, policyVersion));
-        if (policy != null) {
-            return
-                Response.status(Response.Status.OK)
-                        .entity(LifecycleFeature.fsm.getPolicyTypesMap()
-                                        .get(new ToscaPolicyTypeIdentifier(policyName, policyVersion)))
-                        .build();
+        ToscaPolicy policy;
+        try {
+            policy =
+                LifecycleFeature.fsm.getPoliciesMap().get(new ToscaPolicyIdentifier(policyName, policyVersion));
+        } catch (RuntimeException r) {
+            logger.debug("policy {}:{} has not been found", policyName, policyVersion, r);
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        if (policy == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        List<ToscaPolicy> policies =
+                LifecycleFeature.fsm.getPoliciesMap().values().stream().collect(Collectors.toList());
+        policies.removeIf(aPolicy -> policy.getIdentifier().equals(aPolicy.getIdentifier()));
+        return Response.status(Response.Status.OK)
+                       .entity(LifecycleFeature.fsm.update(getPolicyUpdate(policies)))
+                       .build();
+    }
+
+    /**
+     * List of policies individual Operations supported.
+     */
+
+    @GET
+    @Path("policies/operations")
+    @ApiOperation(value = "Gets Policy Operations", responseContainer = "List")
+    public Response policiesOperations() {
+        return Response.status(Response.Status.OK).entity(List.of("deployment", "undeployment")).build();
+    }
+
+    /**
+     * POST a deployment operation on a policy.
+     */
+
+    @POST
+    @Path("policies/operations/deployment")
+    @ApiOperation(value = "Deploys a policy", notes = "Deploys a policy", response = Boolean.class)
+    public Response deployOperation(@ApiParam(value = "Tosca Policy", required = true) String policy) {
+        return deployUndeployOperation(policy, true);
+    }
+
+    /**
+     * POST an undeployment operation on a policy.
+     */
+
+    @POST
+    @Path("policies/operations/undeployment")
+    @ApiOperation(value = "Undeploys a policy", response = Boolean.class)
+    public Response undeployOperation(@ApiParam(value = "Tosca Policy", required = true) String policy) {
+        return deployUndeployOperation(policy, false);
+    }
+
+    private Response deployUndeployOperation(String policy, boolean deploy) {
+        ToscaPolicy toscaPolicy = getToscaPolicy(policy);
+        if (toscaPolicy == null) {
+            return Response.status(Response.Status.NOT_ACCEPTABLE).build();
+        }
+
+        PolicyTypeController typeController = getPolicyTypeController(toscaPolicy);
+        if (typeController == null) {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+
+        return Response.status(Response.Status.OK)
+                       .entity((deploy) ? typeController.deploy(toscaPolicy) : typeController.undeploy(toscaPolicy))
+                       .build();
+    }
+
+    private ToscaPolicy getToscaPolicy(String policy) {
+        try {
+            return coder.decode(policy, ToscaPolicy.class);
+        } catch (CoderException | RuntimeException e) {
+            return null;
         }
+    }
+
+    private PolicyTypeController getPolicyTypeController(ToscaPolicy policy) {
+        return LifecycleFeature.fsm.getPolicyTypesMap().get(policy.getTypeIdentifier());
+    }
 
-        return Response.status(Response.Status.NOT_FOUND).build();
+    private PdpUpdate getPolicyUpdate(List<ToscaPolicy> policies) {
+        PdpUpdate update = new PdpUpdate();
+        update.setName(LifecycleFeature.fsm.getName());
+        update.setPdpGroup(LifecycleFeature.fsm.getGroup());
+        update.setPdpSubgroup(LifecycleFeature.fsm.getSubgroup());
+        update.setPolicies(policies);
+        return update;
     }
+
 }
index 9b673dd..1e9f1c6 100644 (file)
@@ -69,12 +69,7 @@ public class ControllerSupport {
             ;
         }
 
-        ReleaseId coordinates =
-            KieUtils.installArtifact(Paths.get(JUNIT_KMODULE_PATH).toFile(),
-                Paths.get(JUNIT_KMODULE_POM_PATH).toFile(),
-                JUNIT_KJAR_DRL_PATH,
-                Paths.get(JUNIT_KMODULE_DRL_PATH).toFile());
-
+        ReleaseId coordinates = installArtifact();
 
         Properties controllerProps = new Properties();
         controllerProps.put(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, name);
@@ -86,6 +81,17 @@ public class ControllerSupport {
         return PolicyControllerConstants.getFactory().build(name, controllerProps);
     }
 
+    /**
+     * install artifact.
+     */
+    public ReleaseId installArtifact() throws IOException {
+        return
+            KieUtils.installArtifact(Paths.get(JUNIT_KMODULE_PATH).toFile(),
+                Paths.get(JUNIT_KMODULE_POM_PATH).toFile(),
+                        JUNIT_KJAR_DRL_PATH,
+                        Paths.get(JUNIT_KMODULE_DRL_PATH).toFile());
+    }
+
     /**
      * Destroy the echo controller.
      */
index 511fcc9..2222399 100644 (file)
 
 package org.onap.policy.drools.server.restful;
 
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.List;
 import java.util.Properties;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import org.apache.commons.lang3.StringUtils;
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicFactories;
 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
 import org.onap.policy.common.endpoints.http.client.HttpClient;
 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
+import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.network.NetworkUtil;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.drools.lifecycle.ControllerSupport;
 import org.onap.policy.drools.lifecycle.LifecycleFeature;
+import org.onap.policy.drools.lifecycle.LifecycleFsm;
 import org.onap.policy.drools.persistence.SystemPersistenceConstants;
+import org.onap.policy.drools.system.PolicyControllerConstants;
+import org.onap.policy.drools.utils.logging.LoggerUtil;
 import org.onap.policy.models.pdp.enums.PdpState;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
 
 /**
  * REST Lifecycle Manager Test.
  */
 public class RestLifecycleManagerTest {
 
+    // Native Drools Policy
+    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 OP_POLICY_NAME_VCPE = "operational.restart";
+    private static final String VCPE_OPERATIONAL_DROOLS_POLICY_JSON =
+            "policies/vCPE.policy.operational.input.tosca.json";
+
+    private static StandardCoder coder = new StandardCoder();
+    private static ControllerSupport controllerSupport = new ControllerSupport("lifecycle");
+
+    private LifecycleFsm fsm;
+    private HttpClient client;
+
     /**
      * Set up.
      */
     @Before
      public void setUp() throws Exception {
+        SystemPersistenceConstants.getManager().setConfigurationDir("target/test-classes");
+        fsm = newFsmInstance();
+
+        LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, "INFO");
+        LoggerUtil.setLevel("org.onap.policy.common.endpoints", "WARN");
+        LoggerUtil.setLevel("org.onap.policy.drools", "INFO");
+
         HttpServletServerFactoryInstance.getServerFactory().destroy();
         HttpClientFactoryInstance.getClientFactory().destroy();
-
-        SystemPersistenceConstants.getManager().setConfigurationDir("target/test-classes");
+        PolicyControllerConstants.getFactory().destroy();
 
         HttpClientFactoryInstance.getClientFactory().build(
             BusTopicParams.builder()
@@ -70,8 +114,16 @@ public class RestLifecycleManagerTest {
         server.addServletClass("/*", RestLifecycleManager.class.getName());
         server.waitedStart(5000L);
 
-        Assert.assertTrue(NetworkUtil.isTcpPortOpen("localhost", 8765, 5, 10000L));
+        assertTrue(NetworkUtil.isTcpPortOpen("localhost", 8765, 5, 10000L));
+
+        controllerSupport.installArtifact();
 
+        Properties noopTopicProperties = new Properties();
+        noopTopicProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SOURCE_TOPICS, "DCAE_TOPIC");
+        noopTopicProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, "APPC-CL");
+        TopicEndpointManager.getManager().addTopics(noopTopicProperties);
+
+        client = HttpClientFactoryInstance.getClientFactory().get("lifecycle");
     }
 
     /**
@@ -79,88 +131,287 @@ public class RestLifecycleManagerTest {
      */
     @After
     public void tearDown() {
-        HttpServletServerFactoryInstance.getServerFactory().destroy();
+        fsm.shutdown();
+
+        NoopTopicFactories.getSourceFactory().destroy();
+        NoopTopicFactories.getSinkFactory().destroy();
+
         HttpClientFactoryInstance.getClientFactory().destroy();
+        HttpServletServerFactoryInstance.getServerFactory().destroy();
+
+        PolicyControllerConstants.getFactory().destroy();
+        SystemPersistenceConstants.getManager().setConfigurationDir(null);
     }
 
     @Test
-    public void testFsm() {
+    public void testMultiPolicyFlow() throws IOException, CoderException {
+        /* group assignments */
 
-        HttpClient client = HttpClientFactoryInstance.getClientFactory().get("lifecycle");
-        Response response;
+        group();
+        subgroup();
 
-        /* group */
+        /* other resources */
 
-        response = client.put("group/GG", Entity.json(""), Collections.emptyMap());
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals("GG", HttpClient.getBody(response, String.class));
+        properties();
+        topics();
 
-        response = HttpClientFactoryInstance.getClientFactory().get("lifecycle").get("group");
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(LifecycleFeature.fsm.getGroup(), HttpClient.getBody(response, String.class));
+        /* status interval */
 
-        /* subgroup */
+        status();
 
-        response = client.put("subgroup/YY", Entity.json(""), Collections.emptyMap());
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals("YY", HttpClient.getBody(response, String.class));
+        /* start up configuration */
 
-        response = client.get("subgroup");
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(LifecycleFeature.fsm.getSubgroup(), HttpClient.getBody(response, String.class));
+        resourceLists("policyTypes", 2);
+        get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.Operational/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
 
-        /* properties */
+        resourceLists("policies", 0);
+        get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode());
 
-        response = client.get("properties");
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(LifecycleFeature.fsm.getProperties(), HttpClient.getBody(response, Properties.class));
+        /* start lifecycle */
 
-        /* state (disallowed state change as has not been started) */
+        assertTrue(fsm.start());
 
-        response = client.put("state/PASSIVE", Entity.json(""), Collections.emptyMap());
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(Boolean.FALSE, HttpClient.getBody(response, Boolean.class));
+        booleanPut("state/ACTIVE", "", Status.OK.getStatusCode(), Boolean.TRUE);
+        assertEquals(PdpState.ACTIVE,
+                HttpClient.getBody(get("state", Status.OK.getStatusCode()), PdpState.class));
 
-        response = client.get("state");
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(PdpState.TERMINATED, HttpClient.getBody(response, PdpState.class));
+        /* add native controller policy */
 
-        /* topics */
+        ToscaPolicy nativeControllerPolicy =
+            getPolicyFromFile(EXAMPLE_NATIVE_CONTROLLER_POLICY_JSON, EXAMPLE_NATIVE_CONTROLLER_POLICY_NAME);
+        booleanPost("policies", toString(nativeControllerPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
 
-        assertEquals(Status.OK.getStatusCode(), client.get("topic/source").getStatus());
-        assertEquals(Status.OK.getStatusCode(), client.get("topic/sink").getStatus());
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
+        assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
+        assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive());
 
-        /* status interval */
+        get("policyTypes/onap.policies.controlloop.Operational/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
+
+        resourceLists("policies", 1);
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+
+        /* add native artifact policy */
+
+        ToscaPolicy nativeArtifactPolicy =
+            getPolicyFromFile(EXAMPLE_NATIVE_ARTIFACT_POLICY_JSON, EXAMPLE_NATIVE_ARTIFACT_POLICY_NAME);
+        booleanPost("policies", toString(nativeArtifactPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
+
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive());
+
+        /* verify new supported operational policy types */
+
+        resourceLists("policyTypes", 5);
+        get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.Operational/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.type1.type2/1.0.0", Status.OK.getStatusCode());
+
+        /* verify controller and artifact policies */
+
+        resourceLists("policies", 2);
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
+
+        /* add tosca compliant operational policy */
+
+        ToscaPolicy opPolicy = getExamplesPolicy(VCPE_OPERATIONAL_DROOLS_POLICY_JSON, OP_POLICY_NAME_VCPE);
+        opPolicy.getProperties().put("controllerName", "lifecycle");
+        if (StringUtils.isBlank(opPolicy.getName())) {
+            opPolicy.setName(opPolicy.getMetadata().get("policy-id"));
+        }
+
+        booleanPost("policies", toString(opPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
+        assertEquals(1,
+            PolicyControllerConstants
+                .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class) .size());
+
+        resourceLists("policies", 3);
+        get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.OK.getStatusCode());
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
+
+        booleanDelete("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(),
+                Status.OK.getStatusCode(), Boolean.TRUE);
+        assertEquals(0,
+            PolicyControllerConstants
+                .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class) .size());
 
-        response = client.put("status/interval/1000", Entity.json(""), Collections.emptyMap());
+        resourceLists("policies", 2);
+        get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
+
+        /* individual deploy/undeploy operations */
+
+        resourceLists("policies/operations", 2);
+
+        booleanPost("policies/operations/deployment", toString(opPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
+        assertEquals(1,
+            PolicyControllerConstants
+                .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class) .size());
+
+        resourceLists("policies", 2);
+        get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
+
+        booleanPost(
+                "policies/operations/undeployment", toString(opPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
+        assertEquals(0,
+            PolicyControllerConstants
+                .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class) .size());
+
+        resourceLists("policies", 2);
+        get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
+
+        /* delete native artifact policy */
+
+        booleanDelete("policies/example.artifact/1.0.0", Status.OK.getStatusCode(), Boolean.TRUE);
+        assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
+        assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
+
+        resourceLists("policyTypes", 2);
+        get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.Operational/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policyTypes/onap.policies.type1.type2/1.0.0", Status.NOT_FOUND.getStatusCode());
+
+        resourceLists("policies", 1);
+        get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
+
+        /* delete native controller policy */
+
+        booleanDelete("policies/example.controller/1.0.0", Status.OK.getStatusCode(), Boolean.TRUE);
+
+        resourceLists("policyTypes", 2);
+        get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.Operational/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policyTypes/onap.policies.type1.type2/1.0.0", Status.NOT_FOUND.getStatusCode());
+
+        resourceLists("policies", 0);
+        get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
+        get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode());
+        get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode());
+
+        assertThatIllegalArgumentException().isThrownBy(() -> PolicyControllerConstants.getFactory().get("lifecycle"));
+    }
+
+    private Response get(String contextPath, int statusCode) {
+        Response response = client.get(contextPath);
+        assertEquals(statusCode, response.getStatus());
+        return response;
+    }
+
+    private void booleanResponse(Response response, int statusCode, Boolean bool) {
+        assertEquals(statusCode, response.getStatus());
+        assertEquals(bool, HttpClient.getBody(response, Boolean.class));
+    }
+
+    private void booleanPut(String contextPath, String body, int statusCode, Boolean bool) {
+        Response response = client.put(contextPath, Entity.json(body), Collections.emptyMap());
+        booleanResponse(response, statusCode, bool);
+    }
+
+    private void booleanPost(String contextPath, String body, int statusCode, Boolean bool) {
+        Response response = client.post(contextPath, Entity.json(body), Collections.emptyMap());
+        booleanResponse(response, statusCode, bool);
+    }
+
+    private void booleanDelete(String contextPath, int statusCode, Boolean bool) {
+        Response response = client.delete(contextPath, Collections.emptyMap());
+        booleanResponse(response, statusCode, bool);
+    }
+
+    private void resourceLists(String resource, int size) {
+        Response response = client.get(resource);
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertEquals(size, HttpClient.getBody(response, List.class).size());
+    }
+
+    private void status() {
+        Response response = client.put("status/interval/240", Entity.json(""), Collections.emptyMap());
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(Long.valueOf(1000L), HttpClient.getBody(response, Long.class));
+        assertEquals(Long.valueOf(240L), HttpClient.getBody(response, Long.class));
 
         response = client.get("status/interval");
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(Long.valueOf(1000L), HttpClient.getBody(response, Long.class));
+        assertEquals(Long.valueOf(240L), HttpClient.getBody(response, Long.class));
+    }
 
-        /* policy types */
+    private void topics() {
+        assertEquals(Status.OK.getStatusCode(), client.get("topic/source").getStatus());
+        assertEquals(Status.OK.getStatusCode(), client.get("topic/sink").getStatus());
+    }
 
-        response = client.get("policyTypes");
+    private void properties() {
+        Response response = client.get("properties");
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(2, HttpClient.getBody(response, List.class).size());
+        assertEquals(fsm.getProperties(), HttpClient.getBody(response, Properties.class));
+    }
 
-        response = client.get("policyTypes/onap.policies.native.drools.Artifact/1.0.0");
+    private void subgroup() {
+        Response response = client.put("subgroup/YY", Entity.json(""), Collections.emptyMap());
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertNotNull(HttpClient.getBody(response, String.class));
+        assertEquals("YY", HttpClient.getBody(response, String.class));
 
-        response = client.get("policyTypes/onap.policies.native.drools.Controller/1.0.0");
+        response = client.get("subgroup");
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertNotNull(HttpClient.getBody(response, String.class));
+        assertEquals("YY", HttpClient.getBody(response, String.class));
+    }
 
-        /* policies */
+    private void group() {
+        Response response = client.put("group/GG", Entity.json(""), Collections.emptyMap());
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertEquals("GG", HttpClient.getBody(response, String.class));
 
-        response = client.get("policies");
+        response = HttpClientFactoryInstance.getClientFactory().get("lifecycle").get("group");
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        assertEquals(0, HttpClient.getBody(response, List.class).size());
+        assertEquals("GG", HttpClient.getBody(response, String.class));
+    }
+
+    private LifecycleFsm newFsmInstance() throws NoSuchFieldException, IllegalAccessException {
+        Field fsmField = LifecycleFeature.class.getDeclaredField("fsm");
+        fsmField.setAccessible(true);
+
+        Field modifiers = Field.class.getDeclaredField("modifiers");
+        modifiers.setAccessible(true);
+        modifiers.setInt(fsmField, fsmField.getModifiers() & ~Modifier.FINAL );
+
+        LifecycleFsm fsm = new LifecycleFsm();
+        fsmField.set(null, fsm);
+        return fsm;
+    }
+
+    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 String toString(ToscaPolicy policy) throws CoderException {
+        return coder.encode(policy);
+    }
 
-        response = client.get("policies/onap.policies.controlloop.Operational");
-        assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
+    private 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);
     }
 }
index 8bf1ed5..2e5235c 100644 (file)
   -->
 
 <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
-    <kbase name="onap.policies.type1.type2">
+    <kbase name="onap.policies.controlloop.Operational" default="false" equalsBehavior="equality"/>
+    <kbase name="onap.policies.controlloop.operational.common.Drools" default="false" equalsBehavior="equality"
+           includes="onap.policies.controlloop.Operational"/>
+    <kbase name="onap.policies.type1.type2" includes="onap.policies.controlloop.operational.common.Drools">
         <ksession name="junits" />
     </kbase>
 </kmodule>
index 4928778..d11863f 100644 (file)
@@ -108,7 +108,8 @@ public interface PolicyControllerFeatureApi extends OrderedService {
      *     of the operation preventing the invocation of
      *     lower priority features.   False, otherwise.
      */
-    default boolean beforePatch(PolicyController controller, DroolsConfiguration configuration) {
+    default boolean beforePatch(
+        PolicyController controller, DroolsConfiguration oldConfiguration, DroolsConfiguration newConfiguration) {
         return false;
     }
 
@@ -119,7 +120,9 @@ public interface PolicyControllerFeatureApi extends OrderedService {
      *     of the operation preventing the invocation of
      *     lower priority features.   False, otherwise.
      */
-    default boolean afterPatch(PolicyController controller, boolean success) {
+    default boolean afterPatch(
+        PolicyController controller, DroolsConfiguration oldConfiguration,
+        DroolsConfiguration newConfiguration, boolean success) {
         return false;
     }
 
index b80f4c8..0c12dbc 100644 (file)
@@ -227,7 +227,7 @@ public class AggregatedPolicyController implements PolicyController, TopicListen
         }
 
         if (FeatureApiUtils.apply(getProviders(),
-            feature -> feature.beforePatch(this, newDroolsConfiguration),
+            feature -> feature.beforePatch(this, oldDroolsConfiguration, newDroolsConfiguration),
             (feature, ex) -> logger.error("{}: feature {} before-patch failure because of {}", this,
                         feature.getClass().getName(), ex.getMessage(), ex))) {
             return true;
@@ -268,7 +268,7 @@ public class AggregatedPolicyController implements PolicyController, TopicListen
 
         boolean finalSuccess = success;
         FeatureApiUtils.apply(getProviders(),
-            feature -> feature.afterPatch(this, finalSuccess),
+            feature -> feature.afterPatch(this, oldDroolsConfiguration, newDroolsConfiguration, finalSuccess),
             (feature, ex) -> logger.error("{}: feature {} after-patch failure because of {}", this,
                         feature.getClass().getName(), ex.getMessage(), ex));