From ece155048af47ea83ff898c999aa5137dc99a988 Mon Sep 17 00:00:00 2001 From: jhh Date: Tue, 31 Mar 2020 21:05:14 -0500 Subject: Sync controller capabilities as controllers bounce 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 Change-Id: I62bbc03411446849eaa55c9b1524220dc13c2cb0 Signed-off-by: jhh --- .../policy/drools/lifecycle/LifecycleFeature.java | 5 +- .../onap/policy/drools/lifecycle/LifecycleFsm.java | 23 ++- .../lifecycle/PolicyTypeDroolsController.java | 1 + .../PolicyTypeNativeDroolsController.java | 17 +- .../server/restful/RestLifecycleManager.java | 194 ++++++++++++++++++--- 5 files changed, 206 insertions(+), 34 deletions(-) (limited to 'feature-lifecycle/src/main/java') diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java index d9205977..12828e02 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFeature.java @@ -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); } 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 3ecb4b3a..ac76883f 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 @@ -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 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()); } } } diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsController.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsController.java index 2772d854..8dfbf2f3 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsController.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeDroolsController.java @@ -52,6 +52,7 @@ public class PolicyTypeDroolsController implements PolicyTypeController { private static final Logger logger = LoggerFactory.getLogger(PolicyTypeController.class); + @Getter protected final Map controllers = new ConcurrentHashMap<>(); @Getter diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsController.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsController.java index 8255c027..e74b2895 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsController.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeDroolsController.java @@ -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 diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java index 3e55a10c..5c8f9dc2 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/server/restful/RestLifecycleManager.java @@ -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 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 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 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; } + } -- cgit 1.2.3-korg