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