2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.controlloop;
23 import java.time.Instant;
24 import java.util.Collections;
25 import java.util.stream.Collectors;
26 import org.onap.policy.controlloop.CanonicalOnset;
27 import org.onap.policy.controlloop.VirtualControlLoopEvent;
28 import org.onap.policy.controlloop.VirtualControlLoopNotification;
29 import org.onap.policy.controlloop.ControlLoopNotificationType;
30 import org.onap.policy.controlloop.actor.xacml.XacmlActor;
31 import org.onap.policy.controlloop.actorserviceprovider.Operation;
32 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
33 import org.onap.policy.controlloop.actorserviceprovider.OperationFinalResult;
34 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
35 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
36 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
37 import org.onap.policy.controlloop.eventmanager.ActorConstants;
38 import org.onap.policy.controlloop.eventmanager.Step;
39 import org.onap.policy.controlloop.utils.ControlLoopUtils;
40 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager;
41 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithSteps.State;
42 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithOutcome.OperationOutcome2;
43 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithEvent.NewEventStatus;
44 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
45 import org.onap.policy.controlloop.eventmanager.EventManagerServices;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
48 import org.slf4j.LoggerFactory;
49 import org.slf4j.Logger;
51 import org.onap.policy.drools.system.PolicyEngineConstants;
55 * Called at initial start-up, to create the event services that will be used by all
56 * event managers in this rule engine instance.
58 rule "CREATE.EVENT.SERVICES"
60 not (EventManagerServices())
63 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
64 logger.info("{}", drools.getRule().getName());
67 insert(new EventManagerServices("event-manager"));
69 } catch(RuntimeException e) {
70 logger.warn("{}: cannot create event services", drools.getRule().getName(), e);
76 * Called when the ControlLoopParams object has been inserted into working memory from the PAP.
81 $params : ControlLoopParams()
84 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
85 logger.info("{}: {} : TOSCA-POLICY=[{}]", $params.getClosedLoopControlName(), $params.getPolicyName() + "."
86 + drools.getRule().getName(), $params.getToscaPolicy());
91 * Called when a Tosca Policy is present.
94 rule "NEW.TOSCA.POLICY"
96 $policy : ToscaPolicy()
99 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
100 logger.info("{}: [{}|{}|{}|{}]: CONTENT: {}", drools.getRule().getName(),
101 $policy.getType(), $policy.getTypeVersion(), $policy.getName(),
102 $policy.getVersion(), $policy);
104 ControlLoopParams params = ControlLoopUtils.toControlLoopParams($policy);
105 if (params != null) {
111 * Remove Control Loop Parameters.
115 $params : ControlLoopParams( $policyName : getPolicyName(), $policyVersion : getPolicyVersion() )
116 not ( ToscaPolicy( getName() == $policyName, getVersion() == $policyVersion ) )
119 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
120 logger.info("{}: [{}|{}|{}]", drools.getRule().getName(),
121 $params.getPolicyScope(), $params.getPolicyName(), $params.getPolicyVersion());
128 * This rule responds to DCAE Events where there is no manager yet. Either it is
129 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
134 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
135 $event : CanonicalOnset( closedLoopControlName == $clName )
136 $services : EventManagerServices()
137 not ( UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
138 getEvent() == $event ) )
141 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
142 logger.info("{}: {}.{}: event={}",
143 $clName, $params.getPolicyName(), drools.getRule().getName(),
146 // Retract the event from memory; it will be managed by the manager from now on
150 VirtualControlLoopNotification notification = null;
154 // Check the event, because we need it to not be null when
155 // we create the UsecasesEventManager. The UsecasesEventManager
156 // will do extra syntax checking as well as check if the closed loop is disabled.
158 if ($event.getRequestId() == null) {
159 notification = new VirtualControlLoopNotification($event);
160 notification.setNotification(ControlLoopNotificationType.REJECTED);
161 notification.setFrom("policy");
162 notification.setMessage("Missing requestId");
163 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
164 notification.setPolicyVersion($params.getPolicyVersion());
167 UsecasesEventManager manager =
168 new UsecasesEventManager($services, $params, $event, drools.getWorkingMemory());
171 // load the first policy/step
174 if (manager.getSteps().isEmpty()) {
175 // no steps implies no policies, thus go straight to DONE state
176 manager.setState(State.DONE);
178 manager.setAccepted(true);
180 notification = manager.makeNotification();
181 notification.setNotification(ControlLoopNotificationType.ACTIVE);
182 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
185 // Note: the notification will be generated lazily
186 manager.setState(State.POLICY_LOADED);
189 } catch(Exception e) {
194 } catch (Exception e) {
195 logger.warn("{}: {}.{}: error starting manager", $clName, $params.getPolicyName(),
196 drools.getRule().getName(), e);
197 notification = new VirtualControlLoopNotification($event);
198 notification.setNotification(ControlLoopNotificationType.REJECTED);
199 notification.setMessage("Exception occurred: " + e.getMessage());
200 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
201 notification.setPolicyVersion($params.getPolicyVersion());
204 // Generate notification
207 if (notification != null) {
208 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
211 } catch(RuntimeException e) {
212 logger.warn("{}: {}.{}: event={} exception generating notification",
213 $clName, $params.getPolicyName(), drools.getRule().getName(),
220 * This rule fires when we get a subsequent event.
223 rule "EVENT.MANAGER.NEW.EVENT"
225 $event : VirtualControlLoopEvent( )
226 $manager : UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
227 getEvent() == $event )
230 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
231 logger.info("{}: {}.{}: event={} manager={}",
232 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
235 // Remove the event from memory
240 // Check what kind of event this is
242 switch($manager.onNewEvent($event)) {
245 // Ignore any bad syntax events
247 logger.warn("{}: {}.{}: syntax error",
248 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
251 case FIRST_ABATEMENT:
252 case SUBSEQUENT_ABATEMENT:
254 // TODO: handle the abatement. Currently, it's just discarded.
256 logger.info("{}: {}.{}: abatement",
257 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
261 case SUBSEQUENT_ONSET:
264 // We don't care about subsequent onsets
266 logger.warn("{}: {}.{}: subsequent onset",
267 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
274 * All steps have been executed, load the next policy.
277 rule "EVENT.MANAGER.LOAD.NEXT.POLICY"
279 $manager : UsecasesEventManager(
281 getState() == State.POLICY_LOADED,
282 getSteps().isEmpty() )
285 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
286 logger.info("{}: {}.{}: manager={}",
287 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
291 $manager.loadNextPolicy($manager.getResult());
293 if ($manager.getSteps().isEmpty()) {
294 // no steps - must be the final policy
295 $manager.setState(State.DONE);
298 } catch(RuntimeException e) {
299 logger.warn("{}: {}.{}: manager={} exception loading next policy",
300 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
302 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to load next policy");
310 * Policy loaded, identify any preprocessor steps that need to be run first.
313 rule "EVENT.MANAGER.PREPROCESS"
315 $manager : UsecasesEventManager(
317 getState() == State.POLICY_LOADED,
318 $step : getSteps().peek(),
320 !$step.isPreprocessed() )
323 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
324 logger.info("{}: {}.{}: {} manager={}",
325 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
330 * Load any preprocessor steps.
332 * Note: this will not change the state of the manager, but it may change the
335 $step.setPreprocessed(true);
336 $manager.loadPreprocessorSteps();
338 } catch(RuntimeException e) {
339 logger.warn("{}: {}.{}: manager={} exception loading preprocessor steps",
340 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
342 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to load preprocessing steps");
350 * Accepts the event, when ready to execute a step of interest. Does not change the
351 * state of the manager, leaving that to be done by rule "EVENT.MANAGER.EXECUTE.STEP".
354 rule "EVENT.MANAGER.ACCEPT"
357 $manager : UsecasesEventManager(
360 getState() == State.POLICY_LOADED,
361 $step : getSteps().peek(),
363 $step.isPreprocessed(),
364 $step.acceptsEvent() )
367 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
368 logger.info("{}: {}.{}: manager={}",
369 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
373 $manager.setAccepted(true);
375 VirtualControlLoopNotification notification = $manager.makeNotification();
376 notification.setNotification(ControlLoopNotificationType.ACTIVE);
377 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
378 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
380 } catch(RuntimeException e) {
381 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
382 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
384 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to accept the event");
392 * Ready to execute the step.
395 rule "EVENT.MANAGER.EXECUTE.STEP"
397 $manager : UsecasesEventManager(
399 getState() == State.POLICY_LOADED,
400 $step : getSteps().peek(),
402 $step.isPreprocessed() )
405 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
406 logger.info("{}: {}.{}: {} manager={}",
407 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
412 $step.setProperties();
414 boolean guardDisabled = "true".equalsIgnoreCase(
415 PolicyEngineConstants.getManager().getEnvironmentProperty(
416 ControlLoopEventManager.GUARD_DISABLED_PROPERTY));
418 if (guardDisabled && XacmlActor.NAME.equals($step.getActorName())) {
419 // guard is disabled - just enqueue a "SUCCESS" (i.e., "Permit")
420 OperationOutcome outcome = $step.getParams().makeOutcome();
421 outcome.setStart(Instant.now());
422 outcome.setEnd(outcome.getStart());
424 $manager.getOutcomes().add(outcome);
425 $manager.setState(State.AWAITING_OUTCOME);
427 } else if ($manager.executeStep()) {
428 $manager.setState(State.AWAITING_OUTCOME);
431 // this step is no longer necessary - try the next one
435 } catch(RuntimeException e) {
436 logger.warn("{}: {}.{}: manager={} exception executing a step",
437 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
439 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to execute the next step");
447 * Generate SDNR notification. Does not discard the outcome from the queue, leaving it to be
448 * handled by rule "EVENT.MANAGER.PROCESS.OUTCOME".
451 rule "EVENT.MANAGER.GENERATE.SDNR.NOTIFICATION"
452 // this should fire BEFORE the "EVENT.MANAGER.PROCESS.OUTCOME" rule
455 $manager : UsecasesEventManager(
457 getState() == State.AWAITING_OUTCOME,
458 $outcome : getOutcomes().peek(),
460 $outcome.getEnd() != null,
462 $step : getSteps().peek(),
463 "SDNR".equals($step.getActorName()),
464 $outcome.isFor("SDNR", $step.getOperationName()) )
467 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
468 logger.info("{}: {}.{}: {} manager={}",
469 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
473 ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome);
474 $manager.deliver("DCAE_CL_RSP", clResponse, "SDNR notification", drools.getRule().getName());
476 } catch(RuntimeException e) {
477 logger.warn("{}: {}.{}: manager={} exception generating SDNR Response notification",
478 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
485 * Process a GUARD outcome. Does not discard the outcome from the queue, leaving it to be
486 * handled by rule "EVENT.MANAGER.PROCESS.OUTCOME".
489 rule "EVENT.MANAGER.PROCESS.GUARD.OUTCOME"
492 $manager : UsecasesEventManager(
494 getState() == State.AWAITING_OUTCOME,
495 $outcome : getOutcomes().peek(),
498 $step : getSteps().peek(),
499 XacmlActor.NAME.equals($step.getActorName()),
500 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
503 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
504 logger.info("{}: {}.{}: {} manager={}",
505 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
509 VirtualControlLoopNotification notification = $manager.makeNotification();
510 notification.setNotification(ControlLoopNotificationType.OPERATION);
511 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
512 notification.setHistory(Collections.emptyList());
514 // get actor/operation name from the policy step, not from the guard step
515 Step step2 = $step.getParentStep();
517 if ($outcome.getEnd() == null) {
518 // it's a "start" operation
519 notification.setMessage("Sending guard query for " + step2.getActorName() + " " + step2.getOperationName());
521 } else if ($outcome.getResult() == OperationResult.SUCCESS) {
522 notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName()
526 notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName()
530 $manager.deliver("POLICY-CL-MGT", notification, "GUARD notification", drools.getRule().getName());
532 } catch(RuntimeException e) {
533 logger.warn("{}: {}.{}: manager={} exception generating GUARD notification",
534 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
541 * Process an outcome when the policy's operation starts.
544 rule "EVENT.MANAGER.PROCESS.POLICY.STARTED"
546 $manager : UsecasesEventManager(
548 getState() == State.AWAITING_OUTCOME,
549 $outcome : getOutcomes().peek(),
551 $outcome.getEnd() == null,
552 $step : getSteps().peek(),
553 $step.isPolicyStep(),
554 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
557 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
558 logger.info("{}: {}.{}: {} manager={}",
559 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
563 $manager.getOutcomes().remove();
565 // it's a "start" operation for the step
566 $manager.bumpAttempts();
568 $manager.addToHistory($outcome);
569 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
571 VirtualControlLoopNotification notification = $manager.makeNotification();
572 notification.setNotification(ControlLoopNotificationType.OPERATION);
573 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
574 notification.setHistory(Collections.emptyList());
575 notification.setMessage($manager.getOperationMessage());
577 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
579 } catch(RuntimeException e) {
580 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
581 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
583 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'start' outcome");
591 * Process an outcome when an arbitrary Preprocessor step starts.
594 rule "EVENT.MANAGER.PROCESS.PREPROCESSOR.STARTED"
596 $manager : UsecasesEventManager(
598 getState() == State.AWAITING_OUTCOME,
599 $outcome : getOutcomes().peek(),
601 $outcome.getEnd() == null,
602 $step : getSteps().peek(),
603 !$step.isPolicyStep(),
604 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
607 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
608 logger.info("{}: {}.{}: {} manager={}",
609 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
613 $manager.getOutcomes().remove();
615 // it's a "start" operation for the step
616 $manager.bumpAttempts();
618 } catch(RuntimeException e) {
619 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
620 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
622 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle 'start' outcome");
630 * Process an outcome when the policy's operation succeeds.
633 rule "EVENT.MANAGER.PROCESS.POLICY.SUCCESS"
635 $manager : UsecasesEventManager(
637 getState() == State.AWAITING_OUTCOME,
638 $outcome : getOutcomes().peek(),
640 $outcome.getEnd() != null,
641 $outcome.getResult() == OperationResult.SUCCESS,
642 $step : getSteps().peek(),
643 $step.isPolicyStep(),
644 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
647 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
648 logger.info("{}: {}.{}: {} manager={}",
649 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
653 $manager.getOutcomes().remove();
655 // let the step record the response that's contained within the outcome
656 $step.success($outcome);
658 $manager.addToHistory($outcome);
659 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
661 $manager.setResult($outcome.getResult());
663 VirtualControlLoopNotification notification = $manager.makeNotification();
664 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
665 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
666 notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
667 .collect(Collectors.toList()));
669 // this step is complete - discard it
670 $manager.getSteps().remove();
672 $manager.setState(State.POLICY_LOADED);
674 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
676 } catch(RuntimeException e) {
677 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
678 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
680 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'success' outcome");
688 * Process a final failure outcome, when the event has been accepted.
691 rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.ACCEPTED"
693 $manager : UsecasesEventManager(
696 getState() == State.AWAITING_OUTCOME,
697 $outcome : getOutcomes().peek(),
700 $outcome.getEnd() != null,
701 $outcome.isFinalOutcome(),
702 $outcome.getResult() != OperationResult.SUCCESS,
703 $step : getSteps().peek() )
706 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
707 logger.info("{}: {}.{}: {} manager={}",
708 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
712 $manager.getOutcomes().remove();
714 if (!$outcome.isFor($step.getActorName(), $step.getOperationName())) {
715 $outcome.setResult(OperationResult.FAILURE_GUARD);
716 $outcome.setMessage("Operation denied by " + $outcome.getActor());
719 // final failure for this policy
720 $manager.addToHistory($outcome);
721 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
723 $manager.setResult($outcome.getResult());
725 VirtualControlLoopNotification notification = $manager.makeNotification();
726 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
727 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
728 notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
729 .collect(Collectors.toList()));
731 // trigger move to the next policy - clear all steps
732 $manager.getSteps().clear();
733 $manager.setState(State.POLICY_LOADED);
735 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
737 } catch(RuntimeException e) {
738 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
739 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
741 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome");
749 * Process a final failure outcome, when the event has NOT been accepted. This typically
750 * occurs when an A&AI query fails BEFORE the first lock has been requested (and thus
751 * before the first policy's operation has been started).
754 rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.REJECTED"
756 $manager : UsecasesEventManager(
759 getState() == State.AWAITING_OUTCOME,
760 $outcome : getOutcomes().peek(),
763 $outcome.getEnd() != null,
764 $outcome.isFinalOutcome(),
765 $outcome.getResult() != OperationResult.SUCCESS,
766 $step : getSteps().peek() )
769 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
770 logger.info("{}: {}.{}: {} manager={}",
771 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
777 // final failure for this policy
778 $manager.addToHistory($outcome);
780 $manager.setResult($outcome.getResult());
782 VirtualControlLoopNotification notification = $manager.makeNotification();
783 notification.setNotification(ControlLoopNotificationType.REJECTED);
784 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
785 notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
786 .collect(Collectors.toList()));
788 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
790 } catch(RuntimeException e) {
791 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
792 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
794 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to reject event");
802 * Process an outcome when the policy's operation fails.
805 rule "EVENT.MANAGER.PROCESS.POLICY.FAILURE"
807 $manager : UsecasesEventManager(
809 getState() == State.AWAITING_OUTCOME,
810 $outcome : getOutcomes().peek(),
813 $outcome.getEnd() != null,
814 !$outcome.isFinalOutcome(),
815 $outcome.getResult() != OperationResult.SUCCESS,
816 $step : getSteps().peek(),
817 $step.isPolicyStep(),
818 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
821 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
822 logger.info("{}: {}.{}: {} manager={}",
823 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
827 // not a final failure, thus it will be retried automatically
829 $manager.getOutcomes().remove();
831 // do NOT invoke manager.setResult()
833 $manager.addToHistory($outcome);
834 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
836 VirtualControlLoopNotification notification = $manager.makeNotification();
837 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
838 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
840 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
842 } catch(RuntimeException e) {
843 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
844 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
846 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome");
854 * Discard an outcome that was not handled by any other rule.
857 rule "EVENT.MANAGER.DISCARD.OUTCOME"
860 $manager : UsecasesEventManager(
862 getState() == State.AWAITING_OUTCOME,
863 $outcome : getOutcomes().peek(),
865 $step : getSteps().peek() )
868 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
869 logger.info("{}: {}.{}: {} {} manager={}",
870 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
871 $step, $outcome.getResult(), $manager);
874 $manager.getOutcomes().remove();
876 if ($outcome.getEnd() != null && $outcome.isFor($step.getActorName(), $step.getOperationName())) {
877 // it's a completion for the step
879 // let the step record the response that's contained within the outcome
880 if ($outcome.getResult() == OperationResult.SUCCESS) {
881 $step.success($outcome);
884 // this step is complete - discard it
885 $manager.getSteps().remove();
887 $manager.setState(State.POLICY_LOADED);
890 } catch(RuntimeException e) {
891 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
892 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
894 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle outcome");
902 * Abort processing. This can happen in any state (once the manager has been started).
905 rule "EVENT.MANAGER.ABORT"
907 $manager : UsecasesEventManager(
909 getState() != State.DONE,
910 $outcome : getOutcomes().peek(),
913 $step : getSteps().peek() )
916 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
917 logger.info("{}: {}.{}: {} manager={}",
918 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
922 // determine the final message
924 switch ($outcome.getActor()) {
925 case ActorConstants.CL_TIMEOUT_ACTOR:
926 msg = "Control Loop timed out";
928 case ActorConstants.LOCK_ACTOR:
929 msg = "Target Lock was lost";
932 msg = "Processing aborted by " + $outcome.getActor();
936 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE, msg);
938 if ($step != null && "SDNR".equals($step.getActorName())
939 && $outcome.isFor($step.getActorName(), $step.getOperationName())) {
941 // aborted while processing the SDNR step - generate a notification
942 ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome);
943 $manager.deliver("DCAE_CL_RSP", clResponse, "SDNR notification", drools.getRule().getName());
947 $outcome.setActor($step.getActorName());
948 $outcome.setOperation($step.getOperationName());
950 $manager.addToHistory($outcome);
951 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
954 } catch(RuntimeException e) {
955 logger.warn("{}: {}.{}: manager={} exception handling ABORT outcome",
956 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
958 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle ABORT");
966 * Done processing. Arriving here implies that the event has been accepted.
969 rule "EVENT.MANAGER.FINAL"
971 $manager : UsecasesEventManager(
972 !isActive() || getState() == State.DONE )
975 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
976 logger.info("{}: {}.{}: manager={}",
977 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
983 VirtualControlLoopNotification notification = $manager.makeNotification();
984 notification.setPolicyName($manager.getPolicyName() + "." + drools.getRule().getName());
985 notification.setHistory($manager.getFullHistory().stream().map(OperationOutcome2::getClOperation)
986 .collect(Collectors.toList()));
988 OperationFinalResult finalResult = $manager.getFinalResult();
989 if (finalResult == null) {
990 finalResult = ($manager.isActive() ? OperationFinalResult.FINAL_SUCCESS : OperationFinalResult.FINAL_FAILURE);
993 switch (finalResult) {
994 case FINAL_FAILURE_EXCEPTION:
995 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
996 notification.setMessage("Exception in processing closed loop");
999 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
1001 case FINAL_OPENLOOP:
1002 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
1006 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
1010 if ($manager.getFinalMessage() != null) {
1011 notification.setMessage($manager.getFinalMessage());
1014 $manager.deliver("POLICY-CL-MGT", notification, "notification", drools.getRule().getName());
1016 } catch(RuntimeException e) {
1017 logger.warn("{}: {}.{}: manager={} exception generating final notification",
1018 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
1027 * This rule will clean up any rogue events where there is no
1028 * ControlLoopParams object corresponding to the onset event.
1031 rule "EVENT.CLEANUP"
1034 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1037 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1038 logger.info("{}: {}", $clName, drools.getRule().getName());
1039 logger.debug("{}: {}: orphan event={}",
1040 $clName, drools.getRule().getName(), $event);
1042 // Retract the event
1049 * At this point, it appears that if we prevent the rules from getting messages from
1050 * topics, then that will also prevent the actors from getting them. So the following
1051 * rules are here just to discard those messages.
1053 * These have a higher salience so the objects are removed before the "FINAL" message
1054 * is processed, so that the junit test can assume things are done once they see the
1055 * "FINAL" message. Otherwise, tests might fail sporadically.
1058 rule "APPC.Response.CLEANUP"
1061 $msg : org.onap.policy.appc.Response( )
1066 rule "APPC.Request.CLEANUP"
1069 $msg : org.onap.policy.appc.Request( )
1074 rule "APPC-LCM.Response.CLEANUP"
1077 $msg : org.onap.policy.appclcm.AppcLcmDmaapWrapper( )
1082 rule "SDNR.Response.CLEANUP"
1085 $msg : org.onap.policy.sdnr.PciResponseWrapper( )