2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-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.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.vfc.VFCRequest;
45 import org.onap.policy.vfc.VFCResponse;
46 import org.onap.policy.vfc.VFCManager;
47 import org.onap.policy.so.SOManager;
48 import org.onap.policy.so.SORequest;
49 import org.onap.policy.so.SORequestStatus;
50 import org.onap.policy.so.SORequestDetails;
51 import org.onap.policy.so.SOModelInfo;
52 import org.onap.policy.so.SOCloudConfiguration;
53 import org.onap.policy.so.SORequestInfo;
54 import org.onap.policy.so.SORequestParameters;
55 import org.onap.policy.so.SORelatedInstanceListElement;
56 import org.onap.policy.so.SORelatedInstance;
57 import org.onap.policy.so.SOResponse;
58 import org.onap.policy.so.SOResponseWrapper;
59 import org.onap.policy.guard.PolicyGuard;
60 import org.onap.policy.guard.PolicyGuard.LockResult;
61 import org.onap.policy.guard.TargetLock;
62 import org.onap.policy.guard.GuardResult;
63 import org.onap.policy.guard.PolicyGuardRequest;
64 import org.onap.policy.guard.PolicyGuardResponse;
65 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
66 import org.onap.policy.guard.PolicyGuardXacmlHelper;
68 import org.yaml.snakeyaml.Yaml;
69 import org.yaml.snakeyaml.constructor.Constructor;
71 import org.slf4j.LoggerFactory;
72 import org.slf4j.Logger;
74 import java.time.Instant;
75 import java.util.LinkedList;
76 import java.util.Iterator;
78 import org.onap.policy.drools.system.PolicyEngine;
81 * This structure mimics the Params structure.
82 * Its only purpose is to allow management of
83 * rules by the PAP component..
84 * It has no use at runtime since the rules go by
85 * Params for matching purposes.
88 closedLoopControlName : String
89 controlLoopYaml : String
93 * Control Loop Identity
96 closedLoopControlName : String
97 controlLoopYaml : String
101 * Used to clean up Params that no longer have associated rules.
103 declare ParamsCleaner
104 closedLoopControlName : String
105 controlLoopYaml : String
112 declare OperationTimer
113 closedLoopControlName : String
121 declare ControlLoopTimer
122 closedLoopControlName : String
129 * Called once and only once to insert the parameters into working memory for this Closed Loop policy.
130 * This has a higher salience so we can ensure that the Params is created before we have a chance to
131 * discard any events.
134 rule "${policyName}.SETUP"
137 not( Params( getClosedLoopControlName() == "${closedLoopControlName}", getControlLoopYaml() == "${controlLoopYaml}" ) )
140 Params params = new Params();
141 params.setClosedLoopControlName("${closedLoopControlName}");
142 params.setControlLoopYaml("${controlLoopYaml}");
145 // Note: globals have bad behavior when persistence is used,
146 // hence explicitly getting the logger vs using a global
148 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
149 logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(), params.getControlLoopYaml());
154 * This rule responds to DCAE Events where there is no manager yet. Either it is
155 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
158 rule "${policyName}.EVENT"
160 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
161 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
162 not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() ) )
165 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
166 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
171 // Check the event, because we need it to not be null when
172 // we create the ControlLoopEventManager. The ControlLoopEventManager
173 // will do extra syntax checking as well check if the closed loop is disabled.
175 if ($event.getRequestId() == null) {
176 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
177 notification.setNotification(ControlLoopNotificationType.REJECTED);
178 notification.setFrom("policy");
179 notification.setMessage("Missing requestId");
180 notification.setPolicyName(drools.getRule().getName());
181 notification.setPolicyScope("${policyScope}");
182 notification.setPolicyVersion("${policyVersion}");
185 // Let interested parties know
187 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
190 // Retract it from memory
193 } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
194 throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
197 // Create an EventManager
199 ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(), $event.getRequestId());
201 // Determine if EventManager can actively process the event (i.e. syntax, is_closed_loop_disabled checks etc.)
203 VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
204 notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
205 notification.setPolicyName(drools.getRule().getName());
206 notification.setPolicyScope("${policyScope}");
207 notification.setPolicyVersion("${policyVersion}");
209 // Are we actively pursuing this event?
211 if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
213 // Insert Event Manager into memory, this will now kick off processing.
217 // Let interested parties know
219 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
221 // Setup the Overall Control Loop timer
223 ControlLoopTimer clTimer = new ControlLoopTimer();
224 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
225 clTimer.setRequestID($event.getRequestId().toString());
226 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
233 // Let interested parties know
235 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
237 // Retract it from memory
243 // Now that the manager is inserted into Drools working memory, we'll wait for
244 // another rule to fire in order to continue processing. This way we can also
245 // then screen for additional ONSET and ABATED events for this RequestId.
248 } catch (Exception e) {
249 logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
251 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
252 notification.setNotification(ControlLoopNotificationType.REJECTED);
253 notification.setMessage("Exception occurred: " + e.getMessage());
254 notification.setPolicyName(drools.getRule().getName());
255 notification.setPolicyScope("${policyScope}");
256 notification.setPolicyVersion("${policyVersion}");
260 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
270 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
271 * is now created. We can start processing the yaml specification via the Event Manager.
274 rule "${policyName}.EVENT.MANAGER"
276 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
277 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
278 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
279 $clTimer : ControlLoopTimer ( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
282 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
283 logger.info("{}: {}: event={} manager={} clTimer={}",
284 $params.getClosedLoopControlName(), drools.getRule().getName(),
285 $event, $manager, $clTimer);
289 // Check which event this is.
291 ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
293 // Check what kind of event this is
295 if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
297 // We don't care about subsequent onsets
299 logger.info("{}: {}: subsequent onset",
300 $params.getClosedLoopControlName(), drools.getRule().getName());
304 if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
306 // Ignore any bad syntax events
308 logger.warn("{}: {}: syntax error",
309 $params.getClosedLoopControlName(), drools.getRule().getName());
314 // We only want the initial ONSET event in memory,
315 // all the other events need to be retracted to support
316 // cleanup and avoid the other rules being fired for this event.
318 if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
319 logger.warn("{}: {}: not first onset",
320 $params.getClosedLoopControlName(), drools.getRule().getName());
324 logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(),
325 drools.getRule().getName(), $event.getTarget());
327 // Now start seeing if we need to process this event
331 // Check if this is a Final Event
333 VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
336 if (notification != null) {
338 // Its final, but are we waiting for abatement?
340 if ($manager.getNumAbatements() > 0) {
341 logger.info("{}: {}: abatement received for {}. Closing the control loop",
342 $params.getClosedLoopControlName(), drools.getRule().getName(),
343 $event.getRequestId());
345 /// DB Write---end event processing for this RequestId()
346 $manager.commitAbatement("Event Abated","Closed");
348 notification.setFrom("policy");
349 notification.setPolicyName(drools.getRule().getName());
350 notification.setPolicyScope("${policyScope}");
351 notification.setPolicyVersion("${policyVersion}");
353 // In this case, we are done
355 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
359 TargetLock lock = $manager.unlockCurrentOperation();
361 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
362 drools.getRule().getName(), lock);
366 // Retract everything from memory
368 logger.info("{}: {}: retracting onset, manager, and timer",
369 $params.getClosedLoopControlName(), drools.getRule().getName());
371 retract($manager.getOnsetEvent());
375 // TODO - what if we get subsequent Events for this RequestId?
376 // By default, it will all start over again. May be confusing for Ruby.
377 // Or, we could track this and then subsequently ignore the events
381 // Check whether we need to wait for abatement
383 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
384 logger.info("{}: {}: waiting for abatement ..",
385 $params.getClosedLoopControlName(), drools.getRule().getName());
387 logger.info("{}: {}: no abatement expect for {}. Closing the control loop",
388 $params.getClosedLoopControlName(), drools.getRule().getName(),
389 $event.getRequestId());
391 notification.setFrom("policy");
392 notification.setPolicyName(drools.getRule().getName());
393 notification.setPolicyScope("${policyScope}");
394 notification.setPolicyVersion("${policyVersion}");
397 // In this case, we are done
399 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
403 TargetLock lock = $manager.unlockCurrentOperation();
405 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
406 drools.getRule().getName(), lock);
410 // Retract everything from memory
412 logger.info("{}: {}: retracting onset, manager, and timer",
413 $params.getClosedLoopControlName(), drools.getRule().getName());
415 retract($manager.getOnsetEvent());
422 // NOT final, so let's ask for the next operation
424 ControlLoopOperationManager operation = $manager.processControlLoop();
425 if (operation != null) {
427 // Let's ask for a lock right away
429 LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
430 logger.info("{}: {}: guard lock acquired={}",
431 $params.getClosedLoopControlName(), drools.getRule().getName(),
433 if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
435 // insert the operation into memory
440 // insert operation timeout object
442 OperationTimer opTimer = new OperationTimer();
443 opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
444 opTimer.setRequestID($event.getRequestId().toString());
445 opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
449 // Insert lock into memory
451 insert(result.getB());
454 logger.debug("The target resource {} is already processing",
455 $event.getAai().get($event.getTarget()));
456 notification = new VirtualControlLoopNotification($event);
457 notification.setNotification(ControlLoopNotificationType.REJECTED);
458 notification.setMessage("The target " + $event.getAai().get($event.getTarget()) + " is already locked");
459 notification.setFrom("policy");
460 notification.setPolicyName(drools.getRule().getName());
461 notification.setPolicyScope("${policyScope}");
462 notification.setPolicyVersion("${policyVersion}");
464 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
470 if(result.getB() != null) {
471 retract(result.getB());
474 logger.info("{}: {}: starting operation={}",
475 $params.getClosedLoopControlName(), drools.getRule().getName(),
479 // Probably waiting for abatement
481 logger.info("{}: {}: no operation, probably waiting for abatement",
482 $params.getClosedLoopControlName(), drools.getRule().getName());
485 } catch (Exception e) {
486 logger.warn("{}: {}: unexpected",
487 $params.getClosedLoopControlName(),
488 drools.getRule().getName(), e);
490 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
491 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
492 notification.setMessage(e.getMessage());
493 notification.setFrom("policy");
494 notification.setPolicyName(drools.getRule().getName());
495 notification.setPolicyScope("${policyScope}");
496 notification.setPolicyVersion("${policyVersion}");
498 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
509 * Guard Permitted, let's send request to the actor.
512 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
514 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
515 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
516 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
517 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
518 $lock : TargetLock (requestID == $event.getRequestId())
519 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
522 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
523 logger.info("{}: {}: event={} manager={} operation={} lock={}",
524 $params.getClosedLoopControlName(), drools.getRule().getName(),
525 $event, $manager, $operation, $lock);
527 Object request = null;
528 boolean caughtException = false;
531 request = $operation.startOperation($event);
533 if (request != null) {
534 logger.debug("{}: {}: starting operation ..",
535 $params.getClosedLoopControlName(), drools.getRule().getName());
537 // Tell interested parties we are performing this Operation
539 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
540 notification.setNotification(ControlLoopNotificationType.OPERATION);
541 notification.setMessage($operation.getOperationMessage());
542 notification.setHistory($operation.getHistory());
543 notification.setFrom("policy");
544 notification.setPolicyName(drools.getRule().getName());
545 notification.setPolicyScope("${policyScope}");
546 notification.setPolicyVersion("${policyVersion}");
548 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
550 switch ($operation.policy.getActor()){
554 if (request instanceof Request) {
555 PolicyEngine.manager.deliver("APPC-CL", request);
557 else if (request instanceof LcmRequestWrapper) {
558 PolicyEngine.manager.deliver("APPC-LCM-READ", request);
562 // at this point the AAI named query request should have already been made, the response recieved and used
563 // in the construction of the SO Request which is stored in operationRequest
565 if(request instanceof SORequest) {
566 // Call SO. The response will be inserted into memory once it's received
567 SOActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(), request);
571 if (request instanceof VFCRequest) {
573 Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
580 // What happens if its null?
582 logger.warn("{}: {}: unexpected null operation request",
583 $params.getClosedLoopControlName(),
584 drools.getRule().getName());
585 if ("SO".equals($operation.policy.getActor())) {
588 modify($manager) {finishOperation($operation)};
590 else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
593 modify($manager) {finishOperation($operation)};
597 } catch (Exception e) {
598 String msg = e.getMessage();
599 logger.warn("{}: {}: operation={}: AAI failure: {}",
600 $params.getClosedLoopControlName(), drools.getRule().getName(),
602 $operation.setOperationHasException(msg);
604 if(request != null) {
606 // Create a notification for it ("DB Write - end operation")
608 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
609 notification.setFrom("policy");
610 notification.setPolicyName(drools.getRule().getName());
611 notification.setPolicyScope("${policyScope}");
612 notification.setPolicyVersion("${policyVersion}");
613 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
614 notification.setMessage($operation.getOperationHistory());
615 notification.setHistory($operation.getHistory());
617 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
622 caughtException = true;
625 // Having the modify statement in the catch clause doesn't work for whatever reason
626 if (caughtException) {
627 modify($manager) {finishOperation($operation)};
634 * We were able to acquire a lock so now let's ask Xacml Guard whether
635 * we are allowed to proceed with the request to the actor.
638 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
640 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
641 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
642 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
643 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
644 $lock : TargetLock (requestID == $event.getRequestId())
647 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
648 logger.info("{}: {}: event={} manager={} operation={} lock={}",
649 $params.getClosedLoopControlName(), drools.getRule().getName(),
650 $event, $manager, $operation, $lock);
653 // Sending notification that we are about to query Guard ("DB write - start operation")
655 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
656 notification.setNotification(ControlLoopNotificationType.OPERATION);
657 notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe());
658 notification.setHistory($operation.getHistory());
659 notification.setFrom("policy");
660 notification.setPolicyName(drools.getRule().getName());
661 notification.setPolicyScope("${policyScope}");
662 notification.setPolicyVersion("${policyVersion}");
664 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
667 // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
668 // just change guardEnabled to false.
670 // In order to use REST XACML, provide a URL instead of "" as a second argument
671 // to the CallGuardTask() and set the first argument to null
672 // (instead of XacmlPdpEngine).
675 // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
676 boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
680 Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
681 drools.getWorkingMemory(),
682 $event.getClosedLoopControlName(),
683 $operation.policy.getActor().toString(),
684 $operation.policy.getRecipe(),
685 $operation.getTargetEntity(),
686 $event.getRequestId().toString(),
688 AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
689 return(resp == null ? null : resp.countVfModules());
694 insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
700 // This rule will be triggered when a thread talking to the XACML Guard inserts a
701 // guardResponse object into the working memory
703 rule "${policyName}.GUARD.RESPONSE"
705 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
706 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
707 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
708 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
709 $lock : TargetLock (requestID == $event.getRequestId())
710 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
711 $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
714 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
715 logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
716 $params.getClosedLoopControlName(), drools.getRule().getName(),
717 $event, $manager, $operation, $lock, $opTimer, $guardResponse);
720 //we will permit the operation if there was no Guard for it
721 if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
722 $guardResponse.setResult("Permit");
726 // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
728 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
729 notification.setNotification(ControlLoopNotificationType.OPERATION);
730 notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe() + " is " + $guardResponse.getResult());
731 notification.setHistory($operation.getHistory());
732 notification.setFrom("policy");
733 notification.setPolicyName(drools.getRule().getName());
734 notification.setPolicyScope("${policyScope}");
735 notification.setPolicyVersion("${policyVersion}");
737 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
739 if("Permit".equalsIgnoreCase($guardResponse.getResult())){
741 modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
744 //This is the Deny case
745 $operation.startOperation($event);
746 $operation.setOperationHasGuardDeny();
749 modify($manager) {finishOperation($operation)};
752 retract($guardResponse);
758 * This rule responds to APPC Response Events
760 * I would have like to be consistent and write the Response like this:
761 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
763 * However, no compile error was given. But a runtime error was given. I think
764 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
767 rule "${policyName}.APPC.RESPONSE"
769 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
770 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
771 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
772 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
773 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
774 $lock : TargetLock (requestID == $event.getRequestId())
775 $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
778 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
779 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
780 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
781 $params.getClosedLoopControlName(), drools.getRule().getName(),
782 $event, $manager, $operation, $lock, $opTimer, $response);
784 // Get the result of the operation
786 PolicyResult policyResult = $operation.onResponse($response);
787 if (policyResult != null) {
788 logger.debug("{}: {}: operation finished - result={}",
789 $params.getClosedLoopControlName(), drools.getRule().getName(),
792 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
794 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
795 notification.setFrom("policy");
796 notification.setPolicyName(drools.getRule().getName());
797 notification.setPolicyScope("${policyScope}");
798 notification.setPolicyVersion("${policyVersion}");
799 notification.setMessage($operation.getOperationHistory());
800 notification.setHistory($operation.getHistory());
801 if (policyResult.equals(PolicyResult.SUCCESS)) {
802 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
804 // Let interested parties know
806 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
808 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
810 // Let interested parties know
812 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
815 // Ensure the operation is complete
817 if ($operation.isOperationComplete() == true) {
819 // It is complete, remove it from memory
823 // We must also retract the timer object
824 // NOTE: We could write a Rule to do this
828 // Complete the operation
830 modify($manager) {finishOperation($operation)};
833 // Just doing this will kick off the LOCKED rule again
835 modify($operation) {};
839 // Its not finished yet (i.e. expecting more Response objects)
841 // Or possibly it is a leftover response that we timed the request out previously
845 // We are going to retract these objects from memory
852 * The problem with Responses is that they don't have a controlLoopControlName
853 * field in them, so the only way to attach them is via RequestId. If we have multiple
854 * control loop .drl's loaded in the same container, we need to be sure the cleanup
855 * rules don't remove Responses for other control loops.
858 rule "${policyName}.APPC.RESPONSE.CLEANUP"
860 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
861 $response : Response($id : getCommonHeader().RequestId )
862 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
865 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
866 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
867 logger.debug("{}: {}: orphan appc response={}",
868 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
878 * This rule responds to APPC Response Events using the new LCM interface provided by appc
881 rule "${policyName}.APPC.LCM.RESPONSE"
883 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
884 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
885 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
886 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
887 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
888 $lock : TargetLock (requestID == $event.getRequestId())
889 $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
892 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
893 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
894 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
895 $params.getClosedLoopControlName(), drools.getRule().getName(),
896 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
899 // Get the result of the operation
901 PolicyResult policyResult = $operation.onResponse($response);
902 if (policyResult != null) {
903 logger.debug("{}: {}: operation finished - result={}",
904 $params.getClosedLoopControlName(), drools.getRule().getName(),
908 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
910 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
911 notification.setFrom("policy");
912 notification.setPolicyName(drools.getRule().getName());
913 notification.setPolicyScope("${policyScope}");
914 notification.setPolicyVersion("${policyVersion}");
915 notification.setMessage($operation.getOperationHistory());
916 notification.setHistory($operation.getHistory());
917 if (policyResult.equals(PolicyResult.SUCCESS)) {
918 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
920 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
922 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
924 // Ensure the operation is complete
926 if ($operation.isOperationComplete() == true) {
928 // It is complete, remove it from memory
932 // We must also retract the timer object
933 // NOTE: We could write a Rule to do this
937 // Complete the operation
939 modify($manager) {finishOperation($operation)};
942 // Just doing this will kick off the LOCKED rule again
944 modify($operation) {};
948 // Its not finished yet (i.e. expecting more Response objects)
950 // Or possibly it is a leftover response that we timed the request out previously
954 // We are going to retract these objects from memory
961 * Clean Up any lingering LCM reponses
964 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
966 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
967 $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
968 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
971 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
972 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
973 logger.debug("{}: {}: orphan appc response={}",
974 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
983 * This rule responds to SO Response Events
986 rule "${policyName}.SO.RESPONSE"
988 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
989 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
990 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
991 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
992 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
993 $lock : TargetLock (requestID == $event.getRequestId())
994 $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
997 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
998 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
999 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1000 $params.getClosedLoopControlName(), drools.getRule().getName(),
1001 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1003 // Get the result of the operation
1005 PolicyResult policyResult = $operation.onResponse($response);
1006 if (policyResult != null) {
1007 logger.debug("{}: {}: operation finished - result={}",
1008 $params.getClosedLoopControlName(), drools.getRule().getName(),
1012 // This Operation has completed, construct a notification showing our results
1014 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1015 notification.setFrom("policy");
1016 notification.setPolicyName(drools.getRule().getName());
1017 notification.setPolicyScope("${policyScope}");
1018 notification.setPolicyVersion("${policyVersion}");
1019 notification.setMessage($operation.getOperationHistory());
1020 notification.setHistory($operation.getHistory());
1021 if (policyResult.equals(PolicyResult.SUCCESS)) {
1022 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1024 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1027 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1029 // Ensure the operation is complete
1031 if ($operation.isOperationComplete() == true) {
1033 // It is complete, remove it from memory
1035 retract($operation);
1037 // We must also retract the timer object
1038 // NOTE: We could write a Rule to do this
1042 // Complete the operation
1044 modify($manager) {finishOperation($operation)};
1047 // Just doing this will kick off the LOCKED rule again
1049 modify($operation) {};
1053 // Its not finished yet (i.e. expecting more Response objects)
1055 // Or possibly it is a leftover response that we timed the request out previously
1059 // We are going to retract these objects from memory
1067 * This rule responds to VFC Response Events
1070 rule "${policyName}.VFC.RESPONSE"
1072 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1073 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(), closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1074 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1075 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1076 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString() )
1077 $lock : TargetLock (requestID == $event.getRequestId())
1078 $response : VFCResponse( requestId.toString() == $event.getRequestId().toString() )
1080 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1081 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1082 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1083 $params.getClosedLoopControlName(), drools.getRule().getName(),
1084 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1086 // Get the result of the operation
1088 PolicyResult policyResult = $operation.onResponse($response);
1089 if (policyResult != null) {
1091 // This Operation has completed, construct a notification showing our results
1093 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1094 notification.setFrom("policy");
1095 notification.setPolicyName(drools.getRule().getName());
1096 notification.setPolicyScope("${policyScope}");
1097 notification.setPolicyVersion("${policyVersion}");
1098 notification.setMessage($operation.getOperationHistory());
1099 notification.setHistory($operation.getHistory());
1101 // Ensure the operation is complete
1103 if ($operation.isOperationComplete() == true) {
1105 // It is complete, remove it from memory
1107 retract($operation);
1109 // We must also retract the timer object
1110 // NOTE: We could write a Rule to do this
1114 // Complete the operation
1116 modify($manager) {finishOperation($operation)};
1119 // Just doing this will kick off the LOCKED rule again
1121 modify($operation) {};
1125 // Its not finished yet (i.e. expecting more Response objects)
1127 // Or possibly it is a leftover response that we timed the request out previously
1131 // We are going to retract these objects from memory
1139 * This is the timer that manages the timeout for an individual operation.
1142 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1145 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1146 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1147 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1148 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1149 $opTimer : OperationTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), $to : getDelay() )
1150 $lock : TargetLock (requestID == $event.getRequestId())
1153 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1154 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1155 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1156 $params.getClosedLoopControlName(), drools.getRule().getName(),
1157 $event, $manager, $operation, $lock, $operation, $opTimer);
1160 // Tell it its timed out
1162 $operation.setOperationHasTimedOut();
1164 // Create a notification for it ("DB Write - end operation")
1166 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1167 notification.setFrom("policy");
1168 notification.setPolicyName(drools.getRule().getName());
1169 notification.setPolicyScope("${policyScope}");
1170 notification.setPolicyVersion("${policyVersion}");
1171 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1172 notification.setMessage($operation.getOperationHistory());
1173 notification.setHistory($operation.getHistory());
1175 // Let interested parties know
1177 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1179 // Get rid of the timer
1183 // Ensure the operation is complete
1185 if ($operation.isOperationComplete() == true) {
1187 // It is complete, remove it from memory
1189 retract($operation);
1191 // Complete the operation
1193 modify($manager) {finishOperation($operation)};
1196 // Just doing this will kick off the LOCKED rule again
1198 modify($operation) {};
1204 * This is the timer that manages the overall control loop timeout.
1207 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1210 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1211 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1212 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1213 $clTimer : ControlLoopTimer ( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), $to : getDelay() )
1216 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1217 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1219 logger.debug("{}: {}: event={}",
1220 $params.getClosedLoopControlName(), drools.getRule().getName(),
1223 // Tell the Event Manager it has timed out
1225 VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1226 if (notification != null) {
1227 notification.setFrom("policy");
1228 notification.setPolicyName(drools.getRule().getName());
1229 notification.setPolicyScope("${policyScope}");
1230 notification.setPolicyVersion("${policyVersion}");
1232 // Let interested parties know
1234 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1237 // Retract the event
1244 * This rule cleans up the manager and other objects after an event has
1248 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1250 $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1251 $clTimer : ControlLoopTimer ( closedLoopControlName == $clName, requestID == $requestId.toString() )
1252 $operations : LinkedList()
1253 from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, onset.getRequestId() == $requestId ) )
1254 $opTimers : LinkedList()
1255 from collect( OperationTimer( closedLoopControlName == $clName, requestID == $requestId.toString() ) )
1256 $locks : LinkedList()
1257 from collect( TargetLock (requestID == $requestId) )
1258 not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1261 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1262 logger.info("{}: {}", $clName, drools.getRule().getName());
1264 logger.debug("{}: {}: manager={} clTimer={} operations={}",
1265 $clName, drools.getRule().getName(),
1266 $manager, $clTimer, $operations.size());
1269 // Retract EVERYTHING
1274 for(Object manager: $operations) {
1275 retract((ControlLoopOperationManager) manager);
1277 for(Object opTimer: $opTimers) {
1278 retract((OperationTimer) opTimer);
1280 for(Object lock: $locks) {
1281 TargetLock tgt = (TargetLock) lock;
1283 // Ensure we release the lock
1285 PolicyGuard.unlockTarget(tgt);
1292 * This rule will clean up any rogue onsets where there is no
1293 * ControlLoopParams object corresponding to the onset event.
1296 rule "${policyName}.EVENT.CLEANUP"
1298 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1299 not ( Params( getClosedLoopControlName() == $clName) )
1302 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1303 logger.info("{}: {}", $clName, drools.getRule().getName());
1304 logger.debug("{}: {}: orphan onset event={}",
1305 $clName, drools.getRule().getName(), $event);
1312 * When rules are deleted, the associated Params (and its subordinate objects)
1313 * remain in working memory, because there are no longer any rules to clean
1314 * them up. However, ANY time new rules are loaded, this rule will trigger
1315 * a clean-up of ALL Params, regardless of their name & yaml, thus removing
1316 * any that no longer have associated rules.
1317 * This has a higher salience so that we immediately check Params when the
1318 * rules change, before processing any events.
1321 rule "${policyName}.PARAMS.CHECKUP"
1324 Params( $clName: closedLoopControlName, $yaml: controlLoopYaml )
1327 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1328 logger.info("{}: {} : YAML=[{}]", $clName, drools.getRule().getName(), $yaml);
1330 ParamsCleaner cleaner = new ParamsCleaner();
1331 cleaner.setClosedLoopControlName($clName);
1332 cleaner.setControlLoopYaml($yaml);
1339 * This rule removes "cleaner" objects for rules that are still active, thus
1340 * preventing the associated Params objects from being removed. Any cleaners
1341 * that are left after this rule has fired will cause their corresponding Params
1343 * This has a higher salience so that we discard the cleaner before it has
1344 * a chance to force the removal of the associated Params.
1347 rule "${policyName}.CLEANER.ACTIVE"
1350 $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}", getControlLoopYaml() == "${controlLoopYaml}" )
1353 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1354 logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(), $cleaner.getControlLoopYaml());
1361 * This rule removes Params objects that no longer have associated rules; if a
1362 * Params still had associated rules, then the cleaner would have been removed
1363 * by those rules and thus this rule would not fire.
1364 * This has a higher salience so that we remove old Params before it causes any
1365 * events to be processed.
1368 rule "${policyName}.PARAMS.CLEANUP"
1371 $params: Params( $clName: closedLoopControlName, $yaml: controlLoopYaml )
1372 ParamsCleaner( getClosedLoopControlName() == $clName, getControlLoopYaml() == $yaml )
1375 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1376 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(), $params.getControlLoopYaml());
1380 // Note: the cleaner may be needed for cleaning additional params, thus
1381 // we do not retract it here - we'll leave that to another rule
1386 * This rule removes "cleaner" objects when they're no longer needed.
1389 rule "${policyName}.CLEANER.CLEANUP"
1391 $cleaner: ParamsCleaner( )
1394 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1395 logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(), $cleaner.getControlLoopYaml());