diff options
author | jhh <jorge.hernandez-herrero@att.com> | 2020-03-22 19:37:21 -0500 |
---|---|---|
committer | jhh <jorge.hernandez-herrero@att.com> | 2020-03-22 22:29:07 -0500 |
commit | 97e19c931535a5b474d4942a9982f0b7a1cf7414 (patch) | |
tree | ea2f83efb976bf7bda159097dbff50c0b99e451a /feature-lifecycle/src/main/java/org | |
parent | cc69c5a3f56a3e90c17c4fdcf38dc93c37cf93f2 (diff) |
Fix op policies distribution to controllers
Fix a bug when distributing a policy to the right
controller plus additional junits to catch similar
issues.
Issue-ID: POLICY-2356
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
Change-Id: I25fefa64ad54c55e6516ae18c6895b6de9407419
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
Diffstat (limited to 'feature-lifecycle/src/main/java/org')
5 files changed, 307 insertions, 46 deletions
diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/LifecycleFsm.java index a435f02e..6953d831 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 @@ -68,24 +68,32 @@ import org.slf4j.LoggerFactory; */ public class LifecycleFsm implements Startable { + /** + * Default Status Timer in seconds. + */ + public static final long DEFAULT_STATUS_TIMER_SECONDS = 120L; + private static final Logger logger = LoggerFactory.getLogger(LifecycleFsm.class); protected static final String CONFIGURATION_PROPERTIES_NAME = "feature-lifecycle"; protected static final String GROUP_NAME = "lifecycle.pdp.group"; protected static final String DEFAULT_PDP_GROUP = "defaultGroup"; - protected static final long DEFAULT_STATUS_TIMER_SECONDS = 120L; protected static final long MIN_STATUS_INTERVAL_SECONDS = 5L; protected static final String PDP_MESSAGE_NAME = "messageName"; protected static final ToscaPolicyTypeIdentifier POLICY_TYPE_DROOLS_NATIVE_RULES = - new ToscaPolicyTypeIdentifier("onap.policies.native.Drools", "1.0.0"); + new ToscaPolicyTypeIdentifier("onap.policies.native.drools.Artifact", "1.0.0"); - protected static final ToscaPolicyTypeIdentifier POLICY_TYPE_DROOLS_CONTROLLER = - new ToscaPolicyTypeIdentifier("onap.policies.drools.Controller", "1.0.0"); + protected static final ToscaPolicyTypeIdentifier POLICY_TYPE_DROOLS_NATIVE_CONTROLLER = + new ToscaPolicyTypeIdentifier("onap.policies.native.drools.Controller", "1.0.0"); + @Getter protected final Properties properties; + @Getter protected TopicSource source; + + @Getter protected TopicSinkClient client; @Getter @@ -113,14 +121,17 @@ public class LifecycleFsm implements Startable { protected long statusTimerSeconds = DEFAULT_STATUS_TIMER_SECONDS; @Getter - private final String group; + @Setter + private String group; @Getter + @Setter protected String subgroup; @Getter protected final Map<ToscaPolicyTypeIdentifier, PolicyTypeController> policyTypesMap = new HashMap<>(); + @Getter protected final Map<ToscaPolicyIdentifier, ToscaPolicy> policiesMap = new HashMap<>(); /** @@ -130,9 +141,8 @@ public class LifecycleFsm implements Startable { this.properties = SystemPersistenceConstants.getManager().getProperties(CONFIGURATION_PROPERTIES_NAME); this.group = this.properties.getProperty(GROUP_NAME, DEFAULT_PDP_GROUP); - this.policyTypesMap.put( - POLICY_TYPE_DROOLS_CONTROLLER, - new PolicyTypeNativeDroolsController(this, POLICY_TYPE_DROOLS_CONTROLLER)); + this.policyTypesMap.put(POLICY_TYPE_DROOLS_NATIVE_CONTROLLER, + new PolicyTypeNativeDroolsController(this, POLICY_TYPE_DROOLS_NATIVE_CONTROLLER)); this.policyTypesMap.put( POLICY_TYPE_DROOLS_NATIVE_RULES, new PolicyTypeNativeArtifactController(this, POLICY_TYPE_DROOLS_NATIVE_RULES)); @@ -171,7 +181,12 @@ public class LifecycleFsm implements Startable { logger.info("lifecycle event: start controller: {}", controller.getName()); for (ToscaPolicyTypeIdentifier id : controller.getPolicyTypes()) { if (isToscaPolicyType(id.getName())) { - policyTypesMap.put(id, new PolicyTypeDroolsController(this, id, controller)); + PolicyTypeDroolsController ptDroolsController = (PolicyTypeDroolsController) policyTypesMap.get(id); + if (ptDroolsController == null) { + policyTypesMap.put(id, new PolicyTypeDroolsController(this, id, controller)); + } else { + ptDroolsController.add(controller); + } } } } @@ -188,7 +203,14 @@ 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()) { - policyTypesMap.remove(id); + if (!policyTypesMap.containsKey(id)) { + continue; + } + PolicyTypeDroolsController ptDroolsController = (PolicyTypeDroolsController) policyTypesMap.get(id); + ptDroolsController.remove(controller); + if (ptDroolsController.controllers().isEmpty()) { + policyTypesMap.remove(id); + } } } 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 36c52e2b..2772d854 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 @@ -26,6 +26,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import lombok.Getter; +import lombok.NonNull; import org.apache.commons.lang3.StringUtils; import org.onap.policy.common.gson.annotation.GsonJsonIgnore; import org.onap.policy.common.utils.coder.CoderException; @@ -71,15 +72,53 @@ public class PolicyTypeDroolsController implements PolicyTypeController { } @Override - public boolean deploy(ToscaPolicy policy) { + public boolean deploy(@NonNull ToscaPolicy policy) { return perform(policy, (PolicyController controller) -> controller.offer(policy)); } + /** + * Adds a controller to support this policy type. + */ + public void add(@NonNull PolicyController controller) { + if (!controller.getPolicyTypes().contains(this.policyType)) { + throw new IllegalArgumentException( + "controller " + controller.getName() + " does not support " + this.policyType); + } + controllers.put(controller.getName(), controller); + } + + /** + * Removes a controller from this policy type. + */ + public void remove(@NonNull PolicyController controller) { + controllers.remove(controller.getName()); + } + @Override - public boolean undeploy(ToscaPolicy policy) { + public boolean undeploy(@NonNull ToscaPolicy policy) { return perform(policy, (PolicyController controller) -> controller.getDrools().delete(policy)); } + /** + * Get all controllers that support the policy type. + */ + public List<PolicyController> controllers() { + return List.copyOf(controllers.values()); + } + + private List<PolicyController> controllers(String controllerName) { + if (StringUtils.isBlank(controllerName)) { + /* this policy applies to all controllers */ + return controllers(); + } + + if (!this.controllers.containsKey(controllerName)) { + return List.of(); + } + + return List.of(this.controllers.get(controllerName)); + } + private boolean perform(ToscaPolicy policy, Function<PolicyController, Boolean> operation) { try { List<PolicyController> selected = selectControllers(policy); @@ -116,24 +155,4 @@ public class PolicyTypeDroolsController implements PolicyTypeController { } return selected; } - - private List<PolicyController> controllers(String controllerName) { - if (StringUtils.isBlank(controllerName)) { - /* this policy applies to all controllers */ - return controllers(); - } - - if (!this.controllers.containsKey(controllerName)) { - return List.of(); - } - - return List.of(this.controllers.get(controllerName)); - } - - /** - * Get all controllers that support the policy type. - */ - public List<PolicyController> controllers() { - return List.copyOf(controllers.values()); - } } diff --git a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactController.java b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactController.java index 31e9059d..d91ecccf 100644 --- a/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactController.java +++ b/feature-lifecycle/src/main/java/org/onap/policy/drools/lifecycle/PolicyTypeNativeArtifactController.java @@ -57,7 +57,7 @@ public class PolicyTypeNativeArtifactController implements PolicyTypeController nativePolicy = fsm.getDomainMaker().convertTo(policy, NativeArtifactPolicy.class); controller = PolicyControllerConstants.getFactory().get(nativePolicy.getProperties().getController().getName()); - } catch (CoderException e) { + } catch (CoderException | RuntimeException e) { logger.warn("Invalid Policy: {}", policy); return false; } 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 b0118fbe..2a417dcb 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 @@ -21,6 +21,7 @@ package org.onap.policy.drools.lifecycle; import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; @@ -142,6 +143,10 @@ public class PolicyTypeNativeDroolsController implements PolicyTypeController { } private boolean configControllerSources(ControllerProperties controllerConfig, Properties controllerProps) { + if (controllerConfig.getSourceTopics() == null) { + return true; + } + for (ControllerSourceTopic configSourceTopic : controllerConfig.getSourceTopics()) { List<TopicSource> sources = TopicEndpointManager.getManager().getTopicSources(List.of(configSourceTopic.getTopicName())); @@ -161,6 +166,10 @@ public class PolicyTypeNativeDroolsController implements PolicyTypeController { } private boolean configControllerSinks(ControllerProperties controllerConfig, Properties controllerProps) { + if (controllerConfig.getSinkTopics() == null) { + return true; + } + for (ControllerSinkTopic configSinkTopic : controllerConfig.getSinkTopics()) { List<TopicSink> sinks = TopicEndpointManager.getManager().getTopicSinks(List.of(configSinkTopic.getTopicName())); @@ -236,13 +245,21 @@ public class PolicyTypeNativeDroolsController implements PolicyTypeController { } private List<String> sourceTopics(List<ControllerSourceTopic> sourceTopics) { + if (sourceTopics == null) { + return Collections.EMPTY_LIST; + } + return sourceTopics.stream() .map(ControllerSourceTopic::getTopicName) .collect(Collectors.toList()); } - private List<String> sinkTopics(List<ControllerSinkTopic> sourceTopics) { - return sourceTopics.stream() + private List<String> sinkTopics(List<ControllerSinkTopic> sinkTopics) { + if (sinkTopics == null) { + return Collections.EMPTY_LIST; + } + + return sinkTopics.stream() .map(ControllerSinkTopic::getTopicName) .collect(Collectors.toList()); } 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 44113779..3e55a10c 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 @@ -20,47 +20,250 @@ 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.Properties; import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; 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.drools.lifecycle.LifecycleFeature; -import org.onap.policy.drools.lifecycle.LifecycleFsm; +import org.onap.policy.drools.lifecycle.PolicyTypeController; +import org.onap.policy.models.pdp.concepts.PdpStateChange; +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.ToscaPolicyTypeIdentifier; /** * REST Lifecycle Manager. */ -@Path("/policy/pdp") +@Path("/policy/pdp/engine/lifecycle") @Produces({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML}) @Consumes({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML}) @Api public class RestLifecycleManager { + /** + * GET group. + */ + @GET - @Path("engine/lifecycle/fsm/group") - @ApiOperation(value = "Retrieves the Lifecycle FSM", - notes = "Lifecycle FSM", response = LifecycleFsm.class) + @Path("group") + @ApiOperation(value = "Retrieves the Lifecycle group", + notes = "Lifecycle Group", response = String.class) public Response group() { return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getGroup()).build(); } + /** + * PUT group. + */ + + @PUT + @Path("group/{group}") + @ApiOperation(value = "Updates the Lifecycle group", + notes = "Lifecycle Group", response = String.class) + public Response updateGroup( + @ApiParam(value = "Group", required = true) @PathParam("group") String group) { + LifecycleFeature.fsm.setGroup(group); + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getGroup()).build(); + } + + /** + * GET subgroup. + */ + @GET - @Path("engine/lifecycle/fsm/subgroup") - @ApiOperation(value = "Retrieves the Lifecycle FSM", - notes = "Lifecycle FSM", response = LifecycleFsm.class) + @Path("subgroup") + @ApiOperation(value = "Retrieves the Lifecycle subgroup", + notes = "Lifecycle Subgroup", response = String.class) public Response subgroup() { return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getSubgroup()).build(); } + /** + * PUT subgroup. + */ + + @PUT + @Path("subgroup/{subgroup}") + @ApiOperation(value = "Retrieves the Lifecycle subgroup", + notes = "Lifecycle Subgroup", response = String.class) + public Response subgroup( + @ApiParam(value = "Subgroup", required = true) @PathParam("subgroup") String subgroup) { + LifecycleFeature.fsm.setSubgroup(subgroup); + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getSubgroup()).build(); + } + + /** + * GET properties. + */ + @GET - @Path("engine/lifecycle/fsm/state") - @ApiOperation(value = "Retrieves the Lifecycle FSM", - notes = "Lifecycle FSM", response = LifecycleFsm.class) + @Path("properties") + @ApiOperation(value = "Retrieves the Lifecycle properties", + notes = "Lifecycle Properties", response = Properties.class) + public Response properties() { + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getProperties()).build(); + } + + /** + * GET state. + */ + + @GET + @Path("state") + @ApiOperation(value = "Retrieves the Lifecycle state", notes = "Lifecycle State", response = PdpState.class) public Response state() { return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.state()).build(); } + + /** + * PUT state. + */ + + @PUT + @Path("state/{state}") + @ApiOperation(value = "updates the Lifecycle state", notes = "Lifecycle State", response = Boolean.class) + public Response updateState( + @ApiParam(value = "state", required = true) @PathParam("state") String state) { + + PdpStateChange change = new PdpStateChange(); + change.setPdpGroup(LifecycleFeature.fsm.getGroup()); + change.setPdpSubgroup(LifecycleFeature.fsm.getSubgroup()); + change.setState(PdpState.valueOf(state)); + change.setName(LifecycleFeature.fsm.getName()); + + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.stateChange(change)).build(); + } + + /** + * GET topic source. + */ + + @GET + @Path("topic/source") + @ApiOperation(value = "Retrieves the Lifecycle topic source", + notes = "Lifecycle Topic Source", response = TopicSource.class) + public Response source() { + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getSource()).build(); + } + + /** + * GET topic sink. + */ + + @GET + @Path("topic/sink") + @ApiOperation(value = "Retrieves the Lifecycle topic sink", + notes = "Lifecycle Topic Sink", response = TopicSink.class) + public Response sink() { + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getClient()).build(); + } + + /** + * GET status interval. + */ + + @GET + @Path("status/interval") + @ApiOperation(value = "Retrieves the Lifecycle Status Timer Interval in seconds", + notes = "Lifecycle Status Timer Interval in seconds", response = Long.class) + public Response updateStatusTimer() { + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getStatusTimerSeconds()).build(); + } + + /** + * PUT timeout. + */ + + @PUT + @Path("status/interval/{timeout}") + @ApiOperation(value = "Updates the Lifecycle Status Timer Interval in seconds", + notes = "Lifecycle Status Timer Interval in seconds", response = Long.class) + public Response statusTimer( + @ApiParam(value = "timeout", required = true) @PathParam("timeout") Long timeout) { + LifecycleFeature.fsm.setStatusTimerSeconds(timeout); + return Response.status(Response.Status.OK).entity(LifecycleFeature.fsm.getStatusTimerSeconds()).build(); + } + + /** + * GET policy types. + */ + + @GET + @Path("policyTypes") + @ApiOperation(value = "List of supported policy types", + notes = "Lifecycle Policy Types", responseContainer = "List") + public Response policyTypes() { + return Response.status(Response.Status.OK) + .entity(LifecycleFeature.fsm.getPolicyTypesMap().keySet()) + .build(); + } + + /** + * GET controllers. + */ + + @GET + @Path("policyTypes/{policyType}/{policyVersion}") + @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) { + return Response.status(Response.Status.OK) + .entity(LifecycleFeature.fsm + .getPolicyTypesMap() + .get(new ToscaPolicyTypeIdentifier(policyType, policyVersion))) + .build(); + } + + /** + * GET policies. + */ + + @GET + @Path("policies") + @ApiOperation(value = "List of tracked policies", + notes = "Lifecycle Policies", responseContainer = "List") + public Response policies() { + return Response.status(Response.Status.OK) + .entity(LifecycleFeature.fsm.getPoliciesMap().keySet()) + .build(); + + } + + /** + * GET a policy. + */ + + @GET + @Path("policies/{policy}/{policyVersion}") + @ApiOperation(value = "Lifecycle tracked policy", + notes = "Lifecycle Tracked Policy", response = ToscaPolicy.class) + public Response policy( + @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(); + } + + return Response.status(Response.Status.NOT_FOUND).build(); + } } |