diff options
author | jhh <jorge.hernandez-herrero@att.com> | 2020-03-31 21:05:14 -0500 |
---|---|---|
committer | jhh <jorge.hernandez-herrero@att.com> | 2020-04-01 10:59:29 -0500 |
commit | ece155048af47ea83ff898c999aa5137dc99a988 (patch) | |
tree | 25af254f7cbbb42a99b9b98d5e6767c65aef563d | |
parent | 565b43c67c8964fe9e046435307e479921881566 (diff) |
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 <jorge.hernandez-herrero@att.com>
Change-Id: I62bbc03411446849eaa55c9b1524220dc13c2cb0
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
10 files changed, 534 insertions, 99 deletions
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<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()); } } } 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<String, PolicyController> 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()) @@ -242,28 +262,160 @@ 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; } + } diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java index 9b673dd5..1e9f1c66 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/lifecycle/ControllerSupport.java @@ -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); @@ -87,6 +82,17 @@ public class ControllerSupport { } /** + * 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. */ public void destroyController() { diff --git a/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java b/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java index 511fcc9b..2222399b 100644 --- a/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java +++ b/feature-lifecycle/src/test/java/org/onap/policy/drools/server/restful/RestLifecycleManagerTest.java @@ -18,43 +18,87 @@ 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); } } diff --git a/feature-lifecycle/src/test/resources/lifecycle.kmodule b/feature-lifecycle/src/test/resources/lifecycle.kmodule index 8bf1ed5a..2e5235c7 100644 --- a/feature-lifecycle/src/test/resources/lifecycle.kmodule +++ b/feature-lifecycle/src/test/resources/lifecycle.kmodule @@ -20,7 +20,10 @@ --> <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> diff --git a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java index 49287786..d11863f0 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java +++ b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureApi.java @@ -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; } diff --git a/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java b/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java index b80f4c86..0c12dbcb 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java @@ -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)); |