f2fe23162cb586413544410dcf9666de7561fc32
[policy/drools-applications.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.controlloop;
22
23 import org.onap.policy.controlloop.params.ControlLoopParams;
24 import org.onap.policy.controlloop.VirtualControlLoopEvent;
25 import org.onap.policy.controlloop.VirtualControlLoopNotification;
26 import org.onap.policy.controlloop.ControlLoopEventStatus;
27 import org.onap.policy.controlloop.ControlLoopNotificationType;
28 import org.onap.policy.controlloop.ControlLoopLogger;
29 import org.onap.policy.controlloop.policy.PolicyResult;
30 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
31 import org.onap.policy.controlloop.policy.Policy;
32 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
33 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NEW_EVENT_STATUS;
34 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
35 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
36 import org.onap.policy.aai.AaiNqResponseWrapper;
37 import org.onap.policy.appc.Request;
38 import org.onap.policy.appc.Response;
39 import org.onap.policy.appc.CommonHeader;
40 import org.onap.policy.appclcm.LcmRequestWrapper;
41 import org.onap.policy.appclcm.LcmResponseWrapper;
42 import org.onap.policy.appclcm.LcmRequest;
43 import org.onap.policy.appclcm.LcmResponse;
44 import org.onap.policy.appclcm.LcmCommonHeader;
45 import org.onap.policy.sdnr.PciRequestWrapper;
46 import org.onap.policy.sdnr.PciResponseWrapper;
47 import org.onap.policy.sdnr.PciRequest;
48 import org.onap.policy.sdnr.PciResponse;
49 import org.onap.policy.vfc.VFCRequest;
50 import org.onap.policy.vfc.VFCResponse;
51 import org.onap.policy.vfc.VFCManager;
52 import org.onap.policy.so.SOManager;
53 import org.onap.policy.so.SORequest;
54 import org.onap.policy.so.SORequestStatus;
55 import org.onap.policy.so.SORequestDetails;
56 import org.onap.policy.so.SOModelInfo;
57 import org.onap.policy.so.SOCloudConfiguration;
58 import org.onap.policy.so.SORequestInfo;
59 import org.onap.policy.so.SORequestParameters;
60 import org.onap.policy.so.SORelatedInstanceListElement;
61 import org.onap.policy.so.SORelatedInstance;
62 import org.onap.policy.so.SOResponse;
63 import org.onap.policy.so.SOResponseWrapper;
64 import org.onap.policy.guard.PolicyGuard;
65 import org.onap.policy.guard.PolicyGuard.LockResult;
66 import org.onap.policy.guard.TargetLock;
67 import org.onap.policy.guard.GuardResult;
68 import org.onap.policy.guard.PolicyGuardRequest;
69 import org.onap.policy.guard.PolicyGuardResponse;
70 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
71 import org.onap.policy.guard.PolicyGuardXacmlHelper;
72
73 import org.yaml.snakeyaml.Yaml;
74 import org.yaml.snakeyaml.constructor.Constructor;
75
76 import org.slf4j.LoggerFactory;
77 import org.slf4j.Logger;
78
79 import java.time.Instant;
80 import java.util.LinkedList;
81 import java.util.Iterator;
82
83 import org.onap.policy.drools.system.PolicyEngine;
84
85 /*
86  * This object is to provide support for timeouts
87  * due to a bug in drools' built-in timers
88  */
89 declare ControlLoopTimer
90     closedLoopControlName : String
91     requestID : String
92     delay : String
93     expired : boolean
94     //timerType is the type of timer: either "ClosedLoop" or "Operation"
95     timerType : String
96 end
97
98 /*
99 *
100 * Called when the ControlLoopParams object has been inserted into working memory from the BRMSGW.
101 *
102 */
103 rule "INSERT.PARAMS"
104     when
105         $params : ControlLoopParams()
106     then
107
108     // Note: globals have bad behavior when persistence is used,
109     //       hence explicitly getting the logger vs using a global
110
111     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
112     logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), $params.getPolicyName() + "." 
113         + drools.getRule().getName(), $params.getControlLoopYaml());
114 end
115
116 /*
117 *
118 * This rule responds to DCAE Events where there is no manager yet. Either it is
119 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
120 *
121 */
122 rule "EVENT"
123     when
124         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
125         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
126         not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
127             requestID == $event.getRequestId() ) )
128     then
129
130     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
131     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
132
133     try {
134
135         //
136         // Check the event, because we need it to not be null when
137         // we create the ControlLoopEventManager. The ControlLoopEventManager
138         // will do extra syntax checking as well check if the closed loop is disabled.
139         //
140         if ($event.getRequestId() == null) {
141             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
142             notification.setNotification(ControlLoopNotificationType.REJECTED);
143             notification.setFrom("policy");
144             notification.setMessage("Missing requestID");
145             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
146             notification.setPolicyScope($params.getPolicyScope());
147             notification.setPolicyVersion($params.getPolicyVersion());
148
149             //
150             // Let interested parties know
151             //
152             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
153
154             //
155             // Retract it from memory
156             //
157             retract($event);
158         } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
159             throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
160         } else {
161             //
162             // Create an EventManager
163             //
164             ControlLoopEventManager manager = new ControlLoopEventManager($clName, $event.getRequestId());
165             //
166             // Determine if EventManager can actively process the event 
167             // (i.e. syntax, is_closed_loop_disabled checks etc.)
168             //
169             VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
170             notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
171             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
172             notification.setPolicyScope($params.getPolicyScope());
173             notification.setPolicyVersion($params.getPolicyVersion());
174             //
175             // Are we actively pursuing this event?
176             //
177             if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
178                 //
179                 // Insert Event Manager into memory, this will now kick off processing.
180                 //
181                 insert(manager);
182                 //
183                 // Let interested parties know
184                 //
185                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
186                 //
187                 // Setup the Overall Control Loop timer
188                 //
189                 ControlLoopTimer clTimer = new ControlLoopTimer();
190                 clTimer.setTimerType("ClosedLoop");
191                 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
192                 clTimer.setRequestID($event.getRequestId().toString());
193                 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
194                 //
195                 // Insert it
196                 //
197                 insert(clTimer);
198             } else {
199                 //
200                 // Let interested parties know
201                 //
202                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
203                 //
204                 // Retract it from memory
205                 //
206                 retract($event);
207             }
208
209             //
210             // Now that the manager is inserted into Drools working memory, we'll wait for
211             // another rule to fire in order to continue processing. This way we can also
212             // then screen for additional ONSET and ABATED events for this RequestID.
213             //
214         }
215     } catch (Exception e) {
216         logger.warn("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName(), e);
217
218         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
219         notification.setNotification(ControlLoopNotificationType.REJECTED);
220         notification.setMessage("Exception occurred: " + e.getMessage());
221         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
222         notification.setPolicyScope($params.getPolicyScope());
223         notification.setPolicyVersion($params.getPolicyVersion());
224         //
225         //
226         //
227         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
228         //
229         // Retract the event
230         //
231         retract($event);
232     }
233 end
234
235 /*
236 *
237 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
238 * is now created. We can start processing the yaml specification via the Event Manager.
239 *
240 */
241 rule "EVENT.MANAGER"
242     when
243         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
244         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
245         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
246             requestID == $event.getRequestId() )
247         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
248             requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", !expired )
249     then
250
251     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
252     logger.info("{}: {}: event={} manager={} clTimer={}",
253                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
254                 $event, $manager, $clTimer);
255
256     try {
257         //
258         // Check which event this is.
259         //
260         ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
261         //
262         // Check what kind of event this is
263         //
264         if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
265             //
266             // We don't care about subsequent onsets
267             //
268             logger.info("{}: {}: subsequent onset",
269                         $clName, $params.getPolicyName() + "." + drools.getRule().getName());
270             retract($event);
271             return;
272         }
273         if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
274             //
275             // Ignore any bad syntax events
276             //
277             logger.warn("{}: {}: syntax error",
278                         $clName, $params.getPolicyName() + "." + drools.getRule().getName());
279             retract($event);
280             return;
281         }
282         //
283         // We only want the initial ONSET event in memory,
284         // all the other events need to be retracted to support
285         // cleanup and avoid the other rules being fired for this event.
286         //
287         if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
288             logger.warn("{}: {}: no first onset",
289                         $clName, $params.getPolicyName() + "." + drools.getRule().getName());
290             retract($event);
291         }
292
293         logger.debug("{}: {}: target={}", $clName,
294                      $params.getPolicyName() + "." + drools.getRule().getName(), $event.getTarget());
295         //
296         // Now start seeing if we need to process this event
297         //
298
299         //
300         // Check if this is a Final Event
301         //
302         VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
303
304
305         if (notification != null) {
306             //
307             // Its final, but are we waiting for abatement?
308             //
309             if ($manager.getNumAbatements() > 0) {
310                 logger.info("{}: {}: abatement received for {}.  Closing the control loop",
311                             $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
312                             $event.getRequestId());
313                 notification.setFrom("policy");
314                 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
315                 notification.setPolicyScope($params.getPolicyScope());
316                 notification.setPolicyVersion($params.getPolicyVersion());
317                 //
318                 // In this case, we are done
319                 //
320                 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
321                 //
322                 // Unlock the target
323                 //
324                 TargetLock lock = $manager.unlockCurrentOperation();
325                 if (lock != null) {
326                     logger.debug("{}: {}: retracting lock=", $clName,
327                                  $params.getPolicyName() + "." + drools.getRule().getName(), lock);
328                     retract(lock);
329                 }
330                 //
331                 // Retract everything from memory
332                 //
333                 logger.info("{}: {}: retracting onset, manager, and timer",
334                             $clName, $params.getPolicyName() + "." + drools.getRule().getName());
335
336                 retract($manager.getOnsetEvent());
337                 retract($manager);
338                 retract($clTimer);
339                 //
340                 // TODO - what if we get subsequent Events for this RequestID?
341                 // By default, it will all start over again. May be confusing for Ruby.
342                 // Or, we could track this and then subsequently ignore the events
343                 //
344             } else {
345                 //
346                 // Check whether we need to wait for abatement
347                 //
348                 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
349                   logger.info("{}: {}: waiting for abatement ..",
350                               $clName, $params.getPolicyName() + "." + drools.getRule().getName());
351                 } else {
352                   logger.info("{}: {}: no abatement expect for {}.  Closing the control loop",
353                               $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
354                               $event.getRequestId());
355
356                   notification.setFrom("policy");
357                   notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
358                   notification.setPolicyScope($params.getPolicyScope());
359                   notification.setPolicyVersion($params.getPolicyVersion());
360
361                   //
362                   // In this case, we are done
363                   //
364                   PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
365                   //
366                   // Unlock the target
367                   //
368                   TargetLock lock = $manager.unlockCurrentOperation();
369                   if (lock != null) {
370                       logger.debug("{}: {}: retracting lock=", $clName,
371                                   $params.getPolicyName() + "." + drools.getRule().getName(), lock);
372                       retract(lock);
373                   }
374                   //
375                   // Retract everything from memory
376                   //
377                   logger.info("{}: {}: retracting onset, manager, and timer",
378                               $clName, $params.getPolicyName() + "." + drools.getRule().getName());
379
380                   retract($manager.getOnsetEvent());
381                   retract($manager);
382                   retract($clTimer);
383                 }
384             }
385         } else {
386             //
387             // NOT final, so let's ask for the next operation
388             //
389             ControlLoopOperationManager operation = $manager.processControlLoop();
390             if (operation != null) {
391               //
392               // Let's ask for a lock right away
393               //
394               LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
395               logger.info("{}: {}: guard lock acquired={}",
396                             $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
397                             result.getB());
398               if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
399                   //
400                   // insert the operation into memory
401                   //
402                   insert(operation);
403
404                   //
405                   // insert operation timeout object
406                   //
407                   ControlLoopTimer opTimer = new ControlLoopTimer();
408                   opTimer.setTimerType("Operation");
409                   opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
410                   opTimer.setRequestID($event.getRequestId().toString());
411                   opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
412                   insert(opTimer);
413
414                   //
415                   // Insert lock into memory
416                   //
417                   insert(result.getB());
418               }
419               else {
420                   logger.debug("The target resource {} is already processing",
421                                 $event.getAai().get($event.getTarget()));
422                   notification = new VirtualControlLoopNotification($event);
423                   notification.setNotification(ControlLoopNotificationType.REJECTED);
424                   notification.setMessage("The target " + $event.getAai().get($event.getTarget()) 
425                       + " is already locked");
426                   notification.setFrom("policy");
427                   notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
428                   notification.setPolicyScope($params.getPolicyScope());
429                   notification.setPolicyVersion($params.getPolicyVersion());
430
431                   PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
432
433                   retract($event);
434                   retract($manager);
435                   retract($clTimer);
436
437                 if(result.getB() != null) {
438                   retract(result.getB());
439                 }
440               }
441               logger.info("{}: {}: starting operation={}",
442                           $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
443                           operation);
444             } else {
445               //
446               // Probably waiting for abatement
447               //
448               logger.info("{}: {}: no operation, probably waiting for abatement",
449                           $clName, $params.getPolicyName() + "." + drools.getRule().getName());
450             }
451         }
452     } catch (Exception e) {
453         logger.warn("{}: {}: unexpected",
454                    $clName,
455                    $params.getPolicyName() + "." + drools.getRule().getName(), e);
456
457         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
458         notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
459         notification.setMessage(e.getMessage());
460         notification.setFrom("policy");
461         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
462         notification.setPolicyScope($params.getPolicyScope());
463         notification.setPolicyVersion($params.getPolicyVersion());
464
465         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
466
467         retract($event);
468         retract($manager);
469         retract($clTimer);
470     }
471
472 end
473
474 /*
475 *
476 * Guard Permitted, let's send request to the actor.
477 *
478 */
479 rule "EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
480     when
481         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
482         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
483         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
484             requestID == $event.getRequestId() )
485         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(),
486             onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
487         $lock : TargetLock (requestID == $event.getRequestId())
488         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
489             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
490     then
491
492     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
493     logger.info("{}: {}: event={} manager={} operation={} lock={}",
494                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
495                 $event, $manager, $operation, $lock);
496
497     Object request = null;
498     boolean caughtException = false;
499
500     try {
501         request = $operation.startOperation($event);
502
503         if (request != null) {
504           logger.debug("{}: {}: starting operation ..",
505                        $clName,
506                        $params.getPolicyName() + "." + drools.getRule().getName());
507           //
508           // Tell interested parties we are performing this Operation
509           //
510           VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
511           notification.setNotification(ControlLoopNotificationType.OPERATION);
512           notification.setMessage($operation.getOperationMessage());
513           notification.setHistory($operation.getHistory());
514           notification.setFrom("policy");
515           notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
516           notification.setPolicyScope($params.getPolicyScope());
517           notification.setPolicyVersion($params.getPolicyVersion());
518
519           PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
520
521           switch ($operation.policy.getActor()){
522
523               case "APPC":
524
525                   if (request instanceof Request) {
526                       PolicyEngine.manager.deliver("APPC-CL", request);
527                   }
528                   else if (request instanceof LcmRequestWrapper) {
529                       PolicyEngine.manager.deliver("APPC-LCM-READ", request);
530                   }
531                   break;
532               case "SO":
533                   // at this point the AAI named query request should have already been made, the response 
534                   // recieved and used in the construction of the SO Request which is stored in operationRequest
535
536                   if(request instanceof SORequest) {
537                       // Call SO. The response will be inserted into memory once it's received
538                       SoActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(), request);
539                   }
540                   break;
541               case "VFC":
542                   if (request instanceof VFCRequest) {
543                       // Start VFC thread
544                       Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
545                       t.start();
546                   }
547                   break;
548               case "SDNR":
549                   if (request instanceof PciRequestWrapper) {
550                       PolicyEngine.manager.deliver("SDNR-CL", request);
551                   }
552                   break;
553           }
554         } else {
555           //
556           // What happens if its null?
557           //
558             logger.warn("{}: {}: unexpected null operation request",
559                       $clName,
560                       $params.getPolicyName() + "." + drools.getRule().getName());
561             if ("SO".equals($operation.policy.getActor())) {
562                 retract($opTimer);
563                 retract($operation);
564                 modify($manager) {finishOperation($operation)};
565             }
566             else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
567                 retract($opTimer);
568                 retract($operation);
569                 modify($manager) {finishOperation($operation)};
570             }
571         }
572
573     } catch (Exception e) {
574         String msg = e.getMessage();
575         logger.warn("{}: {}: operation={}:  AAI failure: {}",
576                     $clName,
577                     $params.getPolicyName() + "." + drools.getRule().getName(),
578                     $operation, msg, e);
579         $operation.setOperationHasException(msg);
580
581         if(request != null) {
582             //
583             // Create a notification for it ("DB Write - end operation")
584             //
585             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
586             notification.setFrom("policy");
587             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
588             notification.setPolicyScope($params.getPolicyScope());
589             notification.setPolicyVersion($params.getPolicyVersion());
590             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
591             notification.setMessage($operation.getOperationHistory());
592             notification.setHistory($operation.getHistory());
593
594             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
595         }
596
597         retract($opTimer);
598         retract($operation);
599         caughtException = true;
600     }
601
602     // Having the modify statement in the catch clause doesn't work for whatever reason
603     if (caughtException) {
604         modify($manager) {finishOperation($operation)};
605     }
606 end
607
608
609 /*
610 *
611 * We were able to acquire a lock so now let's ask Xacml Guard whether
612 * we are allowed to proceed with the request to the actor.
613 *
614 */
615 rule "EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
616     when
617         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
618         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
619         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
620             requestID == $event.getRequestId() )
621         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
622             onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
623         $lock : TargetLock (requestID == $event.getRequestId())
624     then
625
626     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
627     logger.info("{}: {}: event={} manager={} operation={} lock={}",
628                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
629                 $event, $manager, $operation, $lock);
630
631     //
632     // Sending notification that we are about to query Guard ("DB write - start operation")
633     //
634     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
635     notification.setNotification(ControlLoopNotificationType.OPERATION);
636     notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " 
637         + $operation.policy.getRecipe());
638     notification.setHistory($operation.getHistory());
639     notification.setFrom("policy");
640     notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
641     notification.setPolicyScope($params.getPolicyScope());
642     notification.setPolicyVersion($params.getPolicyVersion());
643
644     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
645
646     //
647     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
648     // just change guardEnabled to false.
649     //
650     // In order to use REST XACML, provide a URL instead of "" as a second argument
651     // to the CallGuardTask() and set the first argument to null
652     // (instead of XacmlPdpEngine).
653     //
654
655     // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
656     boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
657
658     if(guardEnabled){
659
660         Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
661                                                         drools.getWorkingMemory(),
662                                                         $event.getClosedLoopControlName(),
663                                                         $operation.policy.getActor().toString(),
664                                                         $operation.policy.getRecipe(),
665                                                         $operation.getTargetEntity(),
666                                                         $event.getRequestId().toString(),
667                                                         () -> {
668                                                             AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
669                                                             return(resp == null ? null : resp.countVfModules());
670                                                         }));
671         t.start();
672     }
673     else{
674         insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
675     }
676
677 end
678
679 //
680 // This rule will be triggered when a thread talking to the XACML Guard inserts a
681 // guardResponse object into the working memory
682 //
683 rule "GUARD.RESPONSE"
684     when
685         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
686         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
687             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
688         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
689             requestID == $event.getRequestId() )
690         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
691             onset.getRequestId() == $event.getRequestId() )
692         $lock : TargetLock (requestID == $event.getRequestId())
693         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
694             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
695         $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
696     then
697
698     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
699     logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
700                  $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
701                  $event, $manager, $operation, $lock, $opTimer, $guardResponse);
702
703
704     //we will permit the operation if there was no Guard for it
705     if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
706         $guardResponse.setResult("Permit");
707     }
708
709     //
710     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
711     //
712     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
713     notification.setNotification(ControlLoopNotificationType.OPERATION);
714     notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe()
715         + " is " + $guardResponse.getResult());
716     notification.setHistory($operation.getHistory());
717     notification.setFrom("policy");
718     notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
719     notification.setPolicyScope($params.getPolicyScope());
720     notification.setPolicyVersion($params.getPolicyVersion());
721
722     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
723
724     if("Permit".equalsIgnoreCase($guardResponse.getResult())){
725
726         modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
727     }
728     else {
729         //This is the Deny case
730         $operation.startOperation($event);
731         $operation.setOperationHasGuardDeny();
732         retract($opTimer);
733         retract($operation);
734         modify($manager) {finishOperation($operation)};
735     }
736
737     retract($guardResponse);
738
739 end
740
741 /*
742 *
743 * This rule responds to APPC Response Events
744 *
745 * I would have like to be consistent and write the Response like this:
746 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
747 *
748 * However, no compile error was given. But a runtime error was given. I think
749 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
750 *
751 */
752 rule "APPC.RESPONSE"
753     when
754         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
755         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
756             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
757         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
758             requestID == $event.getRequestId() )
759         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
760             onset.getRequestId() == $event.getRequestId() )
761         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
762             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
763         $lock : TargetLock (requestID == $event.getRequestId())
764         $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
765     then
766
767     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
768     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
769     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
770                  $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
771                  $event, $manager, $operation, $lock, $opTimer, $response);
772     //
773     // Get the result of the operation
774     //
775     PolicyResult policyResult = $operation.onResponse($response);
776     if (policyResult != null) {
777         logger.debug("{}: {}: operation finished - result={}",
778                     $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
779                     policyResult);
780         //
781         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
782         //
783         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
784         notification.setFrom("policy");
785         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
786         notification.setPolicyScope($params.getPolicyScope());
787         notification.setPolicyVersion($params.getPolicyVersion());
788         notification.setMessage($operation.getOperationHistory());
789         notification.setHistory($operation.getHistory());
790         if (policyResult.equals(PolicyResult.SUCCESS)) {
791             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
792             //
793             // Let interested parties know
794             //
795             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
796         } else {
797             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
798             //
799             // Let interested parties know
800             //
801             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
802         }
803         //
804         // Ensure the operation is complete
805         //
806         if ($operation.isOperationComplete() == true) {
807             //
808             // It is complete, remove it from memory
809             //
810             retract($operation);
811             //
812             // We must also retract the timer object
813             // NOTE: We could write a Rule to do this
814             //
815             retract($opTimer);
816             //
817             // Complete the operation
818             //
819             modify($manager) {finishOperation($operation)};
820         } else {
821             //
822             // Just doing this will kick off the LOCKED rule again
823             //
824             modify($operation) {};
825         }
826     } else {
827         //
828         // Its not finished yet (i.e. expecting more Response objects)
829         //
830         // Or possibly it is a leftover response that we timed the request out previously
831         //
832     }
833     //
834     // We are going to retract these objects from memory
835     //
836     retract($response);
837 end
838
839 /*
840 *
841 * The problem with Responses is that they don't have a controlLoopControlName
842 * field in them, so the only way to attach them is via RequestID. If we have multiple
843 * control loop .drl's loaded in the same container, we need to be sure the cleanup
844 * rules don't remove Responses for other control loops.
845 *
846 */
847 rule "APPC.RESPONSE.CLEANUP"
848     when
849         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
850         $response : Response($id : getCommonHeader().RequestId )
851         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
852     then
853
854     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
855     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
856     logger.debug("{}: {}: orphan appc response={}",
857                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
858
859     //
860     // Retract it
861     //
862     retract($response);
863 end
864
865 /*
866 *
867 * This rule responds to APPC Response Events using the new LCM interface provided by appc
868 *
869 */
870 rule "APPC.LCM.RESPONSE"
871     when
872         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
873         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
874             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
875         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
876             requestID == $event.getRequestId() )
877         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
878             onset.getRequestId() == $event.getRequestId() )
879         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
880             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
881         $lock : TargetLock (requestID == $event.getRequestId())
882         $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
883     then
884
885     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
886     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
887     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
888                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
889                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
890
891     //
892     // Get the result of the operation
893     //
894     PolicyResult policyResult = $operation.onResponse($response);
895     if (policyResult != null) {
896       logger.debug("{}: {}: operation finished - result={}",
897                   $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
898                   policyResult);
899
900       //
901       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
902       //
903       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
904       notification.setFrom("policy");
905       notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
906       notification.setPolicyScope($params.getPolicyScope());
907       notification.setPolicyVersion($params.getPolicyVersion());
908       notification.setMessage($operation.getOperationHistory());
909       notification.setHistory($operation.getHistory());
910       if (policyResult.equals(PolicyResult.SUCCESS)) {
911           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
912       } else {
913           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
914       }
915       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
916       //
917       // Ensure the operation is complete
918       //
919       if ($operation.isOperationComplete() == true) {
920           //
921           // It is complete, remove it from memory
922           //
923           retract($operation);
924           //
925           // We must also retract the timer object
926           // NOTE: We could write a Rule to do this
927           //
928           retract($opTimer);
929           //
930           // Complete the operation
931           //
932           modify($manager) {finishOperation($operation)};
933       } else {
934           //
935           // Just doing this will kick off the LOCKED rule again
936           //
937           modify($operation) {};
938       }
939     } else {
940         //
941         // Its not finished yet (i.e. expecting more Response objects)
942         //
943         // Or possibly it is a leftover response that we timed the request out previously
944         //
945     }
946     //
947     // We are going to retract these objects from memory
948     //
949     retract($response);
950 end
951
952 /*
953 *
954 * Clean Up any lingering LCM reponses
955 *
956 */
957 rule "APPC.LCM.RESPONSE.CLEANUP"
958     when
959         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
960         $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
961         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
962     then
963
964     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
965     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
966     logger.debug("{}: {}: orphan appc response={}",
967                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
968     //
969     // Retract it
970     //
971     retract($response);
972 end
973
974 /*
975 *
976 * This rule responds to SO Response Events
977 *
978 */
979 rule "SO.RESPONSE"
980     when
981         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
982         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
983             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
984         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
985             requestID == $event.getRequestId() )
986         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
987             onset.getRequestId() == $event.getRequestId() )
988         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
989             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
990         $lock : TargetLock (requestID == $event.getRequestId())
991         $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
992     then
993
994     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
995     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
996     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
997                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
998                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
999
1000     // Get the result of the operation
1001     //
1002     PolicyResult policyResult = $operation.onResponse($response);
1003     if (policyResult != null) {
1004         logger.debug("{}: {}: operation finished - result={}",
1005                     $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1006                     policyResult);
1007
1008         //
1009         // This Operation has completed, construct a notification showing our results
1010         //
1011         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1012         notification.setFrom("policy");
1013         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1014         notification.setPolicyScope($params.getPolicyScope());
1015         notification.setPolicyVersion($params.getPolicyVersion());
1016         notification.setMessage($operation.getOperationHistory());
1017         notification.setHistory($operation.getHistory());
1018         if (policyResult.equals(PolicyResult.SUCCESS)) {
1019             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1020         } else {
1021             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1022
1023         }
1024         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1025         //
1026         // Ensure the operation is complete
1027         //
1028         if ($operation.isOperationComplete() == true) {
1029             //
1030             // It is complete, remove it from memory
1031             //
1032             retract($operation);
1033             //
1034             // We must also retract the timer object
1035             // NOTE: We could write a Rule to do this
1036             //
1037             retract($opTimer);
1038             //
1039             // Complete the operation
1040             //
1041             modify($manager) {finishOperation($operation)};
1042         } else {
1043             //
1044             // Just doing this will kick off the LOCKED rule again
1045             //
1046             modify($operation) {};
1047         }
1048     } else {
1049         //
1050         // Its not finished yet (i.e. expecting more Response objects)
1051         //
1052         // Or possibly it is a leftover response that we timed the request out previously
1053         //
1054     }
1055     //
1056     // We are going to retract these objects from memory
1057     //
1058     retract($response);
1059
1060 end
1061
1062 /*
1063 *
1064 * This rule responds to VFC Response Events
1065 *
1066 */
1067 rule "VFC.RESPONSE"
1068     when
1069         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1070         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
1071             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1072         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1073             requestID == $event.getRequestId() )
1074         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1075             onset.getRequestId() == $event.getRequestId() )
1076         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1077             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1078         $lock : TargetLock (requestID == $event.getRequestId())
1079         $response : VFCResponse( requestId.toString() == $event.getRequestId().toString() )
1080     then
1081         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1082         logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1083         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1084                     $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1085                     $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1086
1087         // Get the result of the operation
1088         //
1089         PolicyResult policyResult = $operation.onResponse($response);
1090         if (policyResult != null) {
1091             //
1092             // This Operation has completed, construct a notification showing our results
1093             //
1094             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1095             notification.setFrom("policy");
1096             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1097             notification.setPolicyScope($params.getPolicyScope());
1098             notification.setPolicyVersion($params.getPolicyVersion());
1099             notification.setMessage($operation.getOperationHistory());
1100             notification.setHistory($operation.getHistory());
1101             //
1102             // Ensure the operation is complete
1103             //
1104             if ($operation.isOperationComplete() == true) {
1105                 //
1106                 // It is complete, remove it from memory
1107                 //
1108                 retract($operation);
1109                 //
1110                 // We must also retract the timer object
1111                 // NOTE: We could write a Rule to do this
1112                 //
1113                 retract($opTimer);
1114                 //
1115                 // Complete the operation
1116                 //
1117                 modify($manager) {finishOperation($operation)};
1118             } else {
1119                 //
1120                 // Just doing this will kick off the LOCKED rule again
1121                 //
1122                 modify($operation) {};
1123             }
1124         } else {
1125             //
1126             // Its not finished yet (i.e. expecting more Response objects)
1127             //
1128             // Or possibly it is a leftover response that we timed the request out previously
1129             //
1130         }
1131         //
1132         // We are going to retract these objects from memory
1133         //
1134         retract($response);
1135
1136 end
1137
1138 /*
1139 *
1140 * This manages a single timer.
1141 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1142 *
1143 */
1144 rule "TIMER.FIRED"
1145     timer (expr: $timeout)
1146     when
1147         $timer : ControlLoopTimer($timeout : delay, !expired)
1148     then
1149         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1150         logger.info("This is TIMER.FIRED");
1151         modify($timer){setExpired(true)};
1152     end
1153
1154 /*
1155 *
1156 * This is the timer that manages the timeout for an individual operation.
1157 *
1158 */
1159 rule "EVENT.MANAGER.OPERATION.TIMEOUT"
1160     when
1161         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1162         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
1163         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1164             requestID == $event.getRequestId() )
1165         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1166             onset.getRequestId() == $event.getRequestId() )
1167         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1168             requestID == $event.getRequestId().toString(), timerType == "Operation", expired )
1169         $lock : TargetLock (requestID == $event.getRequestId())
1170     then
1171
1172     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1173     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1174     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1175                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1176                 $event, $manager, $operation, $lock, $operation, $opTimer);
1177
1178     //
1179     // Tell it its timed out
1180     //
1181     $operation.setOperationHasTimedOut();
1182     //
1183     // Create a notification for it ("DB Write - end operation")
1184     //
1185     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1186     notification.setFrom("policy");
1187     notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1188     notification.setPolicyScope($params.getPolicyScope());
1189     notification.setPolicyVersion($params.getPolicyVersion());
1190     notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1191     notification.setMessage($operation.getOperationHistory());
1192     notification.setHistory($operation.getHistory());
1193     //
1194     // Let interested parties know
1195     //
1196     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1197     //
1198     // Get rid of the timer
1199     //
1200     retract($opTimer);
1201     //
1202     // Ensure the operation is complete
1203     //
1204     if ($operation.isOperationComplete() == true) {
1205         //
1206         // It is complete, remove it from memory
1207         //
1208         retract($operation);
1209         //
1210         // Complete the operation
1211         //
1212         modify($manager) {finishOperation($operation)};
1213     } else {
1214         //
1215         // Just doing this will kick off the LOCKED rule again
1216         //
1217         modify($operation) {};
1218     }
1219 end
1220
1221 /*
1222 *
1223 * This is the timer that manages the overall control loop timeout.
1224 *
1225 */
1226 rule "EVENT.MANAGER.TIMEOUT"
1227     when
1228         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1229         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
1230         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1231             requestID == $event.getRequestId() )
1232         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1233             requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", expired )
1234     then
1235
1236     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1237     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1238
1239     logger.debug("{}: {}: event={}",
1240               $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1241               $event);
1242     //
1243     // Tell the Event Manager it has timed out
1244     //
1245     VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1246     if (notification != null) {
1247         notification.setFrom("policy");
1248         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1249         notification.setPolicyScope($params.getPolicyScope());
1250         notification.setPolicyVersion($params.getPolicyVersion());
1251         //
1252         // Let interested parties know
1253         //
1254         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1255     }
1256     //
1257     // Retract the event
1258     //
1259     retract($event);
1260 end
1261
1262 /*
1263 *
1264 * This rule cleans up the manager and other objects after an event has
1265 * been retracted.
1266 *
1267 */
1268 rule "EVENT.MANAGER.CLEANUP"
1269     when
1270         $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1271         $operations : LinkedList()
1272                         from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, 
1273                             onset.getRequestId() == $requestId ) )
1274         $timers : LinkedList()
1275                         from collect( ControlLoopTimer( closedLoopControlName == $clName, 
1276                             requestID == $requestId.toString() ) )
1277         $locks : LinkedList()
1278                         from collect( TargetLock (requestID == $requestId) )
1279         not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1280     then
1281
1282     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1283     logger.info("{}: {}", $clName, drools.getRule().getName());
1284
1285     logger.debug("{}: {}: manager={} timers={} operations={}",
1286               $clName, drools.getRule().getName(),
1287               $manager, $timers.size(), $operations.size());
1288
1289     //
1290     // Retract EVERYTHING
1291     //
1292     retract($manager);
1293
1294     for(Object manager: $operations) {
1295         retract((ControlLoopOperationManager) manager);
1296     }
1297     for(Object timer: $timers) {
1298         retract((ControlLoopTimer) timer);
1299     }
1300     for(Object lock: $locks) {
1301         TargetLock tgt = (TargetLock) lock;
1302         //
1303         // Ensure we release the lock
1304         //
1305         PolicyGuard.unlockTarget(tgt);
1306         retract(tgt);
1307     }
1308 end
1309
1310 /*
1311 *
1312 * This rule will clean up any rogue onsets where there is no
1313 * ControlLoopParams object corresponding to the onset event.
1314 *
1315 */
1316 rule "EVENT.CLEANUP"
1317     when
1318         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1319         not ( ControlLoopParams( getClosedLoopControlName() == $clName) )
1320     then
1321
1322     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1323     logger.info("{}: {}", $clName, drools.getRule().getName());
1324     logger.debug("{}: {}: orphan onset event={}",
1325                 $clName, drools.getRule().getName(), $event);
1326
1327     retract($event);
1328 end
1329
1330 /*
1331 *
1332 * This rule responds to SDNR Response Events.
1333 *
1334 */
1335 rule "SDNR.RESPONSE"
1336     when
1337         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1338         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
1339             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1340         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1341             requestID == $event.getRequestId() )
1342         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1343             onset.getRequestId() == $event.getRequestId() )
1344         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1345             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1346         $lock : TargetLock (requestID == $event.getRequestId())
1347         $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1348     then
1349
1350     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1351     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1352     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1353                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1354                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1355
1356     //
1357     // Get the result of the operation
1358     //
1359     PolicyResult policyResult = $operation.onResponse($response);
1360     if (policyResult != null) {
1361       logger.debug("{}: {}: operation finished - result={}",
1362                   $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1363                   policyResult);
1364
1365       //
1366       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1367       //
1368       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1369       notification.setFrom("policy");
1370       notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1371       notification.setPolicyScope($params.getPolicyScope());
1372       notification.setPolicyVersion($params.getPolicyVersion());
1373       notification.setMessage($operation.getOperationHistory());
1374       notification.setHistory($operation.getHistory());
1375       if (policyResult.equals(PolicyResult.SUCCESS)) {
1376           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1377       } else {
1378           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1379       }
1380       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1381       //
1382       // Ensure the operation is complete
1383       //
1384       if ($operation.isOperationComplete() == true) {
1385           //
1386           // It is complete, remove it from memory
1387           //
1388           retract($operation);
1389           //
1390           // We must also retract the timer object
1391           // NOTE: We could write a Rule to do this
1392           //
1393           retract($opTimer);
1394           //
1395           // Complete the operation
1396           //
1397           modify($manager) {finishOperation($operation)};
1398       } else {
1399           //
1400           // Just doing this will kick off the LOCKED rule again
1401           //
1402           modify($operation) {};
1403       }
1404     } else {
1405         //
1406         // Its not finished yet (i.e. expecting more Response objects)
1407         //
1408         // Or possibly it is a leftover response that we timed the request out previously
1409         //
1410     }
1411     //
1412     // We are going to retract these objects from memory
1413     //
1414     retract($response);
1415 end
1416
1417 /*
1418 *
1419 * Clean Up any lingering SDNR reponses.
1420 *
1421 */
1422 rule "SDNR.RESPONSE.CLEANUP"
1423     when
1424         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1425         $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1426         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1427     then
1428
1429     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1430     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1431     logger.debug("{}: {}: orphan sdnr response={}",
1432                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
1433     //
1434     // Retract it
1435     //
1436     retract($response);
1437 end