2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2020-2022 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2023-2024 Nordix Foundation.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.controlloop;
24 import java.time.Instant;
25 import java.util.Collections;
26 import java.util.stream.Collectors;
27 import org.onap.policy.controlloop.CanonicalOnset;
28 import org.onap.policy.controlloop.VirtualControlLoopEvent;
29 import org.onap.policy.controlloop.VirtualControlLoopNotification;
30 import org.onap.policy.controlloop.ControlLoopNotificationType;
31 import org.onap.policy.controlloop.actor.xacml.XacmlActor;
32 import org.onap.policy.controlloop.actorserviceprovider.Operation;
33 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
34 import org.onap.policy.controlloop.actorserviceprovider.OperationFinalResult;
35 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
36 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
37 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
38 import org.onap.policy.controlloop.eventmanager.ActorConstants;
39 import org.onap.policy.controlloop.eventmanager.Step;
40 import org.onap.policy.controlloop.utils.ControlLoopUtils;
41 import org.onap.policy.drools.apps.controller.usecases.UsecasesEventManager;
42 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithSteps.State;
43 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithOutcome.OperationOutcome2;
44 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithEvent.NewEventStatus;
45 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
46 import org.onap.policy.controlloop.eventmanager.EventManagerServices;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
49 import org.slf4j.LoggerFactory;
50 import org.slf4j.Logger;
52 import org.onap.policy.drools.system.PolicyEngineConstants;
56 * Called at initial start-up, to create the event services that will be used by all
57 * event managers in this rule engine instance.
59 rule "CREATE.EVENT.SERVICES"
61 not (EventManagerServices())
64 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
65 logger.info("{}", drools.getRule().getName());
68 insert(new EventManagerServices("event-manager"));
70 } catch(RuntimeException e) {
71 logger.warn("{}: cannot create event services", drools.getRule().getName(), e);
77 * Called when the ControlLoopParams object has been inserted into working memory from the PAP.
82 $params : ControlLoopParams()
85 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
86 logger.info("{}: {} : TOSCA-POLICY=[{}]", $params.getClosedLoopControlName(), $params.getPolicyName() + "."
87 + drools.getRule().getName(), $params.getToscaPolicy());
92 * Called when a Tosca Policy is present.
95 rule "NEW.TOSCA.POLICY"
97 $policy : ToscaPolicy()
100 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
101 logger.info("{}: [{}|{}|{}|{}]: CONTENT: {}", drools.getRule().getName(),
102 $policy.getType(), $policy.getTypeVersion(), $policy.getName(),
103 $policy.getVersion(), $policy);
105 ControlLoopParams params = ControlLoopUtils.toControlLoopParams($policy);
106 if (params != null) {
112 * Remove Control Loop Parameters.
116 $params : ControlLoopParams( $policyName : getPolicyName(), $policyVersion : getPolicyVersion() )
117 not ( ToscaPolicy( getName() == $policyName, getVersion() == $policyVersion ) )
120 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
121 logger.info("{}: [{}|{}|{}]", drools.getRule().getName(),
122 $params.getPolicyScope(), $params.getPolicyName(), $params.getPolicyVersion());
129 * This rule responds to DCAE Events where there is no manager yet. Either it is
130 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
135 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
136 $event : CanonicalOnset( closedLoopControlName == $clName )
137 $services : EventManagerServices()
138 not ( UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
139 getEvent() == $event ) )
142 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
143 logger.info("{}: {}.{}: event={}",
144 $clName, $params.getPolicyName(), drools.getRule().getName(),
147 // Retract the event from memory; it will be managed by the manager from now on
151 VirtualControlLoopNotification notification = null;
155 // Check the event, because we need it to not be null when
156 // we create the UsecasesEventManager. The UsecasesEventManager
157 // will do extra syntax checking as well as check if the closed loop is disabled.
159 if ($event.getRequestId() == null) {
160 notification = new VirtualControlLoopNotification($event);
161 notification.setNotification(ControlLoopNotificationType.REJECTED);
162 notification.setFrom("policy");
163 notification.setMessage("Missing requestId");
164 notification.setPolicyScope(drools.getRule().getName());
165 notification.setPolicyName($params.getPolicyName());
166 notification.setPolicyVersion($params.getPolicyVersion());
169 UsecasesEventManager manager =
170 new UsecasesEventManager($services, $params, $event, drools.getWorkingMemory());
173 // load the first policy/step
176 if (manager.getSteps().isEmpty()) {
177 // no steps imply no policies, thus go straight to DONE state
178 manager.setState(State.DONE);
180 manager.setAccepted(true);
182 notification = manager.makeNotification();
183 notification.setNotification(ControlLoopNotificationType.ACTIVE);
184 notification.setPolicyScope(drools.getRule().getName());
185 notification.setPolicyName($params.getPolicyName());
186 notification.setPolicyVersion($params.getPolicyVersion());
189 // Note: the notification will be generated lazily
190 manager.setState(State.POLICY_LOADED);
193 } catch(Exception e) {
198 } catch (Exception e) {
199 logger.warn("{}: {}.{}: error starting manager", $clName, $params.getPolicyName(),
200 drools.getRule().getName(), e);
201 notification = new VirtualControlLoopNotification($event);
202 notification.setNotification(ControlLoopNotificationType.REJECTED);
203 notification.setMessage("Exception occurred: " + e.getMessage());
204 notification.setPolicyScope(drools.getRule().getName());
205 notification.setPolicyName($params.getPolicyName());
206 notification.setPolicyVersion($params.getPolicyVersion());
209 // Generate notification
212 if (notification != null) {
213 PolicyEngineConstants.getManager().deliver("policy-cl-mgt", notification);
216 } catch(RuntimeException e) {
217 logger.warn("{}: {}.{}: event={} exception generating notification",
218 $clName, $params.getPolicyName(), drools.getRule().getName(),
225 * This rule fires when we get a subsequent event.
228 rule "EVENT.MANAGER.NEW.EVENT"
230 $event : VirtualControlLoopEvent( )
231 $manager : UsecasesEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
232 getEvent() == $event )
235 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
236 logger.info("{}: {}.{}: event={} manager={}",
237 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
240 // Remove the event from memory
245 // Check what kind of event this is
247 switch($manager.onNewEvent($event)) {
250 // Ignore any bad syntax events
252 logger.warn("{}: {}.{}: syntax error",
253 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
256 case FIRST_ABATEMENT:
257 case SUBSEQUENT_ABATEMENT:
259 // TODO: handle the abatement. Currently, it's just discarded.
261 logger.info("{}: {}.{}: abatement",
262 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
266 case SUBSEQUENT_ONSET:
269 // We don't care about subsequent onsets
271 logger.warn("{}: {}.{}: subsequent onset",
272 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName());
279 * All steps have been executed, load the next policy.
282 rule "EVENT.MANAGER.LOAD.NEXT.POLICY"
284 $manager : UsecasesEventManager(
286 getState() == State.POLICY_LOADED,
287 getSteps().isEmpty() )
290 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
291 logger.info("{}: {}.{}: manager={}",
292 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
296 $manager.loadNextPolicy($manager.getResult());
298 if ($manager.getSteps().isEmpty()) {
299 // no steps - must be the final policy
300 $manager.setState(State.DONE);
303 } catch(RuntimeException e) {
304 logger.warn("{}: {}.{}: manager={} exception loading next policy",
305 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
307 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to load next policy");
315 * Policy loaded, identify any preprocessor steps that need to be run first.
318 rule "EVENT.MANAGER.PREPROCESS"
320 $manager : UsecasesEventManager(
322 getState() == State.POLICY_LOADED,
323 $step : getSteps().peek(),
325 !$step.isPreprocessed() )
328 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
329 logger.info("{}: {}.{}: {} manager={}",
330 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
335 * Load any preprocessor steps.
337 * Note: this will not change the state of the manager, but it may change the
340 $step.setPreprocessed(true);
341 $manager.loadPreprocessorSteps();
343 } catch(RuntimeException e) {
344 logger.warn("{}: {}.{}: manager={} exception loading preprocessor steps",
345 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
347 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to load preprocessing steps");
355 * Accepts the event, when ready to execute a step of interest. Does not change the
356 * state of the manager, leaving that to be done by rule "EVENT.MANAGER.EXECUTE.STEP".
359 rule "EVENT.MANAGER.ACCEPT"
362 $manager : UsecasesEventManager(
365 getState() == State.POLICY_LOADED,
366 $step : getSteps().peek(),
368 $step.isPreprocessed(),
369 $step.acceptsEvent() )
372 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
373 logger.info("{}: {}.{}: manager={}",
374 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
378 $manager.setAccepted(true);
380 VirtualControlLoopNotification notification = $manager.makeNotification();
381 notification.setNotification(ControlLoopNotificationType.ACTIVE);
382 notification.setPolicyScope(drools.getRule().getName());
383 notification.setPolicyName($manager.getPolicyName());
384 notification.setPolicyVersion($manager.getPolicyVersion());
385 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
387 } catch(RuntimeException e) {
388 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
389 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
391 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to accept the event");
399 * Ready to execute the step.
402 rule "EVENT.MANAGER.EXECUTE.STEP"
404 $manager : UsecasesEventManager(
406 getState() == State.POLICY_LOADED,
407 $step : getSteps().peek(),
409 $step.isPreprocessed() )
412 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
413 logger.info("{}: {}.{}: {} manager={}",
414 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
419 $step.setProperties();
421 boolean guardDisabled = "true".equalsIgnoreCase(
422 PolicyEngineConstants.getManager().getEnvironmentProperty(
423 ControlLoopEventManager.GUARD_DISABLED_PROPERTY));
425 if (guardDisabled && XacmlActor.NAME.equals($step.getActorName())) {
426 // guard is disabled - just enqueue a "SUCCESS" (i.e., "Permit")
427 OperationOutcome outcome = $step.getParams().makeOutcome();
428 outcome.setStart(Instant.now());
429 outcome.setEnd(outcome.getStart());
431 $manager.getOutcomes().add(outcome);
432 $manager.setState(State.AWAITING_OUTCOME);
434 } else if ($manager.executeStep()) {
435 $manager.setState(State.AWAITING_OUTCOME);
438 // this step is no longer necessary - try the next one
442 } catch(RuntimeException e) {
443 logger.warn("{}: {}.{}: manager={} exception executing a step",
444 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
446 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to execute the next step");
454 * Generate SDNR notification. Does not discard the outcome from the queue, leaving it to be
455 * handled by rule "EVENT.MANAGER.PROCESS.OUTCOME".
458 rule "EVENT.MANAGER.GENERATE.SDNR.NOTIFICATION"
459 // this should fire BEFORE the "EVENT.MANAGER.PROCESS.OUTCOME" rule
462 $manager : UsecasesEventManager(
464 getState() == State.AWAITING_OUTCOME,
465 $outcome : getOutcomes().peek(),
467 $outcome.getEnd() != null,
469 $step : getSteps().peek(),
470 "SDNR".equals($step.getActorName()),
471 $outcome.isFor("SDNR", $step.getOperationName()) )
474 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
475 logger.info("{}: {}.{}: {} manager={}",
476 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
480 ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome);
481 $manager.deliver("dcae_cl_rsp", clResponse, "SDNR notification", drools.getRule().getName());
483 } catch(RuntimeException e) {
484 logger.warn("{}: {}.{}: manager={} exception generating SDNR Response notification",
485 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
492 * Process a GUARD outcome. Does not discard the outcome from the queue, leaving it to be
493 * handled by rule "EVENT.MANAGER.PROCESS.OUTCOME".
496 rule "EVENT.MANAGER.PROCESS.GUARD.OUTCOME"
499 $manager : UsecasesEventManager(
501 getState() == State.AWAITING_OUTCOME,
502 $outcome : getOutcomes().peek(),
505 $step : getSteps().peek(),
506 XacmlActor.NAME.equals($step.getActorName()),
507 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
510 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
511 logger.info("{}: {}.{}: {} manager={}",
512 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
516 VirtualControlLoopNotification notification = $manager.makeNotification();
517 notification.setNotification(ControlLoopNotificationType.OPERATION);
518 notification.setPolicyScope(drools.getRule().getName());
519 notification.setPolicyName($manager.getPolicyName());
520 notification.setPolicyVersion($manager.getPolicyVersion());
521 notification.setHistory(Collections.emptyList());
523 // get actor/operation name from the policy step, not from the guard step
524 Step step2 = $step.getParentStep();
526 if ($outcome.getEnd() == null) {
527 // it's a "start" operation
528 notification.setMessage("Sending guard query for " + step2.getActorName() + " " + step2.getOperationName());
530 } else if ($outcome.getResult() == OperationResult.SUCCESS) {
531 notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName()
535 notification.setMessage("Guard result for " + step2.getActorName() + " " + step2.getOperationName()
539 $manager.deliver("policy-cl-mgt", notification, "GUARD notification", drools.getRule().getName());
541 } catch(RuntimeException e) {
542 logger.warn("{}: {}.{}: manager={} exception generating GUARD notification",
543 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
550 * Process an outcome when the policy's operation starts.
553 rule "EVENT.MANAGER.PROCESS.POLICY.STARTED"
555 $manager : UsecasesEventManager(
557 getState() == State.AWAITING_OUTCOME,
558 $outcome : getOutcomes().peek(),
560 $outcome.getEnd() == null,
561 $step : getSteps().peek(),
562 $step.isPolicyStep(),
563 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
566 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
567 logger.info("{}: {}.{}: {} manager={}",
568 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
572 $manager.getOutcomes().remove();
574 // it's a "start" operation for the step
575 $manager.bumpAttempts();
577 $manager.addToHistory($outcome);
578 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
580 VirtualControlLoopNotification notification = $manager.makeNotification();
581 notification.setNotification(ControlLoopNotificationType.OPERATION);
582 notification.setPolicyScope(drools.getRule().getName());
583 notification.setPolicyName($manager.getPolicyName());
584 notification.setPolicyVersion($manager.getPolicyVersion());
585 notification.setHistory(Collections.emptyList());
586 notification.setMessage($manager.getOperationMessage());
588 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
590 } catch(RuntimeException e) {
591 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
592 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
594 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'start' outcome");
602 * Process an outcome when an arbitrary Preprocessor step starts.
605 rule "EVENT.MANAGER.PROCESS.PREPROCESSOR.STARTED"
607 $manager : UsecasesEventManager(
609 getState() == State.AWAITING_OUTCOME,
610 $outcome : getOutcomes().peek(),
612 $outcome.getEnd() == null,
613 $step : getSteps().peek(),
614 !$step.isPolicyStep(),
615 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
618 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
619 logger.info("{}: {}.{}: {} manager={}",
620 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
624 $manager.getOutcomes().remove();
626 // it's a "start" operation for the step
627 $manager.bumpAttempts();
629 } catch(RuntimeException e) {
630 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
631 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
633 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle 'start' outcome");
641 * Process an outcome when the policy's operation succeeds.
644 rule "EVENT.MANAGER.PROCESS.POLICY.SUCCESS"
646 $manager : UsecasesEventManager(
648 getState() == State.AWAITING_OUTCOME,
649 $outcome : getOutcomes().peek(),
651 $outcome.getEnd() != null,
652 $outcome.getResult() == OperationResult.SUCCESS,
653 $step : getSteps().peek(),
654 $step.isPolicyStep(),
655 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
658 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
659 logger.info("{}: {}.{}: {} manager={}",
660 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
664 $manager.getOutcomes().remove();
666 // let the step record the response that's contained within the outcome
667 $step.success($outcome);
669 $manager.addToHistory($outcome);
670 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
672 $manager.setResult($outcome.getResult());
674 VirtualControlLoopNotification notification = $manager.makeNotification();
675 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
676 notification.setPolicyScope(drools.getRule().getName());
677 notification.setPolicyName($manager.getPolicyName());
678 notification.setPolicyVersion($manager.getPolicyVersion());
679 notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
680 .collect(Collectors.toList()));
682 // this step is complete - discard it
683 $manager.getSteps().remove();
685 $manager.setState(State.POLICY_LOADED);
687 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
689 } catch(RuntimeException e) {
690 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
691 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
693 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'success' outcome");
701 * Process a final failure outcome, when the event has been accepted.
704 rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.ACCEPTED"
706 $manager : UsecasesEventManager(
709 getState() == State.AWAITING_OUTCOME,
710 $outcome : getOutcomes().peek(),
713 $outcome.getEnd() != null,
714 $outcome.isFinalOutcome(),
715 $outcome.getResult() != OperationResult.SUCCESS,
716 $step : getSteps().peek() )
719 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
720 logger.info("{}: {}.{}: {} manager={}",
721 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
725 $manager.getOutcomes().remove();
727 if (!$outcome.isFor($step.getActorName(), $step.getOperationName())) {
728 $outcome.setResult(OperationResult.FAILURE_GUARD);
729 $outcome.setMessage("Operation denied by " + $outcome.getActor());
732 // final failure for this policy
733 $manager.addToHistory($outcome);
734 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
736 $manager.setResult($outcome.getResult());
738 VirtualControlLoopNotification notification = $manager.makeNotification();
739 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
740 notification.setPolicyScope(drools.getRule().getName());
741 notification.setPolicyName($manager.getPolicyName());
742 notification.setPolicyVersion($manager.getPolicyVersion());
743 notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
746 // trigger move to the next policy - clear all steps
747 $manager.getSteps().clear();
748 $manager.setState(State.POLICY_LOADED);
750 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
752 } catch(RuntimeException e) {
753 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
754 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
756 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome");
764 * Process a final failure outcome, when the event has NOT been accepted. This typically
765 * occurs when an A&AI query fails BEFORE the first lock has been requested (and thus
766 * before the first policy's operation has been started).
769 rule "EVENT.MANAGER.PROCESS.FINAL.FAILURE.REJECTED"
771 $manager : UsecasesEventManager(
774 getState() == State.AWAITING_OUTCOME,
775 $outcome : getOutcomes().peek(),
778 $outcome.getEnd() != null,
779 $outcome.isFinalOutcome(),
780 $outcome.getResult() != OperationResult.SUCCESS,
781 $step : getSteps().peek() )
784 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
785 logger.info("{}: {}.{}: {} manager={}",
786 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
792 // final failure for this policy
793 $manager.addToHistory($outcome);
795 $manager.setResult($outcome.getResult());
797 VirtualControlLoopNotification notification = $manager.makeNotification();
798 notification.setNotification(ControlLoopNotificationType.REJECTED);
799 notification.setPolicyScope(drools.getRule().getName());
800 notification.setPolicyName($manager.getPolicyName());
801 notification.setPolicyVersion($manager.getPolicyVersion());
802 notification.setHistory($manager.getPartialHistory().stream().map(OperationOutcome2::getClOperation)
805 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
807 } catch(RuntimeException e) {
808 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
809 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
811 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to reject event");
819 * Process an outcome when the policy's operation fails.
822 rule "EVENT.MANAGER.PROCESS.POLICY.FAILURE"
824 $manager : UsecasesEventManager(
826 getState() == State.AWAITING_OUTCOME,
827 $outcome : getOutcomes().peek(),
830 $outcome.getEnd() != null,
831 !$outcome.isFinalOutcome(),
832 $outcome.getResult() != OperationResult.SUCCESS,
833 $step : getSteps().peek(),
834 $step.isPolicyStep(),
835 $outcome.isFor($step.getActorName(), $step.getOperationName()) )
838 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
839 logger.info("{}: {}.{}: {} manager={}",
840 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
844 // not a final failure, thus it will be retried automatically
846 $manager.getOutcomes().remove();
848 // do NOT invoke manager.setResult()
850 $manager.addToHistory($outcome);
851 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
853 VirtualControlLoopNotification notification = $manager.makeNotification();
854 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
855 notification.setPolicyScope(drools.getRule().getName());
856 notification.setPolicyName($manager.getPolicyName());
857 notification.setPolicyVersion($manager.getPolicyVersion());
859 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
861 } catch(RuntimeException e) {
862 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
863 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
865 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle policy 'failure' outcome");
873 * Discard an outcome that was not handled by any other rule.
876 rule "EVENT.MANAGER.DISCARD.OUTCOME"
879 $manager : UsecasesEventManager(
881 getState() == State.AWAITING_OUTCOME,
882 $outcome : getOutcomes().peek(),
884 $step : getSteps().peek() )
887 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
888 logger.info("{}: {}.{}: {} {} manager={}",
889 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
890 $step, $outcome.getResult(), $manager);
893 $manager.getOutcomes().remove();
895 if ($outcome.getEnd() != null && $outcome.isFor($step.getActorName(), $step.getOperationName())) {
896 // it's a completion for the step
898 // let the step record the response that's contained within the outcome
899 if ($outcome.getResult() == OperationResult.SUCCESS) {
900 $step.success($outcome);
903 // this step is complete - discard it
904 $manager.getSteps().remove();
906 $manager.setState(State.POLICY_LOADED);
909 } catch(RuntimeException e) {
910 logger.warn("{}: {}.{}: manager={} exception processing operation outcome",
911 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
913 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle outcome");
921 * Abort processing. This can happen in any state (once the manager has been started).
924 rule "EVENT.MANAGER.ABORT"
926 $manager : UsecasesEventManager(
928 getState() != State.DONE,
929 $outcome : getOutcomes().peek(),
932 $step : getSteps().peek() )
935 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
936 logger.info("{}: {}.{}: {} manager={}",
937 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
941 // determine the final message
943 switch ($outcome.getActor()) {
944 case ActorConstants.CL_TIMEOUT_ACTOR:
945 msg = "Control Loop timed out";
947 case ActorConstants.LOCK_ACTOR:
948 msg = "Target Lock was lost";
951 msg = "Processing aborted by " + $outcome.getActor();
955 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE, msg);
957 if ($step != null && "SDNR".equals($step.getActorName())
958 && $outcome.isFor($step.getActorName(), $step.getOperationName())) {
960 // aborted while processing the SDNR step - generate a notification
961 ControlLoopResponse clResponse = $manager.makeControlLoopResponse($outcome);
962 $manager.deliver("dcae_cl_rsp", clResponse, "SDNR notification", drools.getRule().getName());
966 $outcome.setActor($step.getActorName());
967 $outcome.setOperation($step.getOperationName());
969 $manager.addToHistory($outcome);
970 $manager.storeInDataBase($manager.getPartialHistory().peekLast());
973 } catch(RuntimeException e) {
974 logger.warn("{}: {}.{}: manager={} exception handling ABORT outcome",
975 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
977 $manager.abort(State.DONE, OperationFinalResult.FINAL_FAILURE_EXCEPTION, "failed to handle ABORT");
985 * Done processing. Arriving here implies that the event has been accepted.
988 rule "EVENT.MANAGER.FINAL"
990 $manager : UsecasesEventManager(
991 !isActive() || getState() == State.DONE )
994 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
995 logger.info("{}: {}.{}: manager={}",
996 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
1002 VirtualControlLoopNotification notification = $manager.makeNotification();
1003 notification.setPolicyScope(drools.getRule().getName());
1004 notification.setPolicyName($manager.getPolicyName());
1005 notification.setPolicyVersion($manager.getPolicyVersion());
1006 notification.setHistory($manager.getFullHistory().stream().map(OperationOutcome2::getClOperation)
1009 OperationFinalResult finalResult = $manager.getFinalResult();
1010 if (finalResult == null) {
1011 finalResult = ($manager.isActive() ? OperationFinalResult.FINAL_SUCCESS : OperationFinalResult.FINAL_FAILURE);
1014 switch (finalResult) {
1015 case FINAL_FAILURE_EXCEPTION:
1016 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
1017 notification.setMessage("Exception in processing closed loop");
1020 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
1022 case FINAL_OPENLOOP:
1023 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
1027 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
1031 if ($manager.getFinalMessage() != null) {
1032 notification.setMessage($manager.getFinalMessage());
1035 $manager.deliver("policy-cl-mgt", notification, "notification", drools.getRule().getName());
1037 } catch(RuntimeException e) {
1038 logger.warn("{}: {}.{}: manager={} exception generating final notification",
1039 $manager.getClosedLoopControlName(), $manager.getPolicyName(), drools.getRule().getName(),
1048 * This rule will clean up any rogue events where there is no
1049 * ControlLoopParams object corresponding to the onset event.
1052 rule "EVENT.CLEANUP"
1055 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1058 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackageName());
1059 logger.info("{}: {}", $clName, drools.getRule().getName());
1060 logger.debug("{}: {}: orphan event={}",
1061 $clName, drools.getRule().getName(), $event);
1063 // Retract the event
1070 * At this point, it appears that if we prevent the rules from getting messages from
1071 * topics, then that will also prevent the actors from getting them. So the following
1072 * rules are here just to discard those messages.
1074 * These have a higher salience so the objects are removed before the "FINAL" message
1075 * is processed, so that the junit test can assume things are done once they see the
1076 * "FINAL" message. Otherwise, tests might fail sporadically.
1079 rule "APPC.Response.CLEANUP"
1082 $msg : org.onap.policy.appc.Response( )
1087 rule "APPC.Request.CLEANUP"
1090 $msg : org.onap.policy.appc.Request( )
1095 rule "APPC-LCM.Response.CLEANUP"
1098 $msg : org.onap.policy.appclcm.AppcLcmMessageWrapper( )
1103 rule "SDNR.Response.CLEANUP"
1106 $msg : org.onap.policy.sdnr.PciResponseWrapper( )