diff options
16 files changed, 1640 insertions, 2 deletions
diff --git a/controlloop/common/controller-frankfurt/src/main/resources/META-INF/kmodule.xml b/controlloop/common/controller-frankfurt/src/main/resources/META-INF/kmodule.xml index 011d7ef2f..cc39944a0 100644 --- a/controlloop/common/controller-frankfurt/src/main/resources/META-INF/kmodule.xml +++ b/controlloop/common/controller-frankfurt/src/main/resources/META-INF/kmodule.xml @@ -20,7 +20,7 @@ --> <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> <kbase name="onap.policies.controlloop.operational.common.Drools" equalsBehavior="equality" - packages="org.onap.policy.controlloop" includes="onap.policies.controlloop.operational.common.Drools"> + packages="org.onap.policy.controlloop"> <ksession name="frankfurt"/> </kbase> </kmodule> diff --git a/controlloop/common/controller-usecases/pom.xml b/controlloop/common/controller-usecases/pom.xml index fe1218e10..7319818e8 100644 --- a/controlloop/common/controller-usecases/pom.xml +++ b/controlloop/common/controller-usecases/pom.xml @@ -29,10 +29,21 @@ </parent> <artifactId>controller-usecases</artifactId> + <packaging>kjar</packaging> <name>${project.artifactId}</name> <description>Usecases Experimental Controller</description> + <build> + <plugins> + <plugin> + <groupId>org.kie</groupId> + <artifactId>kie-maven-plugin</artifactId> + <extensions>true</extensions> + </plugin> + </plugins> + </build> + <dependencies> <dependency> <groupId>org.onap.policy.models.policy-models-interactions.model-impl</groupId> diff --git a/controlloop/common/controller-usecases/src/main/resources/META-INF/kmodule.xml b/controlloop/common/controller-usecases/src/main/resources/META-INF/kmodule.xml new file mode 100644 index 000000000..7db705b2b --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/resources/META-INF/kmodule.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP + ================================================================================ + Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> +<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> + <kbase name="onap.policies.controlloop.operational.common.Drools" equalsBehavior="equality" + packages="org.onap.policy.controlloop"> + <ksession name="usecases"/> + </kbase> +</kmodule> diff --git a/controlloop/common/controller-usecases/src/main/resources/usecases.drl b/controlloop/common/controller-usecases/src/main/resources/usecases.drl new file mode 100644 index 000000000..439512cf5 --- /dev/null +++ b/controlloop/common/controller-usecases/src/main/resources/usecases.drl @@ -0,0 +1,1053 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop; + +import java.util.Collections; +import java.util.stream.Collectors; +import org.onap.policy.controlloop.CanonicalOnset; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.VirtualControlLoopNotification; +import org.onap.policy.controlloop.ControlLoopNotificationType; +import org.onap.policy.controlloop.actor.aai.AaiActor; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; +import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation; +import org.onap.policy.controlloop.actor.guard.GuardActor; +import org.onap.policy.controlloop.actor.guard.DecisionOperation; +import org.onap.policy.controlloop.actorserviceprovider.Operation; +import org.onap.policy.controlloop.actorserviceprovider.OperationProperties; +import org.onap.policy.controlloop.drl.legacy.ControlLoopParams; +import org.onap.policy.controlloop.eventmanager.ActorConstants; +import org.onap.policy.controlloop.eventmanager.Step; +import org.onap.policy.controlloop.policy.Policy; +import org.onap.policy.controlloop.policy.FinalResult; +import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.controlloop.utils.ControlLoopUtils; +import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager; +import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.State; +import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.NewEventStatus; +import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager.OperationOutcome2; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; + +import org.slf4j.LoggerFactory; +import org.slf4j.Logger; + +import org.onap.policy.drools.system.PolicyEngineConstants; + +/* +* +* Called when the ControlLoopParams object has been inserted into working memory from the PAP. +* +*/ +rule "INSERT.PARAMS" + when + $params : ControlLoopParams() + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {} : TOSCA-POLICY=[{}]", $params.getClosedLoopControlName(), $params.getPolicyName() + "." + + drools.getRule().getName(), $params.getToscaPolicy()); +end + +/* +* +* Called when a Tosca Policy is present. +* +*/ +rule "NEW.TOSCA.POLICY" + when + $policy : ToscaPolicy() + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: [{}|{}|{}|{}]: CONTENT: {}", drools.getRule().getName(), + $policy.getType(), $policy.getTypeVersion(), $policy.getName(), + $policy.getVersion(), $policy); + + ControlLoopParams params = ControlLoopUtils.toControlLoopParams($policy); + if (params != null) { + insert(params); + } +end + +/* + * Remove Control Loop Parameters. + */ +rule "REMOVE.PARAMS" + when + $params : ControlLoopParams( $policyName : getPolicyName(), $policyVersion : getPolicyVersion() ) + not ( ToscaPolicy( getName() == $policyName, getVersion() == $policyVersion ) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: [{}|{}|{}]", drools.getRule().getName(), + $params.getPolicyScope(), $params.getPolicyName(), $params.getPolicyVersion()); + + retract($params); +end + +/* +* +* This rule responds to DCAE Events where there is no manager yet. Either it is +* the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled) +* +*/ +rule "EVENT" + when + $params : ControlLoopParams( $clName : getClosedLoopControlName() ) + $event : CanonicalOnset( closedLoopControlName == $clName ) + not ( UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(), + getEvent() == $event ) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: event={}", + $clName, $params.getPolicyName(), drools.getRule().getName(), + $event); + // + // Retract the event from memory; it will be managed by the manager from now on + // + retract($event); + + VirtualControlLoopNotification notification = null; + + try { + // + // Check the event, because we need it to not be null when + // we create the UsecasesEventManager. The UsecasesEventManager + // will do extra syntax checking as well as check if the closed loop is disabled. + // + if ($event.getRequestId() == null) { + notification = new VirtualControlLoopNotification($event); + notification.setNotification(ControlLoopNotificationType.REJECTED); + notification.setFrom("policy"); + notification.setMessage("Missing requestId"); + notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName()); + notification.setPolicyVersion($params.getPolicyVersion()); + + } else { + UsecasesEventManager manager = new UsecasesEventManager($params, $event, drools.getWorkingMemory()); + insert(manager); + try { + // load the first policy/step + manager.start(); + + if (manager.getSteps().isEmpty()) { + // no steps implies no policies, thus go straight to DONE state + manager.setState(State.DONE); + + manager.setAccepted(true); + + notification = manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.ACTIVE); + notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName()); + + } else { + // Note: the notification will be generated lazily + manager.setState(State.POLICY_LOADED); + } + + } catch(Exception e) { + retract(manager); + throw e; + } + } + } catch (Exception e) { + logger.warn("{}: {}.{}: error starting manager", $clName, $params.getPolicyName(), + drools.getRule().getName(), e); + notification = new VirtualControlLoopNotification($event); + notification.setNotification(ControlLoopNotificationType.REJECTED); + notification.setMessage("Exception occurred: " + e.getMessage()); + notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName()); + notification.setPolicyVersion($params.getPolicyVersion()); + } + // + // Generate notification + // + try { + if (notification != null) { + PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification); + } + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: event={} exception generating notification", + $clName, $params.getPolicyName(), drools.getRule().getName(), + $event, e); + } +end + +/* +* +* This rule fires when we get a subsequent event. +* +*/ +rule "EVENT.MANAGER.NEW.EVENT" + when + $event : VirtualControlLoopEvent( ) + $manager : UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(), + getEvent() == $event ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: event={} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $event, $manager); + // + // Remove the event from memory + // + retract($event); + + // + // Check what kind of event this is + // + switch($manager.onNewEvent($event)) { + case SYNTAX_ERROR: + // + // Ignore any bad syntax events + // + logger.warn("{}: {}.{}: syntax error", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName()); + break; + + case FIRST_ABATEMENT: + case SUBSEQUENT_ABATEMENT: + // + // TODO: handle the abatement. Currently, it's just discarded. + // + logger.info("{}: {}.{}: abatement", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName()); + break; + + case FIRST_ONSET: + case SUBSEQUENT_ONSET: + default: + // + // We don't care about subsequent onsets + // + logger.warn("{}: {}.{}: subsequent onset", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName()); + break; + } +end + +/* +* +* All steps have been executed, load the next policy. +* +*/ +rule "EVENT.MANAGER.LOAD.NEXT.POLICY" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.POLICY_LOADED, + getSteps().isEmpty() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager); + + try { + $manager.loadNextPolicy($manager.getResult()); + + if ($manager.getSteps().isEmpty()) { + // no steps - must be the final policy + $manager.setState(State.DONE); + } + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception loading next policy", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to load next policy"); + } + + update($manager); +end + +/* +* +* Policy loaded, identify any preprocessor steps that need to be run first. +* +*/ +rule "EVENT.MANAGER.PREPROCESS" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.POLICY_LOADED, + $step : getSteps().peek(), + $step != null, + !$step.isPreprocessed() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + /* + * Load any preprocessor steps. + * + * Note: this will not change the state of the manager, but it may change the + * state of the step. + */ + $step.setPreprocessed(true); + $manager.loadPreprocessorSteps(); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception loading preprocessor steps", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to load preprocessing steps"); + } + + update($manager); +end + +/* +* +* Accepts the event, when ready to execute a step of interest. Does not change the +* state of the manager, leaving that to be done by rule "EVENT.MANAGER.EXECUTE.STEP". +* +*/ +rule "EVENT.MANAGER.ACCEPT" + salience 200 + when + $manager : UsecasesEventManager( + isActive(), + !isAccepted(), + getState() == State.POLICY_LOADED, + $step : getSteps().peek(), + $step != null, + $step.isPreprocessed(), + $step.acceptsEvent() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + $manager.setAccepted(true); + + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.ACTIVE); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to accept the event"); + } + + update($manager); +end + +/* +* +* Ready to execute the step. +* +*/ +rule "EVENT.MANAGER.EXECUTE.STEP" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.POLICY_LOADED, + $step : getSteps().peek(), + $step != null, + $step.isPreprocessed() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + $step.init(); + $step.setProperties(); + + if ($manager.executeStep()) { + $manager.setState(State.AWAITING_OUTCOME); + + } else { + // this step is no longer necessary - try the next one + $manager.nextStep(); + } + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception executing a step", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to execute the next step"); + } + + update($manager); +end + +/* +* +* Generate SDNR notification. Does not discard the outcome from the queue, leaving it to be +* handled by rule "EVENT.MANAGER.PROCESS.OUTCOME". +* +*/ +rule "EVENT.MANAGER.GENERATE.SDNR.NOTIFICATION" + // this should fire BEFORE the "EVENT.MANAGER.PROCESS.OUTCOME" rule + salience 100 + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + $outcome.getEnd() != null, + !isAbort($outcome), + $step : getSteps().peek(), + "SDNR".equals($step.getActorName()), + $outcome.isFor("SDNR", $step.getOperationName()) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome); + $manager.deliver("DCAE_CL_RSP", clResponse, "SDNR notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception generating SDNR Response notification", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + } +end + +/* +* +* Process a GUARD outcome. Does not discard the outcome from the queue, leaving it to be +* handled by rule "EVENT.MANAGER.PROCESS.OUTCOME". +* +*/ +rule "EVENT.MANAGER.PROCESS.GUARD.OUTCOME" + salience 100 + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + !isAbort($outcome), + $step : getSteps().peek(), + "GUARD".equals($step.getActorName()), + $outcome.isFor("GUARD", $step.getOperationName()) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.OPERATION); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + notification.setHistory(Collections.emptyList()); + + // get actor/operation name from the policy step, not from the guard step + Step step2 = $step.getParentStep(); + + if ($outcome.getEnd() == null) { + // it's a "start" operation + notification.setMessage("Sending guard query for " + step2.getActorName() + " " + step2.getOperationName()); + + } else if ($outcome.getResult() == PolicyResult.SUCCESS) { + notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName() + + " is Permit"); + } else { + // it's a failure + notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName() + + " is Deny"); + } + + $manager.deliver("POLICY-CL-MGT", notification, "GUARD notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception generating GUARD notification", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + } +end + +/* +* +* Process an outcome when the policy's operation starts. +* +*/ +rule "EVENT.MANAGER.PROCESS.POLICY.STARTED" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + $outcome.getEnd() == null, + $step : getSteps().peek(), + $step.isPolicyStep(), + $outcome.isFor($step.getActorName(), $step.getOperationName()) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + $manager.getOutcomes().remove(); + + // it's a "start" operation for the step + $manager.bumpAttempts(); + + $manager.addToHistory($outcome); + $manager.storeInDataBase($manager.getPartialHistory().peekLast()); + + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.OPERATION); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + notification.setHistory(Collections.emptyList()); + notification.setMessage($manager.getOperationMessage()); + + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'start' outcome"); + } + + update($manager); +end + +/* +* +* Process an outcome when an arbitrary Preprocessor step starts. +* +*/ +rule "EVENT.MANAGER.PROCESS.PREPROCESSOR.STARTED" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + $outcome.getEnd() == null, + $step : getSteps().peek(), + !$step.isPolicyStep(), + $outcome.isFor($step.getActorName(), $step.getOperationName()) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + $manager.getOutcomes().remove(); + + // it's a "start" operation for the step + $manager.bumpAttempts(); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle 'start' outcome"); + } + + update($manager); +end + +/* +* +* Process an outcome when the policy's operation succeeds. +* +*/ +rule "EVENT.MANAGER.PROCESS.POLICY.SUCCESS" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + $outcome.getEnd() != null, + $outcome.getResult() == PolicyResult.SUCCESS, + $step : getSteps().peek(), + $step.isPolicyStep(), + $outcome.isFor($step.getActorName(), $step.getOperationName()) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + $manager.getOutcomes().remove(); + + // let the step record the response that's contained within the outcome + $step.success($outcome); + + $manager.addToHistory($outcome); + $manager.storeInDataBase($manager.getPartialHistory().peekLast()); + + $manager.setResult($outcome.getResult()); + + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation) + .collect(Collectors.toList())); + + // this step is complete - discard it + $manager.getSteps().remove(); + + $manager.setState(State.POLICY_LOADED); + + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'success' outcome"); + } + + update($manager); +end + +/* +* +* Process a final failure outcome, when the event has been accepted. +* +*/ +rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.ACCEPTED" + when + $manager : UsecasesEventManager( + isActive(), + isAccepted(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + !isAbort($outcome), + $outcome.getEnd() != null, + $outcome.isFinalOutcome(), + $outcome.getResult() != PolicyResult.SUCCESS, + $step : getSteps().peek() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + $manager.getOutcomes().remove(); + + if (!$outcome.isFor($step.getActorName(), $step.getOperationName())) { + $outcome.setResult(PolicyResult.FAILURE_GUARD); + $outcome.setMessage("Operation denied by " + $outcome.getActor()); + } + + // final failure for this policy + $manager.addToHistory($outcome); + $manager.storeInDataBase($manager.getPartialHistory().peekLast()); + + $manager.setResult($outcome.getResult()); + + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation) + .collect(Collectors.toList())); + + // trigger move to the next policy - clear all steps + $manager.getSteps().clear(); + $manager.setState(State.POLICY_LOADED); + + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome"); + } + + update($manager); +end + +/* +* +* Process a final failure outcome, when the event has NOT been accepted. This typically +* occurs when an A&AI query fails BEFORE the first lock has been requested (and thus +* before the first policy's operation has been started). +* +*/ +rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.REJECTED" + when + $manager : UsecasesEventManager( + isActive(), + !isAccepted(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + !isAbort($outcome), + $outcome.getEnd() != null, + $outcome.isFinalOutcome(), + $outcome.getResult() != PolicyResult.SUCCESS, + $step : getSteps().peek() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + retract($manager); + + try { + // final failure for this policy + $manager.addToHistory($outcome); + + $manager.setResult($outcome.getResult()); + + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.REJECTED); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation) + .collect(Collectors.toList())); + + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to reject event"); + } + + $manager.destroy(); +end + +/* +* +* Process an outcome when the policy's operation fails. +* +*/ +rule "EVENT.MANAGER.PROCESS.POLICY.FAILURE" + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + !isAbort($outcome), + $outcome.getEnd() != null, + !$outcome.isFinalOutcome(), + $outcome.getResult() != PolicyResult.SUCCESS, + $step : getSteps().peek(), + $step.isPolicyStep(), + $outcome.isFor($step.getActorName(), $step.getOperationName()) ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + // not a final failure, thus it will be retried automatically + + $manager.getOutcomes().remove(); + + // do NOT invoke manager.setResult() + + $manager.addToHistory($outcome); + $manager.storeInDataBase($manager.getPartialHistory().peekLast()); + + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome"); + } + + update($manager); +end + +/* +* +* Discard an outcome that was not handled by any other rule. +* +*/ +rule "EVENT.MANAGER.DISCARD.OUTCOME" + salience -10 + when + $manager : UsecasesEventManager( + isActive(), + getState() == State.AWAITING_OUTCOME, + $outcome : getOutcomes().peek(), + $outcome != null, + $step : getSteps().peek() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $outcome.getResult(), $manager); + + try { + $manager.getOutcomes().remove(); + + if ($outcome.getEnd() != null && $outcome.isFor($step.getActorName(), $step.getOperationName())) { + // it's a completion for the step + + // let the step record the response that's contained within the outcome + if ($outcome.getResult() == PolicyResult.SUCCESS) { + $step.success($outcome); + } + + // this step is complete - discard it + $manager.getSteps().remove(); + + $manager.setState(State.POLICY_LOADED); + } + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception processing operation outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle outcome"); + } + + update($manager); +end + +/* +* +* Abort processing. This can happen in any state (once the manager has been started). +* +*/ +rule "EVENT.MANAGER.ABORT" + when + $manager : UsecasesEventManager( + isActive(), + getState() != State.DONE, + $outcome : getOutcomes().peek(), + $outcome != null, + isAbort($outcome), + $step : getSteps().peek() ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: {} manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $step, $manager); + + try { + // determine the final message + String msg; + switch ($outcome.getActor()) { + case ActorConstants.CL_TIMEOUT_ACTOR: + msg = "Control Loop timed out"; + break; + case ActorConstants.LOCK_ACTOR: + msg = "Target Lock was lost"; + break; + default: + msg = "Processing aborted by " + $outcome.getActor(); + break; + } + + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE, msg); + + if ($step != null && "SDNR".equals($step.getActorName()) + && $outcome.isFor($step.getActorName(), $step.getOperationName())) { + + // aborted while processing the SDNR step - generate a notification + ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome); + $manager.deliver("DCAE_CL_RSP", clResponse, "SDNR notification", drools.getRule().getName()); + } + + if ($step != null) { + $outcome.setActor($step.getActorName()); + $outcome.setOperation($step.getOperationName()); + + $manager.addToHistory($outcome); + $manager.storeInDataBase($manager.getPartialHistory().peekLast()); + } + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception handling ABORT outcome", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + $manager.abort(State.DONE, FinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle ABORT"); + } + + update($manager); +end + +/* +* +* Done processing. Arriving here implies that the event has been accepted. +* +*/ +rule "EVENT.MANAGER.FINAL" + when + $manager : UsecasesEventManager( + !isActive() || getState() == State.DONE ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}.{}: manager={}", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager); + + retract($manager); + + try { + VirtualControlLoopNotification notification = $manager.makeNotification(); + notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName()); + notification.setHistory($manager.getFullHistory().stream().map(OperationOutcome2::getClOperation) + .collect(Collectors.toList())); + + FinalResult finalResult = $manager.getFinalResult(); + if (finalResult == null) { + finalResult = ($manager.isActive() ? FinalResult.FINAL_SUCCESS : FinalResult.FINAL_FAILURE); + } + + switch (finalResult) { + case FINAL_FAILURE_EXCEPTION: + notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE); + notification.setMessage("Exception in processing closed loop"); + break; + case FINAL_SUCCESS: + notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS); + break; + case FINAL_OPENLOOP: + notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP); + break; + case FINAL_FAILURE: + default: + notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE); + break; + } + + if ($manager.getFinalMessage() != null) { + notification.setMessage($manager.getFinalMessage()); + } + + $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName()); + + } catch(RuntimeException e) { + logger.warn("{}: {}.{}: manager={} exception generating final notification", + $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(), + $manager, e); + } + + $manager.destroy(); +end + +/* +* +* This rule will clean up any rogue events where there is no +* ControlLoopParams object corresponding to the onset event. +* +*/ +rule "EVENT.CLEANUP" + salience -100 + when + $event : VirtualControlLoopEvent( $clName: closedLoopControlName ) + then + + Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage()); + logger.info("{}: {}", $clName, drools.getRule().getName()); + logger.debug("{}: {}: orphan event={}", + $clName, drools.getRule().getName(), $event); + // + // Retract the event + // + retract($event); +end + +/* +* +* At this point, it appears that if we prevent the rules from getting messages from +* topics, then that will also prevent the actors from getting them. So the following +* rules are here just to discard those messages. +* +* These have a higher salience so the objects are removed before the "FINAL" message +* is processed, so that the junit test can assume things are done once they see the +* "FINAL" message. Otherwise, tests might fail sporadically. +* +*/ +rule "APPC.Response.CLEANUP" + salience 1 + when + $msg : org.onap.policy.appc.Response( ) + then + retract($msg); +end + +rule "APPC.Request.CLEANUP" + salience 1 + when + $msg : org.onap.policy.appc.Request( ) + then + retract($msg); +end + +rule "APPC-LCM.Response.CLEANUP" + salience 1 + when + $msg : org.onap.policy.appclcm.AppcLcmDmaapWrapper( ) + then + retract($msg); +end + +rule "SDNR.Response.CLEANUP" + salience 1 + when + $msg : org.onap.policy.sdnr.PciResponseWrapper( ) + then + retract($msg); +end diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/UsecasesTest.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/UsecasesTest.java new file mode 100644 index 000000000..b9864bdd7 --- /dev/null +++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/UsecasesTest.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.controlloop; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.onap.policy.controlloop.common.rules.test.DroolsRuleTest; +import org.onap.policy.controlloop.common.rules.test.Listener; +import org.onap.policy.controlloop.common.rules.test.NamedRunner; +import org.onap.policy.controlloop.common.rules.test.TestNames; +import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; +import org.onap.policy.simulators.Util; + +/** + * Tests use cases using Usecases rules. + * + * <p/> + * Note: this runs ALL tests (i.e., any whose names start with "test"). + */ +@RunWith(NamedRunner.class) +@TestNames(prefixes = {"test"}) + +public class UsecasesTest extends DroolsRuleTest { + protected static final String CONTROLLER_NAME = "usecases"; + + + /** + * Sets up statics. + */ + @BeforeClass + public static void setUpBeforeClass() { + initStatics(CONTROLLER_NAME); + + rules.configure("src/main/resources"); + rules.start(); + httpClients.addClients("usecases"); + simulators.start(Util::buildAaiSim, Util::buildSoSim, Util::buildVfcSim, Util::buildGuardSim, + Util::buildSdncSim); + } + + /** + * Cleans up statics. + */ + @AfterClass + public static void tearDownAfterClass() { + finishStatics(); + } + + /** + * Sets up. + */ + @Before + public void setUp() { + init(); + } + + /** + * Tears down. + */ + @After + public void tearDown() { + finish(); + } + + @Override + protected void waitForLockAndPermit(ToscaPolicy policy, Listener<VirtualControlLoopNotification> policyClMgt) { + String policyName = policy.getIdentifier().getName(); + + policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.ACTIVE + && (policyName + ".EVENT.MANAGER.ACCEPT").equals(notif.getPolicyName())); + + policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION + && (policyName + ".EVENT.MANAGER.PROCESS.GUARD.OUTCOME").equals(notif.getPolicyName()) + && notif.getMessage().startsWith("Sending guard query")); + + policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION + && (policyName + ".EVENT.MANAGER.PROCESS.GUARD.OUTCOME").equals(notif.getPolicyName()) + && notif.getMessage().startsWith("Guard result") && notif.getMessage().endsWith("Permit")); + + policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION + && (policyName + ".EVENT.MANAGER.PROCESS.POLICY.STARTED").equals(notif.getPolicyName()) + && notif.getMessage().startsWith("actor=")); + } + + @Override + protected VirtualControlLoopNotification waitForFinal(ToscaPolicy policy, + Listener<VirtualControlLoopNotification> policyClMgt, ControlLoopNotificationType finalType) { + + return policyClMgt.await(notif -> notif.getNotification() == finalType + && (policy.getIdentifier().getName() + ".EVENT.MANAGER.FINAL").equals(notif.getPolicyName())); + } + + @Override + protected long getCreateCount() { + return UsecasesEventManager.getCreateCount(); + } +} diff --git a/controlloop/common/controller-usecases/src/test/resources/usecases.pom b/controlloop/common/controller-usecases/src/test/resources/usecases.pom new file mode 100644 index 000000000..e30417ef0 --- /dev/null +++ b/controlloop/common/controller-usecases/src/test/resources/usecases.pom @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + ONAP + ================================================================================ + Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <groupId>org.onap.policy.controlloop</groupId> + <artifactId>usecases</artifactId> + <version>1.1.0</version> +</project> diff --git a/controlloop/common/feature-controlloop-usecases/pom.xml b/controlloop/common/feature-controlloop-usecases/pom.xml new file mode 100644 index 000000000..1f8ac2f4b --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/pom.xml @@ -0,0 +1,114 @@ +<!-- + ============LICENSE_START======================================================= + ONAP + ================================================================================ + Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. + Modifications Copyright (C) 2020 Bell Canada. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.policy.drools-applications.controlloop.common</groupId> + <artifactId>drools-applications-common</artifactId> + <version>1.7.1-SNAPSHOT</version> + </parent> + + <artifactId>feature-controlloop-usecases</artifactId> + + <description> + Load Experimental Usecases Control Loop Use Cases Controller as a feature. + </description> + + <build> + <resources> + <resource> + <directory>src/main/feature</directory> + <filtering>true</filtering> + </resource> + <resource> + <directory>src/main/resources</directory> + </resource> + </resources> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <executions> + <execution> + <id>zipfile</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>${project.artifactId}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <goals> + <goal>copy-dependencies</goal> + </goals> + <phase>prepare-package</phase> + <configuration> + <outputDirectory>${project.build.directory}/assembly/lib</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <useRepositoryLayout>false</useRepositoryLayout> + <addParentPoms>false</addParentPoms> + <copyPom>false</copyPom> + <includeScope>runtime</includeScope> + <excludeTransitive>true</excludeTransitive> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.onap.policy.drools-applications.controlloop.common</groupId> + <artifactId>controller-usecases</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.policy.drools-pdp</groupId> + <artifactId>policy-management</artifactId> + <version>${version.policy.drools-pdp}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/controlloop/common/feature-controlloop-usecases/src/assembly/assemble_zip.xml b/controlloop/common/feature-controlloop-usecases/src/assembly/assemble_zip.xml new file mode 100644 index 000000000..860ab2a23 --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/src/assembly/assemble_zip.xml @@ -0,0 +1,85 @@ +<!-- + ============LICENSE_START======================================================= + ONAP + ================================================================================ + Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>feature-controlloop-usecases-package</id> + <formats> + <format>zip</format> + </formats> + + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target</directory> + <outputDirectory>lib/feature</outputDirectory> + <includes> + <include>feature-controlloop-usecases-${project.version}.jar</include> + </includes> + </fileSet> + <fileSet> + <directory>target/assembly/lib</directory> + <outputDirectory>artifacts</outputDirectory> + <includes> + <include>controller-usecases-${project.version}.jar</include> + </includes> + </fileSet> + <fileSet> + <directory>target/assembly/lib</directory> + <outputDirectory>lib/dependencies</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + <excludes> + <exclude>controller-usecases-${project.version}.jar</exclude> + </excludes> + </fileSet> + <fileSet> + <directory>target/classes/config</directory> + <outputDirectory>config</outputDirectory> + <fileMode>0644</fileMode> + <excludes/> + </fileSet> + <fileSet> + <directory>src/main/feature/bin</directory> + <outputDirectory>bin</outputDirectory> + <fileMode>0755</fileMode> + <excludes/> + </fileSet> + <fileSet> + <directory>src/main/feature/db</directory> + <outputDirectory>db</outputDirectory> + <fileMode>0744</fileMode> + <excludes/> + </fileSet> + <fileSet> + <directory>src/main/feature/install</directory> + <outputDirectory>install</outputDirectory> + <fileMode>0755</fileMode> + <excludes/> + </fileSet> + </fileSets> + +</assembly> diff --git a/controlloop/common/feature-controlloop-usecases/src/main/feature/config/logback-include-usecases.xml b/controlloop/common/feature-controlloop-usecases/src/main/feature/config/logback-include-usecases.xml new file mode 100644 index 000000000..655ccd7ca --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/src/main/feature/config/logback-include-usecases.xml @@ -0,0 +1,56 @@ +<!-- + ============LICENSE_START======================================================= + feature-controlloop-usecases + ================================================================================ + Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<!-- + The logger configurations in this file are for each individual controller + to have their own network logger for topic traffic. This is an extension of + logback.xml or logback-eelf.xml. + + NOTE: Each logger MUST contain the same name as the control loop's controller. +--> +<included> + + <property name="logDir" value="${POLICY_LOGS}" /> + <property name="usecasesLog" value="usecases-network" /> + <property name="networkPattern" value="[%d{yyyy-MM-dd'T'HH:mm:ss.SSS+00:00, UTC}|%t]%m%n" /> + + <!-- Usecases Network Logging Properties --> + <appender name="UsecasesOut" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDir}/${usecasesLog}.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + <fileNamePattern>${logDir}/${usecasesLog}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> + <maxFileSize>50MB</maxFileSize> + <maxHistory>30</maxHistory> + <totalSizeCap>10GB</totalSizeCap> + </rollingPolicy> + <encoder> + <pattern>${networkPattern}</pattern> + </encoder> + </appender> + + <appender name="AsyncUsecasesOut" class="ch.qos.logback.classic.AsyncAppender"> + <appender-ref ref="UsecasesOut" /> + </appender> + + <logger name="usecases" level="INFO" additivity="false"> + <appender-ref ref="AsyncUsecasesOut" /> + </logger> + +</included> diff --git a/controlloop/common/feature-controlloop-usecases/src/main/feature/config/usecases-controller.properties b/controlloop/common/feature-controlloop-usecases/src/main/feature/config/usecases-controller.properties new file mode 100644 index 000000000..73c41123f --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/src/main/feature/config/usecases-controller.properties @@ -0,0 +1,64 @@ +### +# ============LICENSE_START======================================================= +# ONAP +# ================================================================================ +# Copyright (C) 2018-2020 AT&T Intellectual Property. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +controller.name=usecases + +dmaap.source.topics=DCAE_TOPIC,APPC-CL,APPC-LCM-WRITE,SDNR-CL-RSP +dmaap.sink.topics=APPC-CL,APPC-LCM-READ,POLICY-CL-MGT,SDNR-CL,DCAE_CL_RSP + +dmaap.source.topics.DCAE_TOPIC.events=\ + org.onap.policy.controlloop.CanonicalOnset,org.onap.policy.controlloop.CanonicalAbated +dmaap.source.topics.DCAE_TOPIC.events.org.onap.policy.controlloop.CanonicalOnset.\ + filter=[?($.closedLoopEventStatus == 'ONSET')] +dmaap.source.topics.DCAE_TOPIC.events.org.onap.policy.controlloop.CanonicalAbated.\ + filter=[?($.closedLoopEventStatus == 'ABATED')] +dmaap.source.topics.DCAE_TOPIC.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gson + +dmaap.source.topics.APPC-CL.events=org.onap.policy.appc.Response +dmaap.source.topics.APPC-CL.events.org.onap.policy.appc.Response.filter=[?($.CommonHeader && $.Status)] +dmaap.source.topics.APPC-CL.events.custom.gson=org.onap.policy.appc.util.Serialization,gsonPretty + +dmaap.source.topics.APPC-LCM-WRITE.events=org.onap.policy.appclcm.AppcLcmDmaapWrapper +dmaap.source.topics.APPC-LCM-WRITE.events.org.onap.policy.appclcm.AppcLcmDmaapWrapper.filter=[?($.type == 'response')] +dmaap.source.topics.APPC-LCM-WRITE.events.custom.gson=org.onap.policy.appclcm.util.Serialization,gson + +dmaap.sink.topics.APPC-CL.events=org.onap.policy.appc.Request +dmaap.sink.topics.APPC-CL.events.custom.gson=org.onap.policy.appc.util.Serialization,gsonPretty + +dmaap.sink.topics.APPC-LCM-READ.events=org.onap.policy.appclcm.AppcLcmDmaapWrapper +dmaap.sink.topics.APPC-LCM-READ.events.custom.gson=org.onap.policy.appclcm.util.Serialization,gson + +dmaap.sink.topics.POLICY-CL-MGT.events=org.onap.policy.controlloop.VirtualControlLoopNotification +dmaap.sink.topics.POLICY-CL-MGT.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty + +dmaap.sink.topics.SDNR-CL.events=org.onap.policy.sdnr.PciRequestWrapper +dmaap.sink.topics.SDNR-CL.events.custom.gson=org.onap.policy.sdnr.util.Serialization,gson + +dmaap.sink.topics.DCAE_CL_RSP.events=org.onap.policy.controlloop.ControlLoopResponse +dmaap.sink.topics.DCAE_CL_RSP.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gsonPretty + +dmaap.source.topics.SDNR-CL-RSP.events=org.onap.policy.sdnr.PciResponseWrapper +dmaap.source.topics.SDNR-CL-RSP.events.org.onap.policy.sdnr.PciResponseWrapper.filter=[?($.type == 'response')] +dmaap.source.topics.SDNR-CL-RSP.events.custom.gson=org.onap.policy.sdnr.util.Serialization,gson + +rules.groupId=${project.groupId} +rules.artifactId=controller-usecases +rules.version=${project.version} + diff --git a/controlloop/common/feature-controlloop-usecases/src/main/java/org/onap/policy/drools/apps/controlloop/feature/usecases/UsecasesFeature.java b/controlloop/common/feature-controlloop-usecases/src/main/java/org/onap/policy/drools/apps/controlloop/feature/usecases/UsecasesFeature.java new file mode 100644 index 000000000..1f8e2545e --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/src/main/java/org/onap/policy/drools/apps/controlloop/feature/usecases/UsecasesFeature.java @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.drools.apps.controlloop.feature.usecases; + +import org.onap.policy.drools.features.PolicyEngineFeatureApi; + +/** + * Usecases installation as a feature saves time + * loading the Usecases controller at runtime over the + * usual installation from nexus. + * + * <p>This class will be expanded in the future for additional + * functionality + * + */ +public class UsecasesFeature implements PolicyEngineFeatureApi { + + public static final int SEQNO = 1000; + + @Override + public int getSequenceNumber() { + return SEQNO; + } + +} diff --git a/controlloop/common/feature-controlloop-usecases/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureApi b/controlloop/common/feature-controlloop-usecases/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureApi new file mode 100644 index 000000000..3a8263942 --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureApi @@ -0,0 +1 @@ +org.onap.policy.drools.apps.controlloop.feature.usecases.UsecasesFeature diff --git a/controlloop/common/feature-controlloop-usecases/src/test/java/org/onap/policy/drools/apps/controlloop/feature/usecases/UsecasesFeatureTest.java b/controlloop/common/feature-controlloop-usecases/src/test/java/org/onap/policy/drools/apps/controlloop/feature/usecases/UsecasesFeatureTest.java new file mode 100644 index 000000000..ed1bba23d --- /dev/null +++ b/controlloop/common/feature-controlloop-usecases/src/test/java/org/onap/policy/drools/apps/controlloop/feature/usecases/UsecasesFeatureTest.java @@ -0,0 +1,31 @@ +/* + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.drools.apps.controlloop.feature.usecases; + +import static org.junit.Assert.assertEquals; + +public class UsecasesFeatureTest { + + @org.junit.Test + public void getSequenceNumber() { + assertEquals(UsecasesFeature.SEQNO, new UsecasesFeature().getSequenceNumber()); + } +} diff --git a/controlloop/common/pom.xml b/controlloop/common/pom.xml index 7298db6c2..4ab1b490e 100644 --- a/controlloop/common/pom.xml +++ b/controlloop/common/pom.xml @@ -42,6 +42,7 @@ <module>feature-controlloop-trans</module> <module>feature-controlloop-management</module> <module>feature-controlloop-frankfurt</module> + <module>feature-controlloop-usecases</module> </modules> diff --git a/controlloop/common/rules-test/src/test/resources/META-INF/kmodule.xml b/controlloop/common/rules-test/src/test/resources/META-INF/kmodule.xml index cc0009735..9ace783c0 100644 --- a/controlloop/common/rules-test/src/test/resources/META-INF/kmodule.xml +++ b/controlloop/common/rules-test/src/test/resources/META-INF/kmodule.xml @@ -20,7 +20,7 @@ --> <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> <kbase name="onap.policies.controlloop.operational.common.Drools" equalsBehavior="equality" - packages="org.onap.policy.controlloop" includes="onap.policies.controlloop.operational.common.Drools"> + packages="org.onap.policy.controlloop"> <ksession name="rulesTest"/> </kbase> </kmodule> diff --git a/controlloop/packages/docker-controlloop/src/main/docker/Dockerfile b/controlloop/packages/docker-controlloop/src/main/docker/Dockerfile index 3e60c9597..efb54b6e4 100644 --- a/controlloop/packages/docker-controlloop/src/main/docker/Dockerfile +++ b/controlloop/packages/docker-controlloop/src/main/docker/Dockerfile @@ -13,13 +13,17 @@ RUN unzip apps-controlloop.zip && \ . $POLICY_HOME/etc/profile.d/env.sh && \ $POLICY_HOME/bin/features install controlloop-utils controlloop-trans controlloop-management && \ $POLICY_HOME/bin/features install controlloop-frankfurt && \ + $POLICY_HOME/bin/features install controlloop-usecases && \ $POLICY_HOME/bin/features enable healthcheck distributed-locking lifecycle && \ $POLICY_HOME/bin/features enable controlloop-trans controlloop-management && \ $POLICY_HOME/bin/features enable controlloop-frankfurt && \ + $POLICY_HOME/bin/features enable controlloop-usecases && \ $POLICY_HOME/bin/deploy-artifact -l -d -s $POLICY_HOME/etc/m2/standalone-settings.xml \ -a $POLICY_HOME/features/controlloop-management/lib/feature/feature-controlloop-management-$BUILD_VERSION_APP_CL.jar && \ $POLICY_HOME/bin/deploy-artifact -l -d -s $POLICY_HOME/etc/m2/standalone-settings.xml \ -a $POLICY_HOME/features/controlloop-frankfurt/artifacts/controller-frankfurt-$BUILD_VERSION_APP_CL.jar && \ + $POLICY_HOME/bin/deploy-artifact -l -d -s $POLICY_HOME/etc/m2/standalone-settings.xml \ + -a $POLICY_HOME/features/controlloop-usecases/artifacts/controller-usecases-$BUILD_VERSION_APP_CL.jar && \ find $HOME/.m2/ -name _maven.repositories -exec rm -v {} \; && \ find $HOME/.m2/ -name _remote.repositories -exec rm -v {} \; && \ rm $POLICY_INSTALL/apps-controlloop.zip $POLICY_INSTALL/basex-controlloop-$BUILD_VERSION_APP_CL.tar.gz 2> /dev/null |