2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 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.ControlLoopException;
27 import org.onap.policy.controlloop.ControlLoopNotificationType;
28 import org.onap.policy.controlloop.ControlLoopLogger;
29 import org.onap.policy.controlloop.policy.PolicyResult;
30 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
31 import org.onap.policy.controlloop.policy.Policy;
32 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
33 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NEW_EVENT_STATUS;
34 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
35 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
36 import org.onap.policy.aai.AaiNqResponseWrapper;
37 import org.onap.policy.appc.Request;
38 import org.onap.policy.appc.Response;
39 import org.onap.policy.appc.CommonHeader;
40 import org.onap.policy.appclcm.LcmRequestWrapper;
41 import org.onap.policy.appclcm.LcmResponseWrapper;
42 import org.onap.policy.appclcm.LcmRequest;
43 import org.onap.policy.appclcm.LcmResponse;
44 import org.onap.policy.appclcm.LcmCommonHeader;
45 import org.onap.policy.vfc.VFCRequest;
46 import org.onap.policy.vfc.VFCResponse;
47 import org.onap.policy.vfc.VFCManager;
48 import org.onap.policy.so.SOManager;
49 import org.onap.policy.so.SORequest;
50 import org.onap.policy.so.SORequestStatus;
51 import org.onap.policy.so.SORequestDetails;
52 import org.onap.policy.so.SOModelInfo;
53 import org.onap.policy.so.SOCloudConfiguration;
54 import org.onap.policy.so.SORequestInfo;
55 import org.onap.policy.so.SORequestParameters;
56 import org.onap.policy.so.SORelatedInstanceListElement;
57 import org.onap.policy.so.SORelatedInstance;
58 import org.onap.policy.so.SOResponse;
59 import org.onap.policy.so.SOResponseWrapper;
60 import org.onap.policy.guard.PolicyGuard;
61 import org.onap.policy.guard.PolicyGuard.LockResult;
62 import org.onap.policy.guard.TargetLock;
63 import org.onap.policy.guard.GuardResult;
64 import org.onap.policy.guard.PolicyGuardRequest;
65 import org.onap.policy.guard.PolicyGuardResponse;
66 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
67 import org.onap.policy.guard.CallGuardTaskEmbedded;
69 import org.yaml.snakeyaml.Yaml;
70 import org.yaml.snakeyaml.constructor.Constructor;
72 import org.slf4j.LoggerFactory;
73 import org.slf4j.Logger;
75 import java.time.Instant;
76 import java.util.LinkedList;
77 import java.util.Iterator;
79 import org.onap.policy.drools.system.PolicyEngine;
82 * This structure mimics the Params structure.
83 * Its only purpose is to allow management of
84 * rules by the PAP component..
85 * It has no use at runtime since the rules go by
86 * Params for matching purposes.
89 closedLoopControlName : String
90 controlLoopYaml : String
94 * Control Loop Identity
97 closedLoopControlName : String
98 controlLoopYaml : String
102 * Used to trigger clean up Params that no longer have associated rules.
104 declare ParamsInitCleaner
105 closedLoopControlName : String // only used when logging
109 * Used to clean up Params that no longer have associated rules.
111 declare ParamsCleaner
112 closedLoopControlName : String
113 controlLoopYaml : String
120 declare OperationTimer
121 closedLoopControlName : String
129 declare ControlLoopTimer
130 closedLoopControlName : String
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}", getControlLoopYaml() == "${controlLoopYaml}" ) )
149 Params params = new Params();
150 params.setClosedLoopControlName("${closedLoopControlName}");
151 params.setControlLoopYaml("${controlLoopYaml}");
154 ParamsInitCleaner initCleaner = new ParamsInitCleaner();
155 initCleaner.setClosedLoopControlName("${closedLoopControlName}");
158 // Note: globals have bad behavior when persistence is used,
159 // hence explicitly getting the logger vs using a global
161 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
162 logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), params.getControlLoopYaml());
167 * This rule responds to DCAE Events where there is no manager yet. Either it is
168 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
171 rule "${policyName}.EVENT"
173 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
174 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
175 not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() ) )
178 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
179 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
184 // Check the event, because we need it to not be null when
185 // we create the ControlLoopEventManager. The ControlLoopEventManager
186 // will do extra syntax checking as well check if the closed loop is disabled.
188 if ($event.getRequestId() == null) {
189 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
190 notification.setNotification(ControlLoopNotificationType.REJECTED);
191 notification.setFrom("policy");
192 notification.setMessage("Missing requestId");
193 notification.setPolicyName(drools.getRule().getName());
194 notification.setPolicyScope("${policyScope}");
195 notification.setPolicyVersion("${policyVersion}");
198 // Let interested parties know
200 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
203 // Retract it from memory
206 } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
207 throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
210 // Create an EventManager
212 ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(), $event.getRequestId());
214 // Disable target locking
216 manager.setUseTargetLock(false);
218 // Determine if EventManager can actively process the event (i.e. syntax, is_closed_loop_disabled checks etc.)
220 VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
221 notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
222 notification.setPolicyName(drools.getRule().getName());
223 notification.setPolicyScope("${policyScope}");
224 notification.setPolicyVersion("${policyVersion}");
226 // Are we actively pursuing this event?
228 if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
230 // Insert Event Manager into memory, this will now kick off processing.
234 // Let interested parties know
236 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
238 // Setup the Overall Control Loop timer
240 ControlLoopTimer clTimer = new ControlLoopTimer();
241 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
242 clTimer.setRequestID($event.getRequestId().toString());
243 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
250 // Let interested parties know
252 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
254 // Retract it from memory
260 // Now that the manager is inserted into Drools working memory, we'll wait for
261 // another rule to fire in order to continue processing. This way we can also
262 // then screen for additional ONSET and ABATED events for this RequestId.
265 } catch (Exception e) {
266 logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
268 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
269 notification.setNotification(ControlLoopNotificationType.REJECTED);
270 notification.setMessage("Exception occurred: " + e.getMessage());
271 notification.setPolicyName(drools.getRule().getName());
272 notification.setPolicyScope("${policyScope}");
273 notification.setPolicyVersion("${policyVersion}");
277 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
287 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
288 * is now created. We can start processing the yaml specification via the Event Manager.
291 rule "${policyName}.EVENT.MANAGER"
293 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
294 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
295 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
296 $clTimer : ControlLoopTimer ( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
299 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
300 logger.info("{}: {}: event={} manager={} clTimer={}",
301 $params.getClosedLoopControlName(), drools.getRule().getName(),
302 $event, $manager, $clTimer);
306 // Check which event this is.
308 ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
310 // Check what kind of event this is
312 if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
314 // We don't care about subsequent onsets
316 logger.info("{}: {}: subsequent onset",
317 $params.getClosedLoopControlName(), drools.getRule().getName());
321 if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
323 // Ignore any bad syntax events
325 logger.warn("{}: {}: syntax error",
326 $params.getClosedLoopControlName(), drools.getRule().getName());
331 // We only want the initial ONSET event in memory,
332 // all the other events need to be retracted to support
333 // cleanup and avoid the other rules being fired for this event.
335 if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
336 logger.warn("{}: {}: not first onset",
337 $params.getClosedLoopControlName(), drools.getRule().getName());
341 logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(),
342 drools.getRule().getName(), $event.getTarget());
344 // Now start seeing if we need to process this event
348 // Check if this is a Final Event
350 VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
352 if (notification != null) {
354 // Set common notification fields
356 notification.setFrom("policy");
357 notification.setPolicyName(drools.getRule().getName());
358 notification.setPolicyScope("${policyScope}");
359 notification.setPolicyVersion("${policyVersion}");
361 // Its final, but are we waiting for abatement?
363 if ($manager.getNumAbatements() > 0) {
365 // We have received an abatement and are done
367 logger.info("{}: {}: abatement received for {}. Closing the control loop",
368 $params.getClosedLoopControlName(), drools.getRule().getName(),
369 $event.getRequestId());
371 // Set notification message
373 notification.setMessage("Abatement received. Closing the control loop.");
375 /// DB Write---end event processing for this RequestId()
377 $manager.commitAbatement("Event Abated","Closed");
381 TargetLock lock = $manager.unlockCurrentOperation();
383 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
384 drools.getRule().getName(), lock);
388 // Retract everything from memory
390 logger.info("{}: {}: retracting onset, manager, and timer",
391 $params.getClosedLoopControlName(), drools.getRule().getName());
393 retract($manager.getOnsetEvent());
395 // 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) {
409 logger.info("{}: {}: waiting for abatement ..",
410 $params.getClosedLoopControlName(), drools.getRule().getName());
412 // Set notification message
414 notification.setMessage("Waiting for abatement");
419 logger.info("{}: {}: no abatement expected for {}. Closing the control loop",
420 $params.getClosedLoopControlName(), drools.getRule().getName(),
421 $event.getRequestId());
423 // Set notification message
425 notification.setMessage("No abatement expected. Closing the control loop.");
429 TargetLock lock = $manager.unlockCurrentOperation();
431 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
432 drools.getRule().getName(), lock);
436 // Retract everything from memory
438 logger.info("{}: {}: retracting onset, manager, and timer",
439 $params.getClosedLoopControlName(), drools.getRule().getName());
441 retract($manager.getOnsetEvent());
443 // don't retract manager, etc. - a clean-up rule will do that
447 // Send the notification
449 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
452 // NOT final, so let's ask for the next operation
454 ControlLoopOperationManager operation = $manager.processControlLoop();
455 if (operation != null) {
457 // Let's ask for a lock right away
459 LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
460 logger.info("{}: {}: guard lock acquired={}",
461 $params.getClosedLoopControlName(), drools.getRule().getName(),
463 if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
465 // insert the operation into memory
470 // insert operation timeout object
472 OperationTimer opTimer = new OperationTimer();
473 opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
474 opTimer.setRequestID($event.getRequestId().toString());
475 opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
479 // Insert lock into memory
481 insert(result.getB());
484 logger.debug("The target resource {} is already processing",
485 $event.getAai().get($event.getTarget()));
486 notification = new VirtualControlLoopNotification($event);
487 notification.setNotification(ControlLoopNotificationType.REJECTED);
488 notification.setMessage("The target " + $event.getAai().get($event.getTarget()) + " is already locked");
489 notification.setFrom("policy");
490 notification.setPolicyName(drools.getRule().getName());
491 notification.setPolicyScope("${policyScope}");
492 notification.setPolicyVersion("${policyVersion}");
494 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
498 // don't retract manager, etc. - a clean-up rule will do that
500 if(result.getB() != null) {
501 retract(result.getB());
504 logger.info("{}: {}: starting operation={}",
505 $params.getClosedLoopControlName(), drools.getRule().getName(),
509 // Probably waiting for abatement
511 logger.info("{}: {}: no operation, probably waiting for abatement",
512 $params.getClosedLoopControlName(), drools.getRule().getName());
515 } catch (Exception e) {
516 logger.warn("{}: {}: unexpected",
517 $params.getClosedLoopControlName(),
518 drools.getRule().getName(), e);
520 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
521 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
522 notification.setMessage(e.getMessage());
523 notification.setFrom("policy");
524 notification.setPolicyName(drools.getRule().getName());
525 notification.setPolicyScope("${policyScope}");
526 notification.setPolicyVersion("${policyVersion}");
528 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
532 // don't retract manager, etc. - a clean-up rule will do that
539 * Guard Permitted, let's send request to the actor.
542 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
544 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
545 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
546 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
547 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
548 $lock : TargetLock (requestID == $event.getRequestId())
549 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
552 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
553 logger.info("{}: {}: event={} manager={} operation={} lock={}",
554 $params.getClosedLoopControlName(), drools.getRule().getName(),
555 $event, $manager, $operation, $lock);
557 Object request = null;
558 boolean caughtException = false;
561 request = $operation.startOperation($event);
563 if (request != null) {
564 logger.debug("{}: {}: starting operation ..",
565 $params.getClosedLoopControlName(), drools.getRule().getName());
567 // Tell interested parties we are performing this Operation
569 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
570 notification.setNotification(ControlLoopNotificationType.OPERATION);
571 notification.setMessage($operation.getOperationMessage());
572 notification.setHistory($operation.getHistory());
573 notification.setFrom("policy");
574 notification.setPolicyName(drools.getRule().getName());
575 notification.setPolicyScope("${policyScope}");
576 notification.setPolicyVersion("${policyVersion}");
578 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
580 switch ($operation.policy.getActor()){
584 if (request instanceof Request) {
585 PolicyEngine.manager.deliver("APPC-CL", request);
587 else if (request instanceof LcmRequestWrapper) {
588 PolicyEngine.manager.deliver("APPC-LCM-READ", request);
592 // at this point the AAI named query request should have already been made, the response received
593 // and used in the construction of the SO Request which is stored in operationRequest
595 if(request instanceof SORequest) {
596 // Call SO. The response will be inserted into memory once it's received
597 SoActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(),
602 if (request instanceof VFCRequest) {
604 Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
611 // What happens if its null?
613 logger.warn("{}: {}: unexpected null operation request",
614 $params.getClosedLoopControlName(),
615 drools.getRule().getName());
616 if ("SO".equals($operation.policy.getActor())) {
619 modify($manager) {finishOperation($operation)};
621 else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
624 modify($manager) {finishOperation($operation)};
628 } catch (Exception e) {
629 String msg = e.getMessage();
630 logger.warn("{}: {}: operation={}: AAI failure: {}",
631 $params.getClosedLoopControlName(), drools.getRule().getName(),
633 $operation.setOperationHasException(msg);
635 if(request != null) {
637 // Create a notification for it ("DB Write - end operation")
639 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
640 notification.setFrom("policy");
641 notification.setPolicyName(drools.getRule().getName());
642 notification.setPolicyScope("${policyScope}");
643 notification.setPolicyVersion("${policyVersion}");
644 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
645 notification.setMessage($operation.getOperationHistory());
646 notification.setHistory($operation.getHistory());
648 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
653 caughtException = true;
656 // Having the modify statement in the catch clause doesn't work for whatever reason
657 if (caughtException) {
658 modify($manager) {finishOperation($operation)};
665 * We were able to acquire a lock so now let's ask Xacml Guard whether
666 * we are allowed to proceed with the request to the actor.
669 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
671 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
672 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
673 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
674 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
675 $lock : TargetLock (requestID == $event.getRequestId())
678 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
679 logger.info("{}: {}: event={} manager={} operation={} lock={}",
680 $params.getClosedLoopControlName(), drools.getRule().getName(),
681 $event, $manager, $operation, $lock);
684 // Sending notification that we are about to query Guard ("DB write - start operation")
686 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
687 notification.setNotification(ControlLoopNotificationType.OPERATION);
688 notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe());
689 notification.setHistory($operation.getHistory());
690 notification.setFrom("policy");
691 notification.setPolicyName(drools.getRule().getName());
692 notification.setPolicyScope("${policyScope}");
693 notification.setPolicyVersion("${policyVersion}");
695 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
698 // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
699 // just change guardEnabled to false.
703 // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
704 boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
708 Thread t = new Thread(new CallGuardTaskEmbedded(
709 drools.getWorkingMemory(),
710 $event.getClosedLoopControlName(),
711 $operation.policy.getActor().toString(),
712 $operation.policy.getRecipe(),
713 $operation.getTargetEntity(),
714 $event.getRequestId().toString(),
716 AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
717 return(resp == null ? null : resp.countVfModules());
722 insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
728 // This rule will be triggered when a thread talking to the XACML Guard inserts a
729 // guardResponse object into the working memory
731 rule "${policyName}.GUARD.RESPONSE"
733 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
734 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
735 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
736 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
737 $lock : TargetLock (requestID == $event.getRequestId())
738 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
739 $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
742 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
743 logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
744 $params.getClosedLoopControlName(), drools.getRule().getName(),
745 $event, $manager, $operation, $lock, $opTimer, $guardResponse);
748 //we will permit the operation if there was no Guard for it
749 if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
750 $guardResponse.setResult("Permit");
754 // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
756 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
757 notification.setNotification(ControlLoopNotificationType.OPERATION);
758 notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe() + " is " + $guardResponse.getResult());
759 notification.setHistory($operation.getHistory());
760 notification.setFrom("policy");
761 notification.setPolicyName(drools.getRule().getName());
762 notification.setPolicyScope("${policyScope}");
763 notification.setPolicyVersion("${policyVersion}");
765 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
767 if("Permit".equalsIgnoreCase($guardResponse.getResult())){
769 modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
772 //This is the Deny case
773 $operation.startOperation($event);
774 $operation.setOperationHasGuardDeny();
777 modify($manager) {finishOperation($operation)};
780 retract($guardResponse);
786 * This rule responds to APPC Response Events
788 * I would have like to be consistent and write the Response like this:
789 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
791 * However, no compile error was given. But a runtime error was given. I think
792 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
795 rule "${policyName}.APPC.RESPONSE"
797 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
798 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
799 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
800 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
801 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
802 $lock : TargetLock (requestID == $event.getRequestId())
803 $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
806 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
807 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
808 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
809 $params.getClosedLoopControlName(), drools.getRule().getName(),
810 $event, $manager, $operation, $lock, $opTimer, $response);
812 // Get the result of the operation
814 PolicyResult policyResult = $operation.onResponse($response);
815 if (policyResult != null) {
816 logger.debug("{}: {}: operation finished - result={}",
817 $params.getClosedLoopControlName(), drools.getRule().getName(),
820 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
822 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
823 notification.setFrom("policy");
824 notification.setPolicyName(drools.getRule().getName());
825 notification.setPolicyScope("${policyScope}");
826 notification.setPolicyVersion("${policyVersion}");
827 notification.setMessage($operation.getOperationHistory());
828 notification.setHistory($operation.getHistory());
829 if (policyResult.equals(PolicyResult.SUCCESS)) {
830 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
832 // Let interested parties know
834 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
836 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
838 // Let interested parties know
840 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
843 // Ensure the operation is complete
845 if ($operation.isOperationComplete() == true) {
847 // It is complete, remove it from memory
851 // We must also retract the timer object
852 // NOTE: We could write a Rule to do this
856 // Complete the operation
858 modify($manager) {finishOperation($operation)};
861 // Just doing this will kick off the LOCKED rule again
863 modify($operation) {};
867 // Its not finished yet (i.e. expecting more Response objects)
869 // Or possibly it is a leftover response that we timed the request out previously
873 // We are going to retract these objects from memory
880 * The problem with Responses is that they don't have a controlLoopControlName
881 * field in them, so the only way to attach them is via RequestId. If we have multiple
882 * control loop .drl's loaded in the same container, we need to be sure the cleanup
883 * rules don't remove Responses for other control loops.
886 rule "${policyName}.APPC.RESPONSE.CLEANUP"
888 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
889 $response : Response($id : getCommonHeader().RequestId )
890 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
893 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
894 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
895 logger.debug("{}: {}: orphan appc response={}",
896 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
906 * This rule responds to APPC Response Events using the new LCM interface provided by appc
909 rule "${policyName}.APPC.LCM.RESPONSE"
911 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
912 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
913 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
914 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
915 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
916 $lock : TargetLock (requestID == $event.getRequestId())
917 $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
920 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
921 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
922 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
923 $params.getClosedLoopControlName(), drools.getRule().getName(),
924 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
927 // Get the result of the operation
929 PolicyResult policyResult = $operation.onResponse($response);
930 if (policyResult != null) {
931 logger.debug("{}: {}: operation finished - result={}",
932 $params.getClosedLoopControlName(), drools.getRule().getName(),
936 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
938 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
939 notification.setFrom("policy");
940 notification.setPolicyName(drools.getRule().getName());
941 notification.setPolicyScope("${policyScope}");
942 notification.setPolicyVersion("${policyVersion}");
943 notification.setMessage($operation.getOperationHistory());
944 notification.setHistory($operation.getHistory());
945 if (policyResult.equals(PolicyResult.SUCCESS)) {
946 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
948 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
950 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
952 // Ensure the operation is complete
954 if ($operation.isOperationComplete() == true) {
956 // It is complete, remove it from memory
960 // We must also retract the timer object
961 // NOTE: We could write a Rule to do this
965 // Complete the operation
967 modify($manager) {finishOperation($operation)};
970 // Just doing this will kick off the LOCKED rule again
972 modify($operation) {};
976 // Its not finished yet (i.e. expecting more Response objects)
978 // Or possibly it is a leftover response that we timed the request out previously
982 // We are going to retract these objects from memory
989 * Clean Up any lingering LCM reponses
992 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
994 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
995 $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
996 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
999 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1000 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1001 logger.debug("{}: {}: orphan appc response={}",
1002 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1011 * This rule responds to SO Response Events
1014 rule "${policyName}.SO.RESPONSE"
1016 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1017 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1018 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1019 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1020 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
1021 $lock : TargetLock (requestID == $event.getRequestId())
1022 $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
1025 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1026 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1027 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1028 $params.getClosedLoopControlName(), drools.getRule().getName(),
1029 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1031 // Get the result of the operation
1033 PolicyResult policyResult = $operation.onResponse($response);
1034 if (policyResult != null) {
1035 logger.debug("{}: {}: operation finished - result={}",
1036 $params.getClosedLoopControlName(), drools.getRule().getName(),
1040 // This Operation has completed, construct a notification showing our results
1042 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1043 notification.setFrom("policy");
1044 notification.setPolicyName(drools.getRule().getName());
1045 notification.setPolicyScope("${policyScope}");
1046 notification.setPolicyVersion("${policyVersion}");
1047 notification.setMessage($operation.getOperationHistory());
1048 notification.setHistory($operation.getHistory());
1049 if (policyResult.equals(PolicyResult.SUCCESS)) {
1050 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1052 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1055 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1057 // Ensure the operation is complete
1059 if ($operation.isOperationComplete() == true) {
1061 // It is complete, remove it from memory
1063 retract($operation);
1065 // We must also retract the timer object
1066 // NOTE: We could write a Rule to do this
1070 // Complete the operation
1072 modify($manager) {finishOperation($operation)};
1075 // Just doing this will kick off the LOCKED rule again
1077 modify($operation) {};
1081 // Its not finished yet (i.e. expecting more Response objects)
1083 // Or possibly it is a leftover response that we timed the request out previously
1087 // We are going to retract these objects from memory
1095 * This rule responds to VFC Response Events
1098 rule "${policyName}.VFC.RESPONSE"
1100 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1101 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1102 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1103 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1104 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
1105 $lock : TargetLock (requestID == $event.getRequestId())
1106 $response : VFCResponse( requestId.toString() == $event.getRequestId().toString() )
1108 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1109 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1110 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1111 $params.getClosedLoopControlName(), drools.getRule().getName(),
1112 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1114 // Get the result of the operation
1116 PolicyResult policyResult = $operation.onResponse($response);
1117 if (policyResult != null) {
1119 // This Operation has completed, construct a notification showing our results
1121 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1122 notification.setFrom("policy");
1123 notification.setPolicyName(drools.getRule().getName());
1124 notification.setPolicyScope("${policyScope}");
1125 notification.setPolicyVersion("${policyVersion}");
1126 notification.setMessage($operation.getOperationHistory());
1127 notification.setHistory($operation.getHistory());
1129 // Ensure the operation is complete
1131 if ($operation.isOperationComplete() == true) {
1133 // It is complete, remove it from memory
1135 retract($operation);
1137 // We must also retract the timer object
1138 // NOTE: We could write a Rule to do this
1142 // Complete the operation
1144 modify($manager) {finishOperation($operation)};
1147 // Just doing this will kick off the LOCKED rule again
1149 modify($operation) {};
1153 // Its not finished yet (i.e. expecting more Response objects)
1155 // Or possibly it is a leftover response that we timed the request out previously
1159 // We are going to retract these objects from memory
1167 * This is the timer that manages the timeout for an individual operation.
1170 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1173 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1174 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1175 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1176 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1177 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), $to : getDelay() )
1178 $lock : TargetLock (requestID == $event.getRequestId())
1181 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1182 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1183 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1184 $params.getClosedLoopControlName(), drools.getRule().getName(),
1185 $event, $manager, $operation, $lock, $operation, $opTimer);
1188 // Tell it its timed out
1190 $operation.setOperationHasTimedOut();
1192 // Create a notification for it ("DB Write - end operation")
1194 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1195 notification.setFrom("policy");
1196 notification.setPolicyName(drools.getRule().getName());
1197 notification.setPolicyScope("${policyScope}");
1198 notification.setPolicyVersion("${policyVersion}");
1199 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1200 notification.setMessage($operation.getOperationHistory());
1201 notification.setHistory($operation.getHistory());
1203 // Let interested parties know
1205 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1207 // Get rid of the timer
1211 // Ensure the operation is complete
1213 if ($operation.isOperationComplete() == true) {
1215 // It is complete, remove it from memory
1217 retract($operation);
1219 // Complete the operation
1221 modify($manager) {finishOperation($operation)};
1224 // Just doing this will kick off the LOCKED rule again
1226 modify($operation) {};
1232 * This is the timer that manages the overall control loop timeout.
1235 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1238 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1239 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1240 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1241 $clTimer : ControlLoopTimer ( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), $to : getDelay() )
1244 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1245 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1247 logger.debug("{}: {}: event={}",
1248 $params.getClosedLoopControlName(), drools.getRule().getName(),
1251 // Tell the Event Manager it has timed out
1253 VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1254 if (notification != null) {
1255 notification.setFrom("policy");
1256 notification.setPolicyName(drools.getRule().getName());
1257 notification.setPolicyScope("${policyScope}");
1258 notification.setPolicyVersion("${policyVersion}");
1260 // Let interested parties know
1262 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1265 // Retract the event
1272 * This rule cleans up the manager and other objects after an event has
1276 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1278 $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1279 $clTimer : ControlLoopTimer ( closedLoopControlName == $clName, requestID == $requestId.toString() )
1280 $operations : LinkedList()
1281 from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, onset.getRequestId() == $requestId ) )
1282 $opTimers : LinkedList()
1283 from collect( OperationTimer( closedLoopControlName == $clName, requestID == $requestId.toString() ) )
1284 $locks : LinkedList()
1285 from collect( TargetLock (requestID == $requestId) )
1286 not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1289 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1290 logger.info("{}: {}", $clName, drools.getRule().getName());
1292 logger.debug("{}: {}: manager={} clTimer={} operations={}",
1293 $clName, drools.getRule().getName(),
1294 $manager, $clTimer, $operations.size());
1297 // Retract EVERYTHING
1302 for(Object manager: $operations) {
1303 retract((ControlLoopOperationManager) manager);
1305 for(Object opTimer: $opTimers) {
1306 retract((OperationTimer) opTimer);
1308 for(Object lock: $locks) {
1309 TargetLock tgt = (TargetLock) lock;
1311 // Ensure we release the lock
1313 PolicyGuard.unlockTarget(tgt);
1320 * This rule will clean up any rogue onsets where there is no
1321 * ControlLoopParams object corresponding to the onset event.
1324 rule "${policyName}.EVENT.CLEANUP"
1326 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1327 not ( Params( getClosedLoopControlName() == $clName) )
1330 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1331 logger.info("{}: {}", $clName, drools.getRule().getName());
1332 logger.debug("{}: {}: orphan onset event={}",
1333 $clName, drools.getRule().getName(), $event);
1339 * Creates a cleaner for every Params object.
1340 * This has a higher salience so that it is fired before PARAMS.FINISHED in ANY policy.
1342 rule "${policyName}.PARAMS.CLEANING"
1346 ParamsInitCleaner( )
1349 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1350 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1351 $params.getControlLoopYaml());
1353 ParamsCleaner cleaner = new ParamsCleaner();
1354 cleaner.setClosedLoopControlName($params.getClosedLoopControlName());
1355 cleaner.setControlLoopYaml($params.getControlLoopYaml());
1360 * Finished creating cleaner objects, so remove the trigger.
1361 * This has a higher salience so that it is fired before processing any events.
1363 rule "${policyName}.PARAMS.FINISHED"
1366 $initCleaner: ParamsInitCleaner( )
1369 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1370 logger.info("{}: {}", $initCleaner.getClosedLoopControlName(), drools.getRule().getName());
1372 retract($initCleaner);
1376 * Identifies Params objects that are still active, removing their associated cleaners.
1377 * This should only leave one active Params object for each policy.
1378 * This has a higher salience so that it is fired before PARAMS.DELETE in ANY policy.
1380 rule "${policyName}.PARAMS.ACTIVE"
1383 $params: Params( getClosedLoopControlName() == "${closedLoopControlName}",
1384 getControlLoopYaml() == "${controlLoopYaml}" )
1385 $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}",
1386 getControlLoopYaml() == "${controlLoopYaml}" )
1389 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1390 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1391 $params.getControlLoopYaml());
1397 * Delete Params objects that are not active (i.e., those that still have an associated
1399 * This has a higher salience so that it is fired before PARAMS.CLEANED in ANY policy.
1401 rule "${policyName}.PARAMS.DELETE"
1405 $cleaner: ParamsCleaner( getClosedLoopControlName() == $params.getClosedLoopControlName(),
1406 getControlLoopYaml() == $params.getControlLoopYaml() )
1409 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1410 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1411 $params.getControlLoopYaml());
1417 * Finished clean-up, so delete the cleaner objects.
1418 * This has a higher salience so that it is fired before processing any events.
1420 rule "${policyName}.PARAMS.CLEANED"
1423 $cleaner: ParamsCleaner( )
1426 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1427 logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(),
1428 $cleaner.getControlLoopYaml());