2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2019 Bell Canada.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.controlloop;
24 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
26 import org.onap.policy.controlloop.VirtualControlLoopEvent;
27 import org.onap.policy.controlloop.VirtualControlLoopNotification;
28 import org.onap.policy.controlloop.ControlLoopEventStatus;
29 import org.onap.policy.controlloop.ControlLoopNotificationType;
30 import org.onap.policy.controlloop.ControlLoopLogger;
31 import org.onap.policy.controlloop.policy.PolicyResult;
32 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
33 import org.onap.policy.controlloop.policy.Policy;
34 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
35 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NewEventStatus;
36 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
37 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
38 import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider;
39 import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider.CdsActorServiceManager;
40 import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants;
41 import org.onap.policy.aai.AaiNqResponseWrapper;
42 import org.onap.policy.aai.AaiCqResponse;
43 import org.onap.policy.appc.Request;
44 import org.onap.policy.appc.Response;
45 import org.onap.policy.appc.CommonHeader;
46 import org.onap.policy.appclcm.LcmRequestWrapper;
47 import org.onap.policy.appclcm.LcmResponseWrapper;
48 import org.onap.policy.appclcm.LcmRequest;
49 import org.onap.policy.appclcm.LcmResponse;
50 import org.onap.policy.appclcm.LcmCommonHeader;
51 import org.onap.policy.cds.CdsResponse;
52 import org.onap.policy.cds.client.CdsProcessorGrpcClient;
53 import org.onap.policy.cds.properties.CdsServerProperties;
54 import org.onap.policy.sdnr.PciRequestWrapper;
55 import org.onap.policy.sdnr.PciResponseWrapper;
56 import org.onap.policy.sdnr.PciRequest;
57 import org.onap.policy.sdnr.PciResponse;
58 import org.onap.policy.vfc.VfcRequest;
59 import org.onap.policy.vfc.VfcResponse;
60 import org.onap.policy.vfc.VfcManager;
61 import org.onap.policy.so.SoManager;
62 import org.onap.policy.so.SoRequest;
63 import org.onap.policy.so.SoResponseWrapper;
64 import org.onap.policy.sdnc.SdncRequest;
65 import org.onap.policy.sdnc.SdncManager;
66 import org.onap.policy.sdnc.SdncResponse;
67 import org.onap.policy.guard.PolicyGuard;
68 import org.onap.policy.guard.PolicyGuard.LockResult;
69 import org.onap.policy.guard.TargetLock;
70 import org.onap.policy.guard.GuardResult;
71 import org.onap.policy.guard.PolicyGuardRequest;
72 import org.onap.policy.guard.PolicyGuardResponse;
73 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
74 import org.onap.policy.guard.PolicyGuardXacmlHelper;
76 import org.yaml.snakeyaml.Yaml;
77 import org.yaml.snakeyaml.constructor.Constructor;
79 import org.slf4j.LoggerFactory;
80 import org.slf4j.Logger;
82 import java.time.Instant;
83 import java.util.LinkedList;
84 import java.util.Iterator;
86 import org.onap.policy.drools.system.PolicyEngineConstants;
89 * This structure mimics the Params structure.
90 * Its only purpose is to allow management of
91 * rules by the PAP component..
92 * It has no use at runtime since the rules go by
93 * Params for matching purposes.
96 closedLoopControlName : String
97 controlLoopYaml : String
101 * Control Loop Identity
104 closedLoopControlName : String
105 controlLoopYaml : String
109 * Used to trigger clean up Params that no longer have associated rules.
111 declare ParamsInitCleaner
112 closedLoopControlName : String // only used when logging
116 * Used to clean up Params that no longer have associated rules.
118 declare ParamsCleaner
119 closedLoopControlName : String
120 controlLoopYaml : String
124 * This object is to provide support for timeouts
125 * due to a bug in drools' built-in timers
127 declare ControlLoopTimer
128 closedLoopControlName : String
132 //timerType is the type of timer: either "ClosedLoop" or "Operation"
138 * Called to insert the parameters into working memory for this Closed Loop policy. This is called
139 * once each time a closed loop is added or its YAML is updated.
140 * This has a higher salience so we can ensure that the Params is created before we have a chance to
141 * discard any events.
144 rule "${policyName}.SETUP"
147 not( Params( getClosedLoopControlName() == "${closedLoopControlName}",
148 getControlLoopYaml() == "${controlLoopYaml}" ) )
151 Params params = new Params();
152 params.setClosedLoopControlName("${closedLoopControlName}");
153 params.setControlLoopYaml("${controlLoopYaml}");
156 ParamsInitCleaner initCleaner = new ParamsInitCleaner();
157 initCleaner.setClosedLoopControlName("${closedLoopControlName}");
160 // Note: globals have bad behavior when persistence is used,
161 // hence explicitly getting the logger vs using a global
163 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
164 logger.info("{}: {} : YAML=[{}]", params.getClosedLoopControlName(), drools.getRule().getName(),
165 params.getControlLoopYaml());
170 * This rule responds to DCAE Events where there is no manager yet. Either it is
171 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
174 rule "${policyName}.EVENT"
176 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
177 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
178 not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
179 requestId == $event.getRequestId() ) )
182 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
183 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
188 // Check the event, because we need it to not be null when
189 // we create the ControlLoopEventManager. The ControlLoopEventManager
190 // will do extra syntax checking as well check if the closed loop is disabled.
192 if ($event.getRequestId() == null) {
193 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
194 notification.setNotification(ControlLoopNotificationType.REJECTED);
195 notification.setFrom("policy");
196 notification.setMessage("Missing requestId");
197 notification.setPolicyName(drools.getRule().getName());
198 notification.setPolicyScope("${policyScope}");
199 notification.setPolicyVersion("${policyVersion}");
202 // Let interested parties know
204 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
207 // Retract it from memory
210 } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
211 throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
214 // Create an EventManager
216 ControlLoopEventManager manager = new ControlLoopEventManager($params.getClosedLoopControlName(),
217 $event.getRequestId());
219 // Determine if EventManager can actively process the event
220 // (i.e. syntax, is_closed_loop_disabled checks etc.)
222 VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
223 notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
224 notification.setPolicyName(drools.getRule().getName());
225 notification.setPolicyScope("${policyScope}");
226 notification.setPolicyVersion("${policyVersion}");
228 // Are we actively pursuing this event?
230 if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
232 // Insert Event Manager into memory, this will now kick off processing.
236 // Let interested parties know
238 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
240 // Setup the Overall Control Loop timer
242 ControlLoopTimer clTimer = new ControlLoopTimer();
243 clTimer.setTimerType("ClosedLoop");
244 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
245 clTimer.setRequestId($event.getRequestId().toString());
246 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
253 // Let interested parties know
255 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
257 // Retract it from memory
263 // Now that the manager is inserted into Drools working memory, we'll wait for
264 // another rule to fire in order to continue processing. This way we can also
265 // then screen for additional ONSET and ABATED events for this RequestId.
268 } catch (Exception e) {
269 logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
271 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
272 notification.setNotification(ControlLoopNotificationType.REJECTED);
273 notification.setMessage("Exception occurred: " + e.getMessage());
274 notification.setPolicyName(drools.getRule().getName());
275 notification.setPolicyScope("${policyScope}");
276 notification.setPolicyVersion("${policyVersion}");
280 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
290 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
291 * is now created. We can start processing the yaml specification via the Event Manager.
294 rule "${policyName}.EVENT.MANAGER"
296 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
297 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
298 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
299 requestId == $event.getRequestId() )
300 $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
301 requestId == $event.getRequestId().toString(), timerType == "ClosedLoop", !expired )
304 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
305 logger.info("{}: {}: event={} manager={} clTimer={}",
306 $params.getClosedLoopControlName(), drools.getRule().getName(),
307 $event, $manager, $clTimer);
311 // Check which event this is.
313 ControlLoopEventManager.NewEventStatus eventStatus = $manager.onNewEvent($event);
315 // Check what kind of event this is
317 if (eventStatus == NewEventStatus.SUBSEQUENT_ONSET) {
319 // We don't care about subsequent onsets
321 logger.info("{}: {}: subsequent onset",
322 $params.getClosedLoopControlName(), drools.getRule().getName());
326 if (eventStatus == NewEventStatus.SYNTAX_ERROR) {
328 // Ignore any bad syntax events
330 logger.warn("{}: {}: syntax error",
331 $params.getClosedLoopControlName(), drools.getRule().getName());
336 // We only want the initial ONSET event in memory,
337 // all the other events need to be retracted to support
338 // cleanup and avoid the other rules being fired for this event.
340 if (eventStatus != NewEventStatus.FIRST_ONSET) {
341 logger.warn("{}: {}: not first onset",
342 $params.getClosedLoopControlName(), drools.getRule().getName());
346 logger.debug("{}: {}: target={}", $params.getClosedLoopControlName(),
347 drools.getRule().getName(), $event.getTarget());
349 // Now start seeing if we need to process this event
353 // Check if this is a Final Event
355 VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
358 if (notification != null) {
360 // Its final, but are we waiting for abatement?
362 if ($manager.getNumAbatements() > 0) {
363 logger.info("{}: {}: abatement received for {}. Closing the control loop",
364 $params.getClosedLoopControlName(), drools.getRule().getName(),
365 $event.getRequestId());
367 /// DB Write---end event processing for this RequestId()
368 $manager.commitAbatement("Event Abated","Closed");
370 notification.setFrom("policy");
371 notification.setPolicyName(drools.getRule().getName());
372 notification.setPolicyScope("${policyScope}");
373 notification.setPolicyVersion("${policyVersion}");
375 // In this case, we are done
377 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
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
398 // TODO - what if we get subsequent Events for this RequestId?
399 // By default, it will all start over again. May be confusing for Ruby.
400 // Or, we could track this and then subsequently ignore the events
404 // Check whether we need to wait for abatement
406 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
407 logger.info("{}: {}: waiting for abatement ..",
408 $params.getClosedLoopControlName(), drools.getRule().getName());
410 logger.info("{}: {}: no abatement expect for {}. Closing the control loop",
411 $params.getClosedLoopControlName(), drools.getRule().getName(),
412 $event.getRequestId());
414 notification.setFrom("policy");
415 notification.setPolicyName(drools.getRule().getName());
416 notification.setPolicyScope("${policyScope}");
417 notification.setPolicyVersion("${policyVersion}");
420 // In this case, we are done
422 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
426 TargetLock lock = $manager.unlockCurrentOperation();
428 logger.debug("{}: {}: retracting lock=", $params.getClosedLoopControlName(),
429 drools.getRule().getName(), lock);
433 // Retract everything from memory
435 logger.info("{}: {}: retracting onset, manager, and timer",
436 $params.getClosedLoopControlName(), drools.getRule().getName());
438 retract($manager.getOnsetEvent());
440 // don't retract manager, etc. - a clean-up rule will do that
445 // NOT final, so let's ask for the next operation
447 ControlLoopOperationManager operation = $manager.processControlLoop();
448 if (operation != null) {
450 // Let's ask for a lock right away
452 LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
453 logger.info("{}: {}: guard lock acquired={}",
454 $params.getClosedLoopControlName(), drools.getRule().getName(),
456 if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
458 // insert the operation into memory
462 // insert operation timeout object
464 ControlLoopTimer opTimer = new ControlLoopTimer();
465 opTimer.setTimerType("Operation");
466 opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
467 opTimer.setRequestId($event.getRequestId().toString());
468 Integer timeout = operation.getOperationTimeout();
469 opTimer.setDelay(timeout > 0 ? timeout.toString() + "s" : $clTimer.getDelay());
473 // Insert lock into memory
475 insert(result.getB());
477 logger.debug("The target resource {} is already processing",
478 $event.getAai().get($event.getTarget()));
479 notification = new VirtualControlLoopNotification($event);
480 notification.setNotification(ControlLoopNotificationType.REJECTED);
481 notification.setMessage("The target " + $event.getAai().get($event.getTarget())
482 + " is already locked");
483 notification.setFrom("policy");
484 notification.setPolicyName(drools.getRule().getName());
485 notification.setPolicyScope("${policyScope}");
486 notification.setPolicyVersion("${policyVersion}");
488 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
492 // don't retract manager, etc. - a clean-up rule will do that
494 if (result.getB() != null) {
495 retract(result.getB());
498 logger.info("{}: {}: starting operation={}",
499 $params.getClosedLoopControlName(), drools.getRule().getName(),
503 // Probably waiting for abatement
505 logger.info("{}: {}: no operation, probably waiting for abatement",
506 $params.getClosedLoopControlName(), drools.getRule().getName());
509 } catch (Exception e) {
510 logger.warn("{}: {}: unexpected",
511 $params.getClosedLoopControlName(),
512 drools.getRule().getName(), e);
514 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
515 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
516 notification.setMessage(e.getMessage());
517 notification.setFrom("policy");
518 notification.setPolicyName(drools.getRule().getName());
519 notification.setPolicyScope("${policyScope}");
520 notification.setPolicyVersion("${policyVersion}");
522 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
526 // don't retract manager, etc. - a clean-up rule will do that
533 * Guard Permitted, let's send request to the actor.
536 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
538 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
539 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
540 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
541 requestId == $event.getRequestId() )
542 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
543 onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
544 $lock : TargetLock (requestId == $event.getRequestId())
545 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
546 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
549 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
550 logger.info("{}: {}: event={} manager={} operation={} lock={}",
551 $params.getClosedLoopControlName(), drools.getRule().getName(),
552 $event, $manager, $operation, $lock);
554 Object request = null;
555 boolean caughtException = false;
558 request = $operation.startOperation($event);
560 if (request != null) {
561 logger.debug("{}: {}: starting operation ..",
562 $params.getClosedLoopControlName(), drools.getRule().getName());
564 // Tell interested parties we are performing this Operation
566 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
567 notification.setNotification(ControlLoopNotificationType.OPERATION);
568 notification.setMessage($operation.getOperationMessage());
569 notification.setHistory($operation.getHistory());
570 notification.setFrom("policy");
571 notification.setPolicyName(drools.getRule().getName());
572 notification.setPolicyScope("${policyScope}");
573 notification.setPolicyVersion("${policyVersion}");
575 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
577 switch ($operation.policy.getActor()){
580 if (request instanceof Request) {
581 PolicyEngineConstants.getManager().deliver("APPC-CL", request);
583 else if (request instanceof LcmRequestWrapper) {
584 PolicyEngineConstants.getManager().deliver("APPC-LCM-READ", request);
588 // at this point the AAI named query request should have already been made,
589 // the response recieved and used
590 // in the construction of the SO Request which is stored in operationRequest
592 if(request instanceof SoRequest) {
593 // Call SO. The response will be inserted into memory once it's received
594 class mySoCallback implements SoManager.SoCallback {
595 public void onSoResponseWrapper(SoResponseWrapper wrapper) {
596 drools.getWorkingMemory().insert(wrapper);
599 SoActorServiceProvider.sendRequest($event.getRequestId().toString(),
602 PolicyEngineConstants.getManager().getEnvironmentProperty("so.url"),
603 PolicyEngineConstants.getManager().getEnvironmentProperty("so.username"),
604 PolicyEngineConstants.getManager().getEnvironmentProperty("so.password"));
608 if (request instanceof VfcRequest) {
610 class myVfcCallback implements VfcManager.VfcCallback {
612 public void onResponse(VfcResponse responseError) {
613 drools.getWorkingMemory().insert(responseError);
617 Thread t = new Thread(new VfcManager(new myVfcCallback(),
619 PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.url"),
620 PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.username"),
621 PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.password")));
627 if (request instanceof SdncRequest) {
629 class mySdncCallback implements SdncManager.SdncCallback {
630 public void onCallback(SdncResponse response) {
631 drools.getWorkingMemory().insert(response);
635 Thread t = new Thread(new SdncManager(new mySdncCallback(),
636 (SdncRequest)request,
637 PolicyEngineConstants.getManager().getEnvironmentProperty("sdnc.url"),
638 PolicyEngineConstants.getManager().getEnvironmentProperty("sdnc.username"),
639 PolicyEngineConstants.getManager().getEnvironmentProperty("sdnc.password")));
644 if (request instanceof PciRequestWrapper) {
645 PolicyEngineConstants.getManager().deliver("SDNR-CL", request);
651 if(request instanceof ExecutionServiceInput) {
653 // Instantiate cds actor, service manager and grpc properties
655 CdsActorServiceProvider cdsActor = new CdsActorServiceProvider();
656 CdsActorServiceProvider.CdsActorServiceManager cdsActorServiceManager = cdsActor.new CdsActorServiceManager();
658 CdsServerProperties props = new CdsServerProperties();
659 props.setHost(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcHost"));
660 props.setPort(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPort")));
661 props.setUsername(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcUsername"));
662 props.setPassword(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcPassword"));
663 props.setTimeout(Integer.parseInt(PolicyEngineConstants.getManager().getEnvironmentProperty("cds.grpcTimeout")));
665 // Send cds grpc request
666 try (CdsProcessorGrpcClient client = new CdsProcessorGrpcClient(cdsActorServiceManager, props)) {
667 CdsResponse response =
668 cdsActorServiceManager.sendRequestToCds(client, props, (ExecutionServiceInput) request);
669 logger.info("CDS response: {}", response);
679 // What happens if its null?
681 logger.warn("{}: {}: unexpected null operation request",
682 $params.getClosedLoopControlName(),
683 drools.getRule().getName());
684 if ("SO".equals($operation.policy.getActor())) {
687 modify($manager) {finishOperation($operation)};
689 else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
692 modify($manager) {finishOperation($operation)};
694 else if ("sdnc".equalsIgnoreCase($operation.policy.getActor())) {
697 modify($manager) {finishOperation($operation)};
701 } catch (Exception e) {
702 String msg = e.getMessage();
703 logger.warn("{}: {}: operation={}: AAI failure: {}",
704 $params.getClosedLoopControlName(), drools.getRule().getName(),
706 $operation.setOperationHasException(msg);
708 if(request != null) {
710 // Create a notification for it ("DB Write - end operation")
712 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
713 notification.setFrom("policy");
714 notification.setPolicyName(drools.getRule().getName());
715 notification.setPolicyScope("${policyScope}");
716 notification.setPolicyVersion("${policyVersion}");
717 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
718 notification.setMessage($operation.getOperationHistory());
719 notification.setHistory($operation.getHistory());
721 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
726 caughtException = true;
729 // Having the modify statement in the catch clause doesn't work for whatever reason
730 if (caughtException) {
731 modify($manager) {finishOperation($operation)};
738 * We were able to acquire a lock so now let's ask Xacml Guard whether
739 * we are allowed to proceed with the request to the actor.
742 rule "${policyName}.EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
744 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
745 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
746 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
747 requestId == $event.getRequestId() )
748 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
749 onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
750 $lock : TargetLock (requestId == $event.getRequestId())
753 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
754 logger.info("{}: {}: event={} manager={} operation={} lock={}",
755 $params.getClosedLoopControlName(), drools.getRule().getName(),
756 $event, $manager, $operation, $lock);
759 // Sending notification that we are about to query Guard ("DB write - start operation")
761 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
762 notification.setNotification(ControlLoopNotificationType.OPERATION);
763 notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " "
764 + $operation.policy.getRecipe());
765 notification.setHistory($operation.getHistory());
766 notification.setFrom("policy");
767 notification.setPolicyName(drools.getRule().getName());
768 notification.setPolicyScope("${policyScope}");
769 notification.setPolicyVersion("${policyVersion}");
771 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
774 // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
775 // just change guardEnabled to false.
777 // In order to use REST XACML, provide a URL instead of "" as a second argument
778 // to the CallGuardTask() and set the first argument to null
779 // (instead of XacmlPdpEngine).
782 // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
783 boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngineConstants.getManager().getEnvironmentProperty("guard.disabled"));
784 boolean cqEnabled = "true".equalsIgnoreCase(PolicyEngineConstants.getManager().getEnvironmentProperty("aai.customQuery"));
788 Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
789 drools.getWorkingMemory(),
790 $event.getClosedLoopControlName(),
791 $operation.policy.getActor().toString(),
792 $operation.policy.getRecipe(),
793 $operation.getTargetEntity(),
794 $event.getRequestId().toString(),
797 AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
798 return(resp == null ? null : resp.countVfModules());
801 AaiCqResponse resp_cq = $manager.getCqResponse($event);
802 if (resp_cq == null){
805 String custId = $operation.policy.getTarget().getModelCustomizationId();
806 String invId = $operation.policy.getTarget().getModelInvariantId();
807 String verId = $operation.policy.getTarget().getModelVersionId();
808 return resp_cq.getVfModuleCount(custId, invId, verId);
810 } catch (Exception e){
811 logger.warn("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName(), e);
819 insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
825 // This rule will be triggered when a thread talking to the XACML Guard inserts a
826 // guardResponse object into the working memory
828 rule "${policyName}.GUARD.RESPONSE"
830 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
831 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
832 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
833 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
834 requestId == $event.getRequestId() )
835 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
836 onset.getRequestId() == $event.getRequestId() )
837 $lock : TargetLock (requestId == $event.getRequestId())
838 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
839 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
840 $guardResponse : PolicyGuardResponse(requestId == $event.getRequestId(), $operation.policy.recipe == operation)
843 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
844 logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
845 $params.getClosedLoopControlName(), drools.getRule().getName(),
846 $event, $manager, $operation, $lock, $opTimer, $guardResponse);
849 //we will permit the operation if there was no Guard for it
850 if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
851 $guardResponse.setResult("Permit");
855 // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
857 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
858 notification.setNotification(ControlLoopNotificationType.OPERATION);
859 notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe()
860 + " is " + $guardResponse.getResult());
861 notification.setHistory($operation.getHistory());
862 notification.setFrom("policy");
863 notification.setPolicyName(drools.getRule().getName());
864 notification.setPolicyScope("${policyScope}");
865 notification.setPolicyVersion("${policyVersion}");
867 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
869 if("Permit".equalsIgnoreCase($guardResponse.getResult())){
871 modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
874 //This is the Deny case
875 $operation.startOperation($event);
876 $operation.setOperationHasGuardDeny();
879 modify($manager) {finishOperation($operation)};
882 retract($guardResponse);
888 * This rule responds to APPC Response Events
890 * I would have like to be consistent and write the Response like this:
891 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
893 * However, no compile error was given. But a runtime error was given. I think
894 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
897 rule "${policyName}.APPC.RESPONSE"
899 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
900 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
901 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
902 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
903 requestId == $event.getRequestId() )
904 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
905 onset.getRequestId() == $event.getRequestId() )
906 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
907 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
908 $lock : TargetLock (requestId == $event.getRequestId())
909 $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
912 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
913 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
914 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
915 $params.getClosedLoopControlName(), drools.getRule().getName(),
916 $event, $manager, $operation, $lock, $opTimer, $response);
918 // Get the result of the operation
920 PolicyResult policyResult = $operation.onResponse($response);
921 if (policyResult != null) {
922 logger.debug("{}: {}: operation finished - result={}",
923 $params.getClosedLoopControlName(), drools.getRule().getName(),
926 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
928 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
929 notification.setFrom("policy");
930 notification.setPolicyName(drools.getRule().getName());
931 notification.setPolicyScope("${policyScope}");
932 notification.setPolicyVersion("${policyVersion}");
933 notification.setMessage($operation.getOperationHistory());
934 notification.setHistory($operation.getHistory());
935 if (policyResult.equals(PolicyResult.SUCCESS)) {
936 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
938 // Let interested parties know
940 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
942 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
944 // Let interested parties know
946 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
949 // Ensure the operation is complete
951 if ($operation.isOperationComplete() == true) {
953 // It is complete, remove it from memory
957 // We must also retract the timer object
958 // NOTE: We could write a Rule to do this
962 // Complete the operation
964 modify($manager) {finishOperation($operation)};
967 // Just doing this will kick off the LOCKED rule again
969 modify($operation) {};
973 // Its not finished yet (i.e. expecting more Response objects)
975 // Or possibly it is a leftover response that we timed the request out previously
979 // We are going to retract these objects from memory
986 * The problem with Responses is that they don't have a controlLoopControlName
987 * field in them, so the only way to attach them is via RequestId. If we have multiple
988 * control loop .drl's loaded in the same container, we need to be sure the cleanup
989 * rules don't remove Responses for other control loops.
992 rule "${policyName}.APPC.RESPONSE.CLEANUP"
994 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
995 $response : Response($id : getCommonHeader().RequestId )
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);
1012 * This rule responds to APPC Response Events using the new LCM interface provided by appc
1015 rule "${policyName}.APPC.LCM.RESPONSE"
1017 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1018 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1019 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1020 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1021 requestId == $event.getRequestId() )
1022 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1023 onset.getRequestId() == $event.getRequestId() )
1024 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1025 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1026 $lock : TargetLock (requestId == $event.getRequestId())
1027 $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1030 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1031 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1032 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1033 $params.getClosedLoopControlName(), drools.getRule().getName(),
1034 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1037 // Get the result of the operation
1039 PolicyResult policyResult = $operation.onResponse($response);
1040 if (policyResult != null) {
1041 logger.debug("{}: {}: operation finished - result={}",
1042 $params.getClosedLoopControlName(), drools.getRule().getName(),
1046 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1048 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1049 notification.setFrom("policy");
1050 notification.setPolicyName(drools.getRule().getName());
1051 notification.setPolicyScope("${policyScope}");
1052 notification.setPolicyVersion("${policyVersion}");
1053 notification.setMessage($operation.getOperationHistory());
1054 notification.setHistory($operation.getHistory());
1055 if (policyResult.equals(PolicyResult.SUCCESS)) {
1056 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1058 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1060 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1062 // Ensure the operation is complete
1064 if ($operation.isOperationComplete() == true) {
1066 // It is complete, remove it from memory
1068 retract($operation);
1070 // We must also retract the timer object
1071 // NOTE: We could write a Rule to do this
1075 // Complete the operation
1077 modify($manager) {finishOperation($operation)};
1080 // Just doing this will kick off the LOCKED rule again
1082 modify($operation) {};
1086 // Its not finished yet (i.e. expecting more Response objects)
1088 // Or possibly it is a leftover response that we timed the request out previously
1092 // We are going to retract these objects from memory
1099 * Clean Up any lingering LCM reponses
1102 rule "${policyName}.APPC.LCM.RESPONSE.CLEANUP"
1104 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1105 $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1106 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1109 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1110 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1111 logger.debug("{}: {}: orphan appc response={}",
1112 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1121 * This rule responds to SDNR Response Events using the new interface provided by SDNR
1124 rule "${policyName}.SDNR.RESPONSE"
1126 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1127 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1128 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1129 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1130 requestId == $event.getRequestId() )
1131 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1132 onset.getRequestId() == $event.getRequestId() )
1133 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1134 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1135 $lock : TargetLock (requestId == $event.getRequestId())
1136 $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1139 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1140 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1141 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1142 $params.getClosedLoopControlName(), drools.getRule().getName(),
1143 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1146 // Get the result of the operation
1148 PolicyResult policyResult = $operation.onResponse($response);
1149 if (policyResult != null) {
1150 logger.debug("{}: {}: operation finished - result={}",
1151 $params.getClosedLoopControlName(), drools.getRule().getName(),
1155 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1157 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1158 notification.setFrom("policy");
1159 notification.setPolicyName(drools.getRule().getName());
1160 notification.setPolicyScope("${policyScope}");
1161 notification.setPolicyVersion("${policyVersion}");
1162 notification.setMessage($operation.getOperationHistory());
1163 notification.setHistory($operation.getHistory());
1164 if (policyResult.equals(PolicyResult.SUCCESS)) {
1165 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1167 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1169 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1171 // Ensure the operation is complete
1173 if ($operation.isOperationComplete()) {
1175 // It is complete, remove it from memory
1177 retract($operation);
1179 // We must also retract the timer object
1180 // NOTE: We could write a Rule to do this
1184 // Complete the operation
1186 modify($manager) {finishOperation($operation)};
1189 // Just doing this will kick off the LOCKED rule again
1191 modify($operation) {};
1195 // Its not finished yet (i.e. expecting more Response objects)
1197 // Or possibly it is a leftover response that we timed the request out previously
1201 // We are going to retract these objects from memory
1208 * Clean Up any lingering SDNR reponses
1211 rule "${policyName}.SDNR.RESPONSE.CLEANUP"
1213 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1214 $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1215 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1218 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1219 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1220 logger.debug("{}: {}: orphan SDNR response={}",
1221 $params.getClosedLoopControlName(), drools.getRule().getName(), $id);
1230 * This rule responds to SO Response Events
1233 rule "${policyName}.SO.RESPONSE"
1235 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1236 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1237 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1238 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1239 requestId == $event.getRequestId() )
1240 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1241 onset.getRequestId() == $event.getRequestId() )
1242 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1243 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1244 $lock : TargetLock (requestId == $event.getRequestId())
1245 $response : SoResponseWrapper(requestId.toString() == $event.getRequestId().toString() )
1248 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1249 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1250 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1251 $params.getClosedLoopControlName(), drools.getRule().getName(),
1252 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1254 // Get the result of the operation
1256 PolicyResult policyResult = $operation.onResponse($response);
1257 if (policyResult != null) {
1258 logger.debug("{}: {}: operation finished - result={}",
1259 $params.getClosedLoopControlName(), drools.getRule().getName(),
1263 // This Operation has completed, construct a notification showing our results
1265 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1266 notification.setFrom("policy");
1267 notification.setPolicyName(drools.getRule().getName());
1268 notification.setPolicyScope("${policyScope}");
1269 notification.setPolicyVersion("${policyVersion}");
1270 notification.setMessage($operation.getOperationHistory());
1271 notification.setHistory($operation.getHistory());
1272 if (policyResult.equals(PolicyResult.SUCCESS)) {
1273 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1275 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1278 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1280 // Ensure the operation is complete
1282 if ($operation.isOperationComplete() == true) {
1284 // It is complete, remove it from memory
1286 retract($operation);
1288 // We must also retract the timer object
1289 // NOTE: We could write a Rule to do this
1293 // Complete the operation
1295 modify($manager) {finishOperation($operation)};
1298 // Just doing this will kick off the LOCKED rule again
1300 modify($operation) {};
1304 // Its not finished yet (i.e. expecting more Response objects)
1306 // Or possibly it is a leftover response that we timed the request out previously
1310 // We are going to retract these objects from memory
1318 * This rule responds to VFC Response Events
1321 rule "${policyName}.VFC.RESPONSE"
1323 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1324 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1325 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1326 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1327 requestId == $event.getRequestId() )
1328 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1329 onset.getRequestId() == $event.getRequestId() )
1330 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1331 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1332 $lock : TargetLock (requestId == $event.getRequestId())
1333 $response : VfcResponse( requestId.toString() == $event.getRequestId().toString() )
1335 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1336 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1337 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1338 $params.getClosedLoopControlName(), drools.getRule().getName(),
1339 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1341 // Get the result of the operation
1343 PolicyResult policyResult = $operation.onResponse($response);
1344 if (policyResult != null) {
1346 // This Operation has completed, construct a notification showing our results
1348 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1349 notification.setFrom("policy");
1350 notification.setPolicyName(drools.getRule().getName());
1351 notification.setPolicyScope("${policyScope}");
1352 notification.setPolicyVersion("${policyVersion}");
1353 notification.setMessage($operation.getOperationHistory());
1354 notification.setHistory($operation.getHistory());
1356 // Ensure the operation is complete
1358 if ($operation.isOperationComplete() == true) {
1360 // It is complete, remove it from memory
1362 retract($operation);
1364 // We must also retract the timer object
1365 // NOTE: We could write a Rule to do this
1369 // Complete the operation
1371 modify($manager) {finishOperation($operation)};
1374 // Just doing this will kick off the LOCKED rule again
1376 modify($operation) {};
1380 // Its not finished yet (i.e. expecting more Response objects)
1382 // Or possibly it is a leftover response that we timed the request out previously
1386 // We are going to retract these objects from memory
1394 * This rule responds to SDNC Response Events
1398 rule "${policyName}.SDNC.RESPONSE"
1400 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1401 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1402 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1403 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1404 requestId == $event.getRequestId() )
1405 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1406 onset.getRequestId() == $event.getRequestId() )
1407 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1408 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1409 $lock : TargetLock (requestId == $event.getRequestId())
1410 $response : SdncResponse( requestId.toString() == $event.getRequestId().toString() )
1412 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1413 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1414 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1415 $params.getClosedLoopControlName(), drools.getRule().getName(),
1416 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1418 // Get the result of the operation
1420 PolicyResult policyResult = $operation.onResponse($response);
1421 if (policyResult != null) {
1423 // This Operation has completed, construct a notification showing our results
1425 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1426 notification.setFrom("policy");
1427 notification.setPolicyName(drools.getRule().getName());
1428 notification.setPolicyScope("${policyScope}");
1429 notification.setPolicyVersion("${policyVersion}");
1430 notification.setMessage($operation.getOperationHistory());
1431 notification.setHistory($operation.getHistory());
1433 // Ensure the operation is complete
1435 if ($operation.isOperationComplete()) {
1437 // It is complete, remove it from memory
1439 retract($operation);
1441 // We must also retract the timer object
1442 // NOTE: We could write a Rule to do this
1446 // Complete the operation
1448 modify($manager) {finishOperation($operation)};
1451 // Just doing this will kick off the LOCKED rule again
1453 modify($operation) {};
1457 // Its not finished yet (i.e. expecting more Response objects)
1459 // Or possibly it is a leftover response that we timed the request out previously
1463 // We are going to retract these objects from memory
1471 * This rule responds to CDS Response Events
1473 rule "${policyName}.CDS.RESPONSE"
1475 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1476 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName(),
1477 closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1478 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1479 requestId == $event.getRequestId() )
1480 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1481 onset.getRequestId() == $event.getRequestId() )
1482 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1483 requestId == $event.getRequestId().toString(), timerType == "Operation", !expired )
1484 $lock : TargetLock (requestId == $event.getRequestId())
1485 $response : CdsResponse( requestId == $event.getRequestId().toString() )
1489 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1490 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1491 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1492 $params.getClosedLoopControlName(), drools.getRule().getName(),
1493 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1495 // Get the result of the operation
1496 PolicyResult policyResult = $operation.onResponse($response);
1498 if (policyResult != null) {
1499 logger.debug("{}: {}: operation finished - result={}",
1500 $params.getClosedLoopControlName(), drools.getRule().getName(),
1503 // The operation has completed, construct a notification showing our results
1504 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1505 notification.setFrom("policy");
1506 notification.setPolicyName(drools.getRule().getName());
1507 notification.setPolicyScope("${policyScope}");
1508 notification.setPolicyVersion("${policyVersion}");
1509 notification.setMessage($operation.getOperationHistory());
1510 notification.setHistory($operation.getHistory());
1511 notification.setNotification(
1512 ($response != null && CdsActorConstants.SUCCESS.equals($response.getStatus()))
1513 ? ControlLoopNotificationType.OPERATION_SUCCESS : ControlLoopNotificationType.OPERATION_FAILURE);
1515 // Send the notification
1516 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1518 // Ensure the operation is complete
1519 if ($operation.isOperationComplete()) {
1521 // It is complete, remove it from memory
1522 retract($operation);
1524 // We must also retract the timer object
1525 // NOTE: We could write a Rule to do this
1528 // Complete the operation
1529 modify($manager) {finishOperation($operation)};
1532 // Just doing this will kick off the LOCKED rule again
1533 modify($operation) {};
1536 // Its not finished yet (i.e. expecting more Response objects)
1537 // Or possibly it is a leftover response that we timed the request out previously
1539 "policyResult is null"
1540 + "\nIt's not finished yet (i.e. expecting more Response objects)"
1541 + "\nOr possibly it is a leftover response that we timed the request out previously");
1544 // We are going to retract these objects from memory
1551 * This manages a single timer.
1552 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1555 rule "${policyName}.TIMER.FIRED"
1556 timer (expr: $timeout)
1558 $timer : ControlLoopTimer($timeout : delay, !expired)
1560 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1561 logger.info("This is ${policyName}.TIMER.FIRED");
1562 modify($timer){setExpired(true)};
1567 * This is the timer that manages the timeout for an individual operation.
1570 rule "${policyName}.EVENT.MANAGER.OPERATION.TIMEOUT"
1572 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1573 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1574 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1575 requestId == $event.getRequestId() )
1576 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
1577 onset.getRequestId() == $event.getRequestId() )
1578 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1579 requestId == $event.getRequestId().toString(), expired, timerType == "Operation" )
1580 $lock : TargetLock (requestId == $event.getRequestId())
1583 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1584 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1585 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1586 $params.getClosedLoopControlName(), drools.getRule().getName(),
1587 $event, $manager, $operation, $lock, $operation, $opTimer);
1590 // Tell it its timed out
1592 $operation.setOperationHasTimedOut();
1594 // Create a notification for it ("DB Write - end operation")
1596 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1597 notification.setFrom("policy");
1598 notification.setPolicyName(drools.getRule().getName());
1599 notification.setPolicyScope("${policyScope}");
1600 notification.setPolicyVersion("${policyVersion}");
1601 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1602 notification.setMessage($operation.getOperationHistory());
1603 notification.setHistory($operation.getHistory());
1605 // Let interested parties know
1607 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1609 // Get rid of the timer
1613 // Ensure the operation is complete
1615 if ($operation.isOperationComplete() == true) {
1617 // It is complete, remove it from memory
1619 retract($operation);
1621 // Complete the operation
1623 modify($manager) {finishOperation($operation)};
1626 // Just doing this will kick off the LOCKED rule again
1628 modify($operation) {};
1634 * This is the timer that manages the overall control loop timeout.
1637 rule "${policyName}.EVENT.MANAGER.TIMEOUT"
1639 $params : Params( getClosedLoopControlName() == "${closedLoopControlName}" )
1640 $event : VirtualControlLoopEvent( closedLoopControlName == $params.getClosedLoopControlName() )
1641 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(),
1642 requestId == $event.getRequestId() )
1643 $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(),
1644 requestId == $event.getRequestId().toString(), expired, timerType == "ClosedLoop" )
1647 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1648 logger.info("{}: {}", $params.getClosedLoopControlName(), drools.getRule().getName());
1650 logger.debug("{}: {}: event={}",
1651 $params.getClosedLoopControlName(), drools.getRule().getName(),
1654 // Tell the Event Manager it has timed out
1656 VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1657 if (notification != null) {
1658 notification.setFrom("policy");
1659 notification.setPolicyName(drools.getRule().getName());
1660 notification.setPolicyScope("${policyScope}");
1661 notification.setPolicyVersion("${policyVersion}");
1663 // Let interested parties know
1665 PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
1668 // Retract the event
1675 * This rule cleans up the manager and other objects after an event has
1679 rule "${policyName}.EVENT.MANAGER.CLEANUP"
1681 $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestId() )
1682 $operations : LinkedList()
1683 from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName,
1684 onset.getRequestId() == $requestId ) )
1685 $timers : LinkedList()
1686 from collect( ControlLoopTimer( closedLoopControlName == $clName,
1687 requestId == $requestId.toString() ) )
1688 $locks : LinkedList()
1689 from collect( TargetLock (requestId == $requestId) )
1690 not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1693 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1694 logger.info("{}: {}", $clName, drools.getRule().getName());
1696 logger.debug("{}: {}: manager={} timers={} operations={}",
1697 $clName, drools.getRule().getName(),
1698 $manager, $timers.size(), $operations.size());
1701 // Retract EVERYTHING
1705 for(Object manager: $operations) {
1706 retract((ControlLoopOperationManager) manager);
1708 for(Object timer: $timers) {
1709 retract((ControlLoopTimer) timer);
1711 for(Object lock: $locks) {
1712 TargetLock tgt = (TargetLock) lock;
1714 // Ensure we release the lock
1716 PolicyGuard.unlockTarget(tgt);
1723 * This rule will clean up any rogue onsets where there is no
1724 * ControlLoopParams object corresponding to the onset event.
1727 rule "${policyName}.EVENT.CLEANUP"
1729 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1730 not ( Params( getClosedLoopControlName() == $clName) )
1733 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1734 logger.info("{}: {}", $clName, drools.getRule().getName());
1735 logger.debug("{}: {}: orphan onset event={}",
1736 $clName, drools.getRule().getName(), $event);
1742 * Creates a cleaner for every Params object.
1743 * This has a higher salience so that it is fired before PARAMS.FINISHED in ANY policy.
1745 rule "${policyName}.PARAMS.CLEANING"
1749 ParamsInitCleaner( )
1752 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1753 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1754 $params.getControlLoopYaml());
1756 ParamsCleaner cleaner = new ParamsCleaner();
1757 cleaner.setClosedLoopControlName($params.getClosedLoopControlName());
1758 cleaner.setControlLoopYaml($params.getControlLoopYaml());
1763 * Finished creating cleaner objects, so remove the trigger.
1764 * This has a higher salience so that it is fired before processing any events.
1766 rule "${policyName}.PARAMS.FINISHED"
1769 $initCleaner: ParamsInitCleaner( )
1772 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1773 logger.info("{}: {}", $initCleaner.getClosedLoopControlName(), drools.getRule().getName());
1775 retract($initCleaner);
1779 * Identifies Params objects that are still active, removing their associated cleaners.
1780 * This should only leave one active Params object for each policy.
1781 * This has a higher salience so that it is fired before PARAMS.DELETE in ANY policy.
1783 rule "${policyName}.PARAMS.ACTIVE"
1786 $params: Params( getClosedLoopControlName() == "${closedLoopControlName}",
1787 getControlLoopYaml() == "${controlLoopYaml}" )
1788 $cleaner: ParamsCleaner( getClosedLoopControlName() == "${closedLoopControlName}",
1789 getControlLoopYaml() == "${controlLoopYaml}" )
1792 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1793 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1794 $params.getControlLoopYaml());
1800 * Delete Params objects that are not active (i.e., those that still have an associated
1802 * This has a higher salience so that it is fired before PARAMS.CLEANED in ANY policy.
1804 rule "${policyName}.PARAMS.DELETE"
1808 $cleaner: ParamsCleaner( getClosedLoopControlName() == $params.getClosedLoopControlName(),
1809 getControlLoopYaml() == $params.getControlLoopYaml() )
1812 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1813 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), drools.getRule().getName(),
1814 $params.getControlLoopYaml());
1820 * Finished clean-up, so delete the cleaner objects.
1821 * This has a higher salience so that it is fired before processing any events.
1823 rule "${policyName}.PARAMS.CLEANED"
1826 $cleaner: ParamsCleaner( )
1829 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1830 logger.info("{}: {} : YAML=[{}]", $cleaner.getClosedLoopControlName(), drools.getRule().getName(),
1831 $cleaner.getControlLoopYaml());