2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 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 org.onap.policy.controlloop.VirtualControlLoopEvent;
24 import org.onap.policy.controlloop.VirtualControlLoopNotification;
25 import org.onap.policy.controlloop.ControlLoopEventStatus;
26 import org.onap.policy.controlloop.ControlLoopNotificationType;
27 import org.onap.policy.controlloop.ControlLoopLogger;
28 import org.onap.policy.controlloop.policy.PolicyResult;
29 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
30 import org.onap.policy.controlloop.policy.Policy;
31 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
32 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NEW_EVENT_STATUS;
33 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
34 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
35 import org.onap.policy.aai.AaiNqResponseWrapper;
36 import org.onap.policy.appc.Request;
37 import org.onap.policy.appc.Response;
38 import org.onap.policy.appc.CommonHeader;
39 import org.onap.policy.appclcm.LcmRequestWrapper;
40 import org.onap.policy.appclcm.LcmResponseWrapper;
41 import org.onap.policy.appclcm.LcmRequest;
42 import org.onap.policy.appclcm.LcmResponse;
43 import org.onap.policy.appclcm.LcmCommonHeader;
44 import org.onap.policy.sdnr.PciRequestWrapper;
45 import org.onap.policy.sdnr.PciResponseWrapper;
46 import org.onap.policy.sdnr.PciRequest;
47 import org.onap.policy.sdnr.PciResponse;
48 import org.onap.policy.vfc.VfcRequest;
49 import org.onap.policy.vfc.VfcResponse;
50 import org.onap.policy.vfc.VfcManager;
51 import org.onap.policy.so.SOManager;
52 import org.onap.policy.so.SORequest;
53 import org.onap.policy.so.SORequestStatus;
54 import org.onap.policy.so.SORequestDetails;
55 import org.onap.policy.so.SOModelInfo;
56 import org.onap.policy.so.SOCloudConfiguration;
57 import org.onap.policy.so.SORequestInfo;
58 import org.onap.policy.so.SORequestParameters;
59 import org.onap.policy.so.SORelatedInstanceListElement;
60 import org.onap.policy.so.SORelatedInstance;
61 import org.onap.policy.so.SOResponse;
62 import org.onap.policy.so.SOResponseWrapper;
63 import org.onap.policy.sdnc.SdncRequest;
64 import org.onap.policy.sdnc.SdncManager;
65 import org.onap.policy.sdnc.SdncResponse;
66 import org.onap.policy.guard.PolicyGuard;
67 import org.onap.policy.guard.PolicyGuard.LockResult;
68 import org.onap.policy.guard.TargetLock;
69 import org.onap.policy.guard.GuardResult;
70 import org.onap.policy.guard.PolicyGuardRequest;
71 import org.onap.policy.guard.PolicyGuardResponse;
72 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
73 import org.onap.policy.guard.PolicyGuardXacmlHelper;
75 import org.yaml.snakeyaml.Yaml;
76 import org.yaml.snakeyaml.constructor.Constructor;
78 import org.slf4j.LoggerFactory;
79 import org.slf4j.Logger;
81 import java.time.Instant;
82 import java.util.LinkedList;
83 import java.util.Iterator;
85 import org.onap.policy.drools.system.PolicyEngine;
88 * This structure mimics the Params structure.
89 * Its only purpose is to allow management of
90 * rules by the PAP component..
91 * It has no use at runtime since the rules go by
92 * Params for matching purposes.
95 closedLoopControlName : String
96 controlLoopYaml : String
100 * Control Loop Identity
103 closedLoopControlName : String
104 controlLoopYaml : String
108 * Used to trigger clean up Params that no longer have associated rules.
110 declare ParamsInitCleaner
111 closedLoopControlName : String // only used when logging
115 * Used to clean up Params that no longer have associated rules.
117 declare ParamsCleaner
118 closedLoopControlName : String
119 controlLoopYaml : String
123 * This object is to provide support for timeouts
124 * due to a bug in drools' built-in timers
126 declare ControlLoopTimer
127 closedLoopControlName : String
131 //timerType is the type of timer: either "ClosedLoop" or "Operation"
137 * Called to insert the parameters into working memory for this Closed Loop policy. This is called
138 * once each time a closed loop is added or its YAML is updated.
139 * This has a higher salience so we can ensure that the Params is created before we have a chance to
140 * discard any events.
143 rule "${policyName}.SETUP"
146 not( Params( getClosedLoopControlName() == "${closedLoopControlName}",
147 getControlLoopYaml() == "${controlLoopYaml}" ) )
150 Params params = new Params();
151 params.setClosedLoopControlName("${closedLoopControlName}");
152 params.setControlLoopYaml("${controlLoopYaml}");
155 ParamsInitCleaner initCleaner = new ParamsInitCleaner();
156 initCleaner.setClosedLoopControlName("${closedLoopControlName}");
159 // Note: globals have bad behavior when persistence is used,
160 // hence explicitly getting the logger vs using a global
162 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
163 logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(),
164 params.getControlLoopYaml());
169 * This rule responds to DCAE Events where there is no manager yet. Either it is
170 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
173 rule "${policyName}.EVENT"
175 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
176 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
177 not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
178 requestID == $event.getRequestId() ) )
181 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
182 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
187 // Check the event, because we need it to not be null when
188 // we create the ControlLoopEventManager. The ControlLoopEventManager
189 // will do extra syntax checking as well check if the closed loop is disabled.
191 if ($event.getRequestId() == null) {
192 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
193 notification.setNotification(ControlLoopNotificationType.REJECTED);
194 notification.setFrom("policy");
195 notification.setMessage("Missing requestId");
196 notification.setPolicyName(drools.getRule().getName());
197 notification.setPolicyScope("${policyScope}");
198 notification.setPolicyVersion("${policyVersion}");
201 // Let interested parties know
203 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
206 // Retract it from memory
209 } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
210 throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
213 // Create an EventManager
215 ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(),
216 $event.getRequestId());
218 // Determine if EventManager can actively process the event
219 // (i.e. syntax, is_closed_loop_disabled checks etc.)
221 VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
222 notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
223 notification.setPolicyName(drools.getRule().getName());
224 notification.setPolicyScope("${policyScope}");
225 notification.setPolicyVersion("${policyVersion}");
227 // Are we actively pursuing this event?
229 if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
231 // Insert Event Manager into memory, this will now kick off processing.
235 // Let interested parties know
237 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
239 // Setup the Overall Control Loop timer
241 ControlLoopTimer clTimer = new ControlLoopTimer();
242 clTimer.setTimerType("ClosedLoop");
243 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
244 clTimer.setRequestID($event.getRequestId().toString());
245 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
252 // Let interested parties know
254 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
256 // Retract it from memory
262 // Now that the manager is inserted into Drools working memory, we'll wait for
263 // another rule to fire in order to continue processing. This way we can also
264 // then screen for additional ONSET and ABATED events for this RequestId.
267 } catch (Exception e) {
268 logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
270 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
271 notification.setNotification(ControlLoopNotificationType.REJECTED);
272 notification.setMessage("Exception occurred: " + e.getMessage());
273 notification.setPolicyName(drools.getRule().getName());
274 notification.setPolicyScope("${policyScope}");
275 notification.setPolicyVersion("${policyVersion}");
279 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
289 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
290 * is now created. We can start processing the yaml specification via the Event Manager.
293 rule "${policyName}.EVENT.MANAGER"
295 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
296 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
297 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
298 requestID == $event.getRequestId() )
299 $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
300 requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", !expired )
303 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
304 logger.info("{}: {}: event={} manager={} clTimer={}",
305 $params.getClosedLoopControlName(), drools.getRule().getName(),
306 $event, $manager, $clTimer);
310 // Check which event this is.
312 ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
314 // Check what kind of event this is
316 if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
318 // We don't care about subsequent onsets
320 logger.info("{}: {}: subsequent onset",
321 $params.getClosedLoopControlName(), drools.getRule().getName());
325 if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
327 // Ignore any bad syntax events
329 logger.warn("{}: {}: syntax error",
330 $params.getClosedLoopControlName(), drools.getRule().getName());
335 // We only want the initial ONSET event in memory,
336 // all the other events need to be retracted to support
337 // cleanup and avoid the other rules being fired for this event.
339 if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
340 logger.warn("{}: {}: not first onset",
341 $params.getClosedLoopControlName(), drools.getRule().getName());
345 logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(),
346 drools.getRule().getName(), $event.getTarget());
348 // Now start seeing if we need to process this event
352 // Check if this is a Final Event
354 VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
357 if (notification != null) {
359 // Its final, but are we waiting for abatement?
361 if ($manager.getNumAbatements() > 0) {
362 logger.info("{}: {}: abatement received for {}. Closing the control loop",
363 $params.getClosedLoopControlName(), drools.getRule().getName(),
364 $event.getRequestId());
366 /// DB Write---end event processing for this RequestId()
367 $manager.commitAbatement("Event Abated","Closed");
369 notification.setFrom("policy");
370 notification.setPolicyName(drools.getRule().getName());
371 notification.setPolicyScope("${policyScope}");
372 notification.setPolicyVersion("${policyVersion}");
374 // In this case, we are done
376 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
380 TargetLock lock = $manager.unlockCurrentOperation();
382 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
383 drools.getRule().getName(), lock);
387 // Retract everything from memory
389 logger.info("{}: {}: retracting onset, manager, and timer",
390 $params.getClosedLoopControlName(), drools.getRule().getName());
392 retract($manager.getOnsetEvent());
394 // don't retract manager, etc. - a clean-up rule will do that
397 // TODO - what if we get subsequent Events for this RequestId?
398 // By default, it will all start over again. May be confusing for Ruby.
399 // Or, we could track this and then subsequently ignore the events
403 // Check whether we need to wait for abatement
405 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
406 logger.info("{}: {}: waiting for abatement ..",
407 $params.getClosedLoopControlName(), drools.getRule().getName());
409 logger.info("{}: {}: no abatement expect for {}. Closing the control loop",
410 $params.getClosedLoopControlName(), drools.getRule().getName(),
411 $event.getRequestId());
413 notification.setFrom("policy");
414 notification.setPolicyName(drools.getRule().getName());
415 notification.setPolicyScope("${policyScope}");
416 notification.setPolicyVersion("${policyVersion}");
419 // In this case, we are done
421 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
425 TargetLock lock = $manager.unlockCurrentOperation();
427 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
428 drools.getRule().getName(), lock);
432 // Retract everything from memory
434 logger.info("{}: {}: retracting onset, manager, and timer",
435 $params.getClosedLoopControlName(), drools.getRule().getName());
437 retract($manager.getOnsetEvent());
439 // don't retract manager, etc. - a clean-up rule will do that
444 // NOT final, so let's ask for the next operation
446 ControlLoopOperationManager operation = $manager.processControlLoop();
447 if (operation != null) {
449 // Let's ask for a lock right away
451 LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
452 logger.info("{}: {}: guard lock acquired={}",
453 $params.getClosedLoopControlName(), drools.getRule().getName(),
455 if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
457 // insert the operation into memory
461 // insert operation timeout object
463 ControlLoopTimer opTimer = new ControlLoopTimer();
464 opTimer.setTimerType("Operation");
465 opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
466 opTimer.setRequestID($event.getRequestId().toString());
467 opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
471 // Insert lock into memory
473 insert(result.getB());
475 logger.debug("The target resource {} is already processing",
476 $event.getAai().get($event.getTarget()));
477 notification = new VirtualControlLoopNotification($event);
478 notification.setNotification(ControlLoopNotificationType.REJECTED);
479 notification.setMessage("The target " + $event.getAai().get($event.getTarget())
480 + " is already locked");
481 notification.setFrom("policy");
482 notification.setPolicyName(drools.getRule().getName());
483 notification.setPolicyScope("${policyScope}");
484 notification.setPolicyVersion("${policyVersion}");
486 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
490 // don't retract manager, etc. - a clean-up rule will do that
492 if (result.getB() != null) {
493 retract(result.getB());
496 logger.info("{}: {}: starting operation={}",
497 $params.getClosedLoopControlName(), drools.getRule().getName(),
501 // Probably waiting for abatement
503 logger.info("{}: {}: no operation, probably waiting for abatement",
504 $params.getClosedLoopControlName(), drools.getRule().getName());
507 } catch (Exception e) {
508 logger.warn("{}: {}: unexpected",
509 $params.getClosedLoopControlName(),
510 drools.getRule().getName(), e);
512 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
513 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
514 notification.setMessage(e.getMessage());
515 notification.setFrom("policy");
516 notification.setPolicyName(drools.getRule().getName());
517 notification.setPolicyScope("${policyScope}");
518 notification.setPolicyVersion("${policyVersion}");
520 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
524 // don't retract manager, etc. - a clean-up rule will do that
531 * Guard Permitted, let's send request to the actor.
534 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
536 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
537 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
538 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
539 requestID == $event.getRequestId() )
540 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
541 onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
542 $lock : TargetLock (requestID == $event.getRequestId())
543 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
544 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
547 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
548 logger.info("{}: {}: event={} manager={} operation={} lock={}",
549 $params.getClosedLoopControlName(), drools.getRule().getName(),
550 $event, $manager, $operation, $lock);
552 Object request = null;
553 boolean caughtException = false;
556 request = $operation.startOperation($event);
558 if (request != null) {
559 logger.debug("{}: {}: starting operation ..",
560 $params.getClosedLoopControlName(), drools.getRule().getName());
562 // Tell interested parties we are performing this Operation
564 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
565 notification.setNotification(ControlLoopNotificationType.OPERATION);
566 notification.setMessage($operation.getOperationMessage());
567 notification.setHistory($operation.getHistory());
568 notification.setFrom("policy");
569 notification.setPolicyName(drools.getRule().getName());
570 notification.setPolicyScope("${policyScope}");
571 notification.setPolicyVersion("${policyVersion}");
573 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
575 switch ($operation.policy.getActor()){
578 if (request instanceof Request) {
579 PolicyEngine.manager.deliver("APPC-CL", request);
581 else if (request instanceof LcmRequestWrapper) {
582 PolicyEngine.manager.deliver("APPC-LCM-READ", request);
586 // at this point the AAI named query request should have already been made,
587 // the response recieved and used
588 // in the construction of the SO Request which is stored in operationRequest
590 if(request instanceof SORequest) {
591 // Call SO. The response will be inserted into memory once it's received
592 SoActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(),
597 if (request instanceof VfcRequest) {
599 Thread t = new Thread(new VfcManager(drools.getWorkingMemory(), (VfcRequest)request));
605 if (request instanceof SdncRequest) {
607 Thread t = new Thread(new SdncManager(drools.getWorkingMemory(), (SdncRequest)request));
612 if (request instanceof PciRequestWrapper) {
613 PolicyEngine.manager.deliver("SDNR-CL", request);
619 // What happens if its null?
621 logger.warn("{}: {}: unexpected null operation request",
622 $params.getClosedLoopControlName(),
623 drools.getRule().getName());
624 if ("SO".equals($operation.policy.getActor())) {
627 modify($manager) {finishOperation($operation)};
629 else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
632 modify($manager) {finishOperation($operation)};
634 else if ("sdnc".equalsIgnoreCase($operation.policy.getActor())) {
637 modify($manager) {finishOperation($operation)};
641 } catch (Exception e) {
642 String msg = e.getMessage();
643 logger.warn("{}: {}: operation={}: AAI failure: {}",
644 $params.getClosedLoopControlName(), drools.getRule().getName(),
646 $operation.setOperationHasException(msg);
648 if(request != null) {
650 // Create a notification for it ("DB Write - end operation")
652 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
653 notification.setFrom("policy");
654 notification.setPolicyName(drools.getRule().getName());
655 notification.setPolicyScope("${policyScope}");
656 notification.setPolicyVersion("${policyVersion}");
657 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
658 notification.setMessage($operation.getOperationHistory());
659 notification.setHistory($operation.getHistory());
661 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
666 caughtException = true;
669 // Having the modify statement in the catch clause doesn't work for whatever reason
670 if (caughtException) {
671 modify($manager) {finishOperation($operation)};
678 * We were able to acquire a lock so now let's ask Xacml Guard whether
679 * we are allowed to proceed with the request to the actor.
682 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
684 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
685 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
686 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
687 requestID == $event.getRequestId() )
688 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
689 onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
690 $lock : TargetLock (requestID == $event.getRequestId())
693 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
694 logger.info("{}: {}: event={} manager={} operation={} lock={}",
695 $params.getClosedLoopControlName(), drools.getRule().getName(),
696 $event, $manager, $operation, $lock);
699 // Sending notification that we are about to query Guard ("DB write - start operation")
701 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
702 notification.setNotification(ControlLoopNotificationType.OPERATION);
703 notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " "
704 + $operation.policy.getRecipe());
705 notification.setHistory($operation.getHistory());
706 notification.setFrom("policy");
707 notification.setPolicyName(drools.getRule().getName());
708 notification.setPolicyScope("${policyScope}");
709 notification.setPolicyVersion("${policyVersion}");
711 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
714 // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
715 // just change guardEnabled to false.
717 // In order to use REST XACML, provide a URL instead of "" as a second argument
718 // to the CallGuardTask() and set the first argument to null
719 // (instead of XacmlPdpEngine).
722 // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
723 boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
727 Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
728 drools.getWorkingMemory(),
729 $event.getClosedLoopControlName(),
730 $operation.policy.getActor().toString(),
731 $operation.policy.getRecipe(),
732 $operation.getTargetEntity(),
733 $event.getRequestId().toString(),
735 AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
736 return(resp == null ? null : resp.countVfModules());
741 insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
747 // This rule will be triggered when a thread talking to the XACML Guard inserts a
748 // guardResponse object into the working memory
750 rule "${policyName}.GUARD.RESPONSE"
752 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
753 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
754 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
755 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
756 requestID == $event.getRequestId() )
757 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
758 onset.getRequestId() == $event.getRequestId() )
759 $lock : TargetLock (requestID == $event.getRequestId())
760 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
761 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
762 $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
765 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
766 logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
767 $params.getClosedLoopControlName(), drools.getRule().getName(),
768 $event, $manager, $operation, $lock, $opTimer, $guardResponse);
771 //we will permit the operation if there was no Guard for it
772 if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
773 $guardResponse.setResult("Permit");
777 // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
779 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
780 notification.setNotification(ControlLoopNotificationType.OPERATION);
781 notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe()
782 + " is " + $guardResponse.getResult());
783 notification.setHistory($operation.getHistory());
784 notification.setFrom("policy");
785 notification.setPolicyName(drools.getRule().getName());
786 notification.setPolicyScope("${policyScope}");
787 notification.setPolicyVersion("${policyVersion}");
789 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
791 if("Permit".equalsIgnoreCase($guardResponse.getResult())){
793 modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
796 //This is the Deny case
797 $operation.startOperation($event);
798 $operation.setOperationHasGuardDeny();
801 modify($manager) {finishOperation($operation)};
804 retract($guardResponse);
810 * This rule responds to APPC Response Events
812 * I would have like to be consistent and write the Response like this:
813 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
815 * However, no compile error was given. But a runtime error was given. I think
816 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
819 rule "${policyName}.APPC.RESPONSE"
821 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
822 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
823 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
824 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
825 requestID == $event.getRequestId() )
826 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
827 onset.getRequestId() == $event.getRequestId() )
828 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
829 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
830 $lock : TargetLock (requestID == $event.getRequestId())
831 $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
834 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
835 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
836 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
837 $params.getClosedLoopControlName(), drools.getRule().getName(),
838 $event, $manager, $operation, $lock, $opTimer, $response);
840 // Get the result of the operation
842 PolicyResult policyResult = $operation.onResponse($response);
843 if (policyResult != null) {
844 logger.debug("{}: {}: operation finished - result={}",
845 $params.getClosedLoopControlName(), drools.getRule().getName(),
848 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
850 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
851 notification.setFrom("policy");
852 notification.setPolicyName(drools.getRule().getName());
853 notification.setPolicyScope("${policyScope}");
854 notification.setPolicyVersion("${policyVersion}");
855 notification.setMessage($operation.getOperationHistory());
856 notification.setHistory($operation.getHistory());
857 if (policyResult.equals(PolicyResult.SUCCESS)) {
858 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
860 // Let interested parties know
862 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
864 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
866 // Let interested parties know
868 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
871 // Ensure the operation is complete
873 if ($operation.isOperationComplete() == true) {
875 // It is complete, remove it from memory
879 // We must also retract the timer object
880 // NOTE: We could write a Rule to do this
884 // Complete the operation
886 modify($manager) {finishOperation($operation)};
889 // Just doing this will kick off the LOCKED rule again
891 modify($operation) {};
895 // Its not finished yet (i.e. expecting more Response objects)
897 // Or possibly it is a leftover response that we timed the request out previously
901 // We are going to retract these objects from memory
908 * The problem with Responses is that they don't have a controlLoopControlName
909 * field in them, so the only way to attach them is via RequestId. If we have multiple
910 * control loop .drl's loaded in the same container, we need to be sure the cleanup
911 * rules don't remove Responses for other control loops.
914 rule "${policyName}.APPC.RESPONSE.CLEANUP"
916 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
917 $response : Response($id : getCommonHeader().RequestId )
918 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
921 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
922 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
923 logger.debug("{}: {}: orphan appc response={}",
924 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
934 * This rule responds to APPC Response Events using the new LCM interface provided by appc
937 rule "${policyName}.APPC.LCM.RESPONSE"
939 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
940 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
941 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
942 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
943 requestID == $event.getRequestId() )
944 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
945 onset.getRequestId() == $event.getRequestId() )
946 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
947 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
948 $lock : TargetLock (requestID == $event.getRequestId())
949 $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
952 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
953 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
954 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
955 $params.getClosedLoopControlName(), drools.getRule().getName(),
956 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
959 // Get the result of the operation
961 PolicyResult policyResult = $operation.onResponse($response);
962 if (policyResult != null) {
963 logger.debug("{}: {}: operation finished - result={}",
964 $params.getClosedLoopControlName(), drools.getRule().getName(),
968 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
970 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
971 notification.setFrom("policy");
972 notification.setPolicyName(drools.getRule().getName());
973 notification.setPolicyScope("${policyScope}");
974 notification.setPolicyVersion("${policyVersion}");
975 notification.setMessage($operation.getOperationHistory());
976 notification.setHistory($operation.getHistory());
977 if (policyResult.equals(PolicyResult.SUCCESS)) {
978 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
980 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
982 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
984 // Ensure the operation is complete
986 if ($operation.isOperationComplete() == true) {
988 // It is complete, remove it from memory
992 // We must also retract the timer object
993 // NOTE: We could write a Rule to do this
997 // Complete the operation
999 modify($manager) {finishOperation($operation)};
1002 // Just doing this will kick off the LOCKED rule again
1004 modify($operation) {};
1008 // Its not finished yet (i.e. expecting more Response objects)
1010 // Or possibly it is a leftover response that we timed the request out previously
1014 // We are going to retract these objects from memory
1021 * Clean Up any lingering LCM reponses
1024 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
1026 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1027 $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1028 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1031 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1032 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1033 logger.debug("{}: {}: orphan appc response={}",
1034 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1043 * This rule responds to SDNR Response Events using the new interface provided by SDNR
1046 rule "${policyName}.SDNR.RESPONSE"
1048 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1049 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1050 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1051 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1052 requestID == $event.getRequestId() )
1053 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1054 onset.getRequestId() == $event.getRequestId() )
1055 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1056 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1057 $lock : TargetLock (requestID == $event.getRequestId())
1058 $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1061 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1062 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1063 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1064 $params.getClosedLoopControlName(), drools.getRule().getName(),
1065 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1068 // Get the result of the operation
1070 PolicyResult policyResult = $operation.onResponse($response);
1071 if (policyResult != null) {
1072 logger.debug("{}: {}: operation finished - result={}",
1073 $params.getClosedLoopControlName(), drools.getRule().getName(),
1077 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1079 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1080 notification.setFrom("policy");
1081 notification.setPolicyName(drools.getRule().getName());
1082 notification.setPolicyScope("${policyScope}");
1083 notification.setPolicyVersion("${policyVersion}");
1084 notification.setMessage($operation.getOperationHistory());
1085 notification.setHistory($operation.getHistory());
1086 if (policyResult.equals(PolicyResult.SUCCESS)) {
1087 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1089 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1091 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1093 // Ensure the operation is complete
1095 if ($operation.isOperationComplete()) {
1097 // It is complete, remove it from memory
1099 retract($operation);
1101 // We must also retract the timer object
1102 // NOTE: We could write a Rule to do this
1106 // Complete the operation
1108 modify($manager) {finishOperation($operation)};
1111 // Just doing this will kick off the LOCKED rule again
1113 modify($operation) {};
1117 // Its not finished yet (i.e. expecting more Response objects)
1119 // Or possibly it is a leftover response that we timed the request out previously
1123 // We are going to retract these objects from memory
1130 * Clean Up any lingering SDNR reponses
1133 rule "${policyName}.SDNR.RESPONSE.CLEANUP"
1135 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1136 $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1137 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1140 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1141 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1142 logger.debug("{}: {}: orphan SDNR response={}",
1143 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1152 * This rule responds to SO Response Events
1155 rule "${policyName}.SO.RESPONSE"
1157 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1158 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1159 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1160 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1161 requestID == $event.getRequestId() )
1162 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1163 onset.getRequestId() == $event.getRequestId() )
1164 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1165 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1166 $lock : TargetLock (requestID == $event.getRequestId())
1167 $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
1170 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1171 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1172 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1173 $params.getClosedLoopControlName(), drools.getRule().getName(),
1174 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1176 // Get the result of the operation
1178 PolicyResult policyResult = $operation.onResponse($response);
1179 if (policyResult != null) {
1180 logger.debug("{}: {}: operation finished - result={}",
1181 $params.getClosedLoopControlName(), drools.getRule().getName(),
1185 // This Operation has completed, construct a notification showing our results
1187 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1188 notification.setFrom("policy");
1189 notification.setPolicyName(drools.getRule().getName());
1190 notification.setPolicyScope("${policyScope}");
1191 notification.setPolicyVersion("${policyVersion}");
1192 notification.setMessage($operation.getOperationHistory());
1193 notification.setHistory($operation.getHistory());
1194 if (policyResult.equals(PolicyResult.SUCCESS)) {
1195 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1197 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1200 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1202 // Ensure the operation is complete
1204 if ($operation.isOperationComplete() == true) {
1206 // It is complete, remove it from memory
1208 retract($operation);
1210 // We must also retract the timer object
1211 // NOTE: We could write a Rule to do this
1215 // Complete the operation
1217 modify($manager) {finishOperation($operation)};
1220 // Just doing this will kick off the LOCKED rule again
1222 modify($operation) {};
1226 // Its not finished yet (i.e. expecting more Response objects)
1228 // Or possibly it is a leftover response that we timed the request out previously
1232 // We are going to retract these objects from memory
1240 * This rule responds to VFC Response Events
1243 rule "${policyName}.VFC.RESPONSE"
1245 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1246 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1247 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1248 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1249 requestID == $event.getRequestId() )
1250 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1251 onset.getRequestId() == $event.getRequestId() )
1252 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1253 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1254 $lock : TargetLock (requestID == $event.getRequestId())
1255 $response : VfcResponse( requestId.toString() == $event.getRequestId().toString() )
1257 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1258 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1259 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1260 $params.getClosedLoopControlName(), drools.getRule().getName(),
1261 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1263 // Get the result of the operation
1265 PolicyResult policyResult = $operation.onResponse($response);
1266 if (policyResult != null) {
1268 // This Operation has completed, construct a notification showing our results
1270 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1271 notification.setFrom("policy");
1272 notification.setPolicyName(drools.getRule().getName());
1273 notification.setPolicyScope("${policyScope}");
1274 notification.setPolicyVersion("${policyVersion}");
1275 notification.setMessage($operation.getOperationHistory());
1276 notification.setHistory($operation.getHistory());
1278 // Ensure the operation is complete
1280 if ($operation.isOperationComplete() == true) {
1282 // It is complete, remove it from memory
1284 retract($operation);
1286 // We must also retract the timer object
1287 // NOTE: We could write a Rule to do this
1291 // Complete the operation
1293 modify($manager) {finishOperation($operation)};
1296 // Just doing this will kick off the LOCKED rule again
1298 modify($operation) {};
1302 // Its not finished yet (i.e. expecting more Response objects)
1304 // Or possibly it is a leftover response that we timed the request out previously
1308 // We are going to retract these objects from memory
1316 * This rule responds to SDNC Response Events
1320 rule "${policyName}.SDNC.RESPONSE"
1322 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1323 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1324 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1325 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1326 requestID == $event.getRequestId() )
1327 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1328 onset.getRequestId() == $event.getRequestId() )
1329 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1330 requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1331 $lock : TargetLock (requestID == $event.getRequestId())
1332 $response : SdncResponse( requestId.toString() == $event.getRequestId().toString() )
1334 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1335 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1336 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1337 $params.getClosedLoopControlName(), drools.getRule().getName(),
1338 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1340 // Get the result of the operation
1342 PolicyResult policyResult = $operation.onResponse($response);
1343 if (policyResult != null) {
1345 // This Operation has completed, construct a notification showing our results
1347 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1348 notification.setFrom("policy");
1349 notification.setPolicyName(drools.getRule().getName());
1350 notification.setPolicyScope("${policyScope}");
1351 notification.setPolicyVersion("${policyVersion}");
1352 notification.setMessage($operation.getOperationHistory());
1353 notification.setHistory($operation.getHistory());
1355 // Ensure the operation is complete
1357 if ($operation.isOperationComplete()) {
1359 // It is complete, remove it from memory
1361 retract($operation);
1363 // We must also retract the timer object
1364 // NOTE: We could write a Rule to do this
1368 // Complete the operation
1370 modify($manager) {finishOperation($operation)};
1373 // Just doing this will kick off the LOCKED rule again
1375 modify($operation) {};
1379 // Its not finished yet (i.e. expecting more Response objects)
1381 // Or possibly it is a leftover response that we timed the request out previously
1385 // We are going to retract these objects from memory
1393 * This manages a single timer.
1394 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1397 rule "${policyName}.TIMER.FIRED"
1398 timer (expr: $timeout)
1400 $timer : ControlLoopTimer($timeout : delay, !expired)
1402 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1403 logger.info("This is ${policyName}.TIMER.FIRED");
1404 modify($timer){setExpired(true)};
1409 * This is the timer that manages the timeout for an individual operation.
1412 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1414 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1415 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1416 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1417 requestID == $event.getRequestId() )
1418 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1419 onset.getRequestId() == $event.getRequestId() )
1420 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1421 requestID == $event.getRequestId().toString(), expired, timerType == "Operation" )
1422 $lock : TargetLock (requestID == $event.getRequestId())
1425 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1426 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1427 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1428 $params.getClosedLoopControlName(), drools.getRule().getName(),
1429 $event, $manager, $operation, $lock, $operation, $opTimer);
1432 // Tell it its timed out
1434 $operation.setOperationHasTimedOut();
1436 // Create a notification for it ("DB Write - end operation")
1438 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1439 notification.setFrom("policy");
1440 notification.setPolicyName(drools.getRule().getName());
1441 notification.setPolicyScope("${policyScope}");
1442 notification.setPolicyVersion("${policyVersion}");
1443 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1444 notification.setMessage($operation.getOperationHistory());
1445 notification.setHistory($operation.getHistory());
1447 // Let interested parties know
1449 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1451 // Get rid of the timer
1455 // Ensure the operation is complete
1457 if ($operation.isOperationComplete() == true) {
1459 // It is complete, remove it from memory
1461 retract($operation);
1463 // Complete the operation
1465 modify($manager) {finishOperation($operation)};
1468 // Just doing this will kick off the LOCKED rule again
1470 modify($operation) {};
1476 * This is the timer that manages the overall control loop timeout.
1479 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1481 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1482 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1483 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1484 requestID == $event.getRequestId() )
1485 $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1486 requestID == $event.getRequestId().toString(), expired, timerType == "ClosedLoop" )
1489 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1490 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1492 logger.debug("{}: {}: event={}",
1493 $params.getClosedLoopControlName(), drools.getRule().getName(),
1496 // Tell the Event Manager it has timed out
1498 VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1499 if (notification != null) {
1500 notification.setFrom("policy");
1501 notification.setPolicyName(drools.getRule().getName());
1502 notification.setPolicyScope("${policyScope}");
1503 notification.setPolicyVersion("${policyVersion}");
1505 // Let interested parties know
1507 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1510 // Retract the event
1517 * This rule cleans up the manager and other objects after an event has
1521 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1523 $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1524 $operations : LinkedList()
1525 from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName,
1526 onset.getRequestId() == $requestId ) )
1527 $timers : LinkedList()
1528 from collect( ControlLoopTimer( closedLoopControlName == $clName,
1529 requestID == $requestId.toString() ) )
1530 $locks : LinkedList()
1531 from collect( TargetLock (requestID == $requestId) )
1532 not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1535 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1536 logger.info("{}: {}", $clName, drools.getRule().getName());
1538 logger.debug("{}: {}: manager={} timers={} operations={}",
1539 $clName, drools.getRule().getName(),
1540 $manager, $timers.size(), $operations.size());
1543 // Retract EVERYTHING
1547 for(Object manager: $operations) {
1548 retract((ControlLoopOperationManager) manager);
1550 for(Object timer: $timers) {
1551 retract((ControlLoopTimer) timer);
1553 for(Object lock: $locks) {
1554 TargetLock tgt = (TargetLock) lock;
1556 // Ensure we release the lock
1558 PolicyGuard.unlockTarget(tgt);
1565 * This rule will clean up any rogue onsets where there is no
1566 * ControlLoopParams object corresponding to the onset event.
1569 rule "${policyName}.EVENT.CLEANUP"
1571 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1572 not ( Params( getClosedLoopControlName() == $clName) )
1575 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1576 logger.info("{}: {}", $clName, drools.getRule().getName());
1577 logger.debug("{}: {}: orphan onset event={}",
1578 $clName, drools.getRule().getName(), $event);
1584 * Creates a cleaner for every Params object.
1585 * This has a higher salience so that it is fired before PARAMS.FINISHED in ANY policy.
1587 rule "${policyName}.PARAMS.CLEANING"
1591 ParamsInitCleaner( )
1594 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1595 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1596 $params.getControlLoopYaml());
1598 ParamsCleaner cleaner = new ParamsCleaner();
1599 cleaner.setClosedLoopControlName($params.getClosedLoopControlName());
1600 cleaner.setControlLoopYaml($params.getControlLoopYaml());
1605 * Finished creating cleaner objects, so remove the trigger.
1606 * This has a higher salience so that it is fired before processing any events.
1608 rule "${policyName}.PARAMS.FINISHED"
1611 $initCleaner: ParamsInitCleaner( )
1614 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1615 logger.info("{}: {}", $initCleaner.getClosedLoopControlName(), drools.getRule().getName());
1617 retract($initCleaner);
1621 * Identifies Params objects that are still active, removing their associated cleaners.
1622 * This should only leave one active Params object for each policy.
1623 * This has a higher salience so that it is fired before PARAMS.DELETE in ANY policy.
1625 rule "${policyName}.PARAMS.ACTIVE"
1628 $params: Params( getClosedLoopControlName() == "${closedLoopControlName}",
1629 getControlLoopYaml() == "${controlLoopYaml}" )
1630 $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}",
1631 getControlLoopYaml() == "${controlLoopYaml}" )
1634 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1635 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1636 $params.getControlLoopYaml());
1642 * Delete Params objects that are not active (i.e., those that still have an associated
1644 * This has a higher salience so that it is fired before PARAMS.CLEANED in ANY policy.
1646 rule "${policyName}.PARAMS.DELETE"
1650 $cleaner: ParamsCleaner( getClosedLoopControlName() == $params.getClosedLoopControlName(),
1651 getControlLoopYaml() == $params.getControlLoopYaml() )
1654 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1655 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1656 $params.getControlLoopYaml());
1662 * Finished clean-up, so delete the cleaner objects.
1663 * This has a higher salience so that it is fired before processing any events.
1665 rule "${policyName}.PARAMS.CLEANED"
1668 $cleaner: ParamsCleaner( )
1671 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1672 logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(),
1673 $cleaner.getControlLoopYaml());