f2aa7ef16f17350fd1ae5e807a3a1ab37f60d90c
[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             else if ("sdnc".equalsIgnoreCase($operation.policy.getActor())) {
583                 retract($opTimer);
584                 retract($operation);
585                 modify($manager) {finishOperation($operation)};
586             }
587         }
588
589     } catch (Exception e) {
590         String msg = e.getMessage();
591         logger.warn("{}: {}: operation={}:  AAI failure: {}",
592                     $clName,
593                     $params.getPolicyName() + "." + drools.getRule().getName(),
594                     $operation, msg, e);
595         $operation.setOperationHasException(msg);
596
597         if(request != null) {
598             //
599             // Create a notification for it ("DB Write - end operation")
600             //
601             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
602             notification.setFrom("policy");
603             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
604             notification.setPolicyScope($params.getPolicyScope());
605             notification.setPolicyVersion($params.getPolicyVersion());
606             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
607             notification.setMessage($operation.getOperationHistory());
608             notification.setHistory($operation.getHistory());
609
610             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
611         }
612
613         retract($opTimer);
614         retract($operation);
615         caughtException = true;
616     }
617
618     // Having the modify statement in the catch clause doesn't work for whatever reason
619     if (caughtException) {
620         modify($manager) {finishOperation($operation)};
621     }
622 end
623
624
625 /*
626 *
627 * We were able to acquire a lock so now let's ask Xacml Guard whether
628 * we are allowed to proceed with the request to the actor.
629 *
630 */
631 rule "EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
632     when
633         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
634         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
635         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
636             requestID == $event.getRequestId() )
637         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
638             onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
639         $lock : TargetLock (requestID == $event.getRequestId())
640     then
641
642     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
643     logger.info("{}: {}: event={} manager={} operation={} lock={}",
644                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
645                 $event, $manager, $operation, $lock);
646
647     //
648     // Sending notification that we are about to query Guard ("DB write - start operation")
649     //
650     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
651     notification.setNotification(ControlLoopNotificationType.OPERATION);
652     notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " 
653         + $operation.policy.getRecipe());
654     notification.setHistory($operation.getHistory());
655     notification.setFrom("policy");
656     notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
657     notification.setPolicyScope($params.getPolicyScope());
658     notification.setPolicyVersion($params.getPolicyVersion());
659
660     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
661
662     //
663     // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
664     // just change guardEnabled to false.
665     //
666     // In order to use REST XACML, provide a URL instead of "" as a second argument
667     // to the CallGuardTask() and set the first argument to null
668     // (instead of XacmlPdpEngine).
669     //
670
671     // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
672     boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
673
674     if(guardEnabled){
675
676         Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
677                                                         drools.getWorkingMemory(),
678                                                         $event.getClosedLoopControlName(),
679                                                         $operation.policy.getActor().toString(),
680                                                         $operation.policy.getRecipe(),
681                                                         $operation.getTargetEntity(),
682                                                         $event.getRequestId().toString(),
683                                                         () -> {
684                                                             AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
685                                                             return(resp == null ? null : resp.countVfModules());
686                                                         }));
687         t.start();
688     }
689     else{
690         insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
691     }
692
693 end
694
695 //
696 // This rule will be triggered when a thread talking to the XACML Guard inserts a
697 // guardResponse object into the working memory
698 //
699 rule "GUARD.RESPONSE"
700     when
701         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
702         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
703             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
704         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
705             requestID == $event.getRequestId() )
706         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
707             onset.getRequestId() == $event.getRequestId() )
708         $lock : TargetLock (requestID == $event.getRequestId())
709         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
710             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
711         $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
712     then
713
714     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
715     logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
716                  $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
717                  $event, $manager, $operation, $lock, $opTimer, $guardResponse);
718
719
720     //we will permit the operation if there was no Guard for it
721     if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
722         $guardResponse.setResult("Permit");
723     }
724
725     //
726     // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
727     //
728     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
729     notification.setNotification(ControlLoopNotificationType.OPERATION);
730     notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe()
731         + " is " + $guardResponse.getResult());
732     notification.setHistory($operation.getHistory());
733     notification.setFrom("policy");
734     notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
735     notification.setPolicyScope($params.getPolicyScope());
736     notification.setPolicyVersion($params.getPolicyVersion());
737
738     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
739
740     if("Permit".equalsIgnoreCase($guardResponse.getResult())){
741
742         modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
743     }
744     else {
745         //This is the Deny case
746         $operation.startOperation($event);
747         $operation.setOperationHasGuardDeny();
748         retract($opTimer);
749         retract($operation);
750         modify($manager) {finishOperation($operation)};
751     }
752
753     retract($guardResponse);
754
755 end
756
757 /*
758 *
759 * This rule responds to APPC Response Events
760 *
761 * I would have like to be consistent and write the Response like this:
762 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
763 *
764 * However, no compile error was given. But a runtime error was given. I think
765 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
766 *
767 */
768 rule "APPC.RESPONSE"
769     when
770         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
771         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
772             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
773         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
774             requestID == $event.getRequestId() )
775         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
776             onset.getRequestId() == $event.getRequestId() )
777         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
778             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
779         $lock : TargetLock (requestID == $event.getRequestId())
780         $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
781     then
782
783     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
784     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
785     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
786                  $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
787                  $event, $manager, $operation, $lock, $opTimer, $response);
788     //
789     // Get the result of the operation
790     //
791     PolicyResult policyResult = $operation.onResponse($response);
792     if (policyResult != null) {
793         logger.debug("{}: {}: operation finished - result={}",
794                     $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
795                     policyResult);
796         //
797         // This Operation has completed, construct a notification showing our results. (DB write - end operation)
798         //
799         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
800         notification.setFrom("policy");
801         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
802         notification.setPolicyScope($params.getPolicyScope());
803         notification.setPolicyVersion($params.getPolicyVersion());
804         notification.setMessage($operation.getOperationHistory());
805         notification.setHistory($operation.getHistory());
806         if (policyResult.equals(PolicyResult.SUCCESS)) {
807             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
808             //
809             // Let interested parties know
810             //
811             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
812         } else {
813             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
814             //
815             // Let interested parties know
816             //
817             PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
818         }
819         //
820         // Ensure the operation is complete
821         //
822         if ($operation.isOperationComplete() == true) {
823             //
824             // It is complete, remove it from memory
825             //
826             retract($operation);
827             //
828             // We must also retract the timer object
829             // NOTE: We could write a Rule to do this
830             //
831             retract($opTimer);
832             //
833             // Complete the operation
834             //
835             modify($manager) {finishOperation($operation)};
836         } else {
837             //
838             // Just doing this will kick off the LOCKED rule again
839             //
840             modify($operation) {};
841         }
842     } else {
843         //
844         // Its not finished yet (i.e. expecting more Response objects)
845         //
846         // Or possibly it is a leftover response that we timed the request out previously
847         //
848     }
849     //
850     // We are going to retract these objects from memory
851     //
852     retract($response);
853 end
854
855 /*
856 *
857 * The problem with Responses is that they don't have a controlLoopControlName
858 * field in them, so the only way to attach them is via RequestID. If we have multiple
859 * control loop .drl's loaded in the same container, we need to be sure the cleanup
860 * rules don't remove Responses for other control loops.
861 *
862 */
863 rule "APPC.RESPONSE.CLEANUP"
864     when
865         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
866         $response : Response($id : getCommonHeader().RequestId )
867         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
868     then
869
870     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
871     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
872     logger.debug("{}: {}: orphan appc response={}",
873                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
874
875     //
876     // Retract it
877     //
878     retract($response);
879 end
880
881 /*
882 *
883 * This rule responds to APPC Response Events using the new LCM interface provided by appc
884 *
885 */
886 rule "APPC.LCM.RESPONSE"
887     when
888         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
889         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
890             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
891         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
892             requestID == $event.getRequestId() )
893         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
894             onset.getRequestId() == $event.getRequestId() )
895         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
896             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
897         $lock : TargetLock (requestID == $event.getRequestId())
898         $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
899     then
900
901     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
902     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
903     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
904                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
905                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
906
907     //
908     // Get the result of the operation
909     //
910     PolicyResult policyResult = $operation.onResponse($response);
911     if (policyResult != null) {
912       logger.debug("{}: {}: operation finished - result={}",
913                   $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
914                   policyResult);
915
916       //
917       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
918       //
919       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
920       notification.setFrom("policy");
921       notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
922       notification.setPolicyScope($params.getPolicyScope());
923       notification.setPolicyVersion($params.getPolicyVersion());
924       notification.setMessage($operation.getOperationHistory());
925       notification.setHistory($operation.getHistory());
926       if (policyResult.equals(PolicyResult.SUCCESS)) {
927           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
928       } else {
929           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
930       }
931       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
932       //
933       // Ensure the operation is complete
934       //
935       if ($operation.isOperationComplete() == true) {
936           //
937           // It is complete, remove it from memory
938           //
939           retract($operation);
940           //
941           // We must also retract the timer object
942           // NOTE: We could write a Rule to do this
943           //
944           retract($opTimer);
945           //
946           // Complete the operation
947           //
948           modify($manager) {finishOperation($operation)};
949       } else {
950           //
951           // Just doing this will kick off the LOCKED rule again
952           //
953           modify($operation) {};
954       }
955     } else {
956         //
957         // Its not finished yet (i.e. expecting more Response objects)
958         //
959         // Or possibly it is a leftover response that we timed the request out previously
960         //
961     }
962     //
963     // We are going to retract these objects from memory
964     //
965     retract($response);
966 end
967
968 /*
969 *
970 * Clean Up any lingering LCM reponses
971 *
972 */
973 rule "APPC.LCM.RESPONSE.CLEANUP"
974     when
975         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
976         $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
977         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
978     then
979
980     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
981     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
982     logger.debug("{}: {}: orphan appc response={}",
983                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
984     //
985     // Retract it
986     //
987     retract($response);
988 end
989
990 /*
991 *
992 * This rule responds to SO Response Events
993 *
994 */
995 rule "SO.RESPONSE"
996     when
997         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
998         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
999             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1000         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1001             requestID == $event.getRequestId() )
1002         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1003             onset.getRequestId() == $event.getRequestId() )
1004         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1005             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1006         $lock : TargetLock (requestID == $event.getRequestId())
1007         $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
1008     then
1009
1010     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1011     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1012     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1013                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1014                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1015
1016     // Get the result of the operation
1017     //
1018     PolicyResult policyResult = $operation.onResponse($response);
1019     if (policyResult != null) {
1020         logger.debug("{}: {}: operation finished - result={}",
1021                     $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1022                     policyResult);
1023
1024         //
1025         // This Operation has completed, construct a notification showing our results
1026         //
1027         VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1028         notification.setFrom("policy");
1029         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1030         notification.setPolicyScope($params.getPolicyScope());
1031         notification.setPolicyVersion($params.getPolicyVersion());
1032         notification.setMessage($operation.getOperationHistory());
1033         notification.setHistory($operation.getHistory());
1034         if (policyResult.equals(PolicyResult.SUCCESS)) {
1035             notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1036         } else {
1037             notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1038
1039         }
1040         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1041         //
1042         // Ensure the operation is complete
1043         //
1044         if ($operation.isOperationComplete() == true) {
1045             //
1046             // It is complete, remove it from memory
1047             //
1048             retract($operation);
1049             //
1050             // We must also retract the timer object
1051             // NOTE: We could write a Rule to do this
1052             //
1053             retract($opTimer);
1054             //
1055             // Complete the operation
1056             //
1057             modify($manager) {finishOperation($operation)};
1058         } else {
1059             //
1060             // Just doing this will kick off the LOCKED rule again
1061             //
1062             modify($operation) {};
1063         }
1064     } else {
1065         //
1066         // Its not finished yet (i.e. expecting more Response objects)
1067         //
1068         // Or possibly it is a leftover response that we timed the request out previously
1069         //
1070     }
1071     //
1072     // We are going to retract these objects from memory
1073     //
1074     retract($response);
1075
1076 end
1077
1078 /*
1079 *
1080 * This rule responds to VFC Response Events
1081 *
1082 */
1083 rule "VFC.RESPONSE"
1084     when
1085         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1086         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
1087             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1088         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1089             requestID == $event.getRequestId() )
1090         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1091             onset.getRequestId() == $event.getRequestId() )
1092         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1093             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1094         $lock : TargetLock (requestID == $event.getRequestId())
1095         $response : VFCResponse( requestId.toString() == $event.getRequestId().toString() )
1096     then
1097         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1098         logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1099         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1100                     $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1101                     $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1102
1103         // Get the result of the operation
1104         //
1105         PolicyResult policyResult = $operation.onResponse($response);
1106         if (policyResult != null) {
1107             //
1108             // This Operation has completed, construct a notification showing our results
1109             //
1110             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1111             notification.setFrom("policy");
1112             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1113             notification.setPolicyScope($params.getPolicyScope());
1114             notification.setPolicyVersion($params.getPolicyVersion());
1115             notification.setMessage($operation.getOperationHistory());
1116             notification.setHistory($operation.getHistory());
1117             //
1118             // Ensure the operation is complete
1119             //
1120             if ($operation.isOperationComplete() == true) {
1121                 //
1122                 // It is complete, remove it from memory
1123                 //
1124                 retract($operation);
1125                 //
1126                 // We must also retract the timer object
1127                 // NOTE: We could write a Rule to do this
1128                 //
1129                 retract($opTimer);
1130                 //
1131                 // Complete the operation
1132                 //
1133                 modify($manager) {finishOperation($operation)};
1134             } else {
1135                 //
1136                 // Just doing this will kick off the LOCKED rule again
1137                 //
1138                 modify($operation) {};
1139             }
1140         } else {
1141             //
1142             // Its not finished yet (i.e. expecting more Response objects)
1143             //
1144             // Or possibly it is a leftover response that we timed the request out previously
1145             //
1146         }
1147         //
1148         // We are going to retract these objects from memory
1149         //
1150         retract($response);
1151
1152 end
1153
1154 /*
1155 *
1156 * This rule responds to SDNC Response Events
1157 *
1158 */
1159 rule "SDNC.RESPONSE"
1160     when
1161         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1162         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1163         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1164         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1165         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1166             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1167         $lock : TargetLock (requestID == $event.getRequestId())
1168         $response : SdncResponse( requestId.toString() == $event.getRequestId().toString() )
1169     then
1170         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1171         logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1172         logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1173                         $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1174                         $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1175
1176         // Get the result of the operation
1177         //
1178         PolicyResult policyResult = $operation.onResponse($response);
1179         if (policyResult != null) {
1180             //
1181             // This Operation has completed, construct a notification showing our results
1182             //
1183             VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1184             notification.setFrom("policy");
1185             notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1186             notification.setPolicyScope($params.getPolicyScope());
1187             notification.setPolicyVersion($params.getPolicyVersion());
1188             notification.setMessage($operation.getOperationHistory());
1189             notification.setHistory($operation.getHistory());
1190             //
1191             // Ensure the operation is complete
1192             //
1193             if ($operation.isOperationComplete()) {
1194                 //
1195                 // It is complete, remove it from memory
1196                 //
1197                 retract($operation);
1198                 //
1199                 // We must also retract the timer object
1200                 // NOTE: We could write a Rule to do this
1201                 //
1202                 retract($opTimer);
1203                 //
1204                 // Complete the operation
1205                 //
1206                 modify($manager) {finishOperation($operation)};
1207             } else {
1208                 //
1209                 // Just doing this will kick off the LOCKED rule again
1210                 //
1211                 modify($operation) {};
1212             }
1213         } else {
1214             //
1215             // Its not finished yet (i.e. expecting more Response objects)
1216             //
1217             // Or possibly it is a leftover response that we timed the request out previously
1218             //
1219         }
1220         //
1221         // We are going to retract these objects from memory
1222         //
1223         retract($response);
1224
1225 end
1226
1227 /*
1228 *
1229 * This manages a single timer.
1230 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1231 *
1232 */
1233 rule "TIMER.FIRED"
1234     timer (expr: $timeout)
1235     when
1236         $timer : ControlLoopTimer($timeout : delay, !expired)
1237     then
1238         Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1239         logger.info("This is TIMER.FIRED");
1240         modify($timer){setExpired(true)};
1241     end
1242
1243 /*
1244 *
1245 * This is the timer that manages the timeout for an individual operation.
1246 *
1247 */
1248 rule "EVENT.MANAGER.OPERATION.TIMEOUT"
1249     when
1250         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1251         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
1252         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1253             requestID == $event.getRequestId() )
1254         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1255             onset.getRequestId() == $event.getRequestId() )
1256         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1257             requestID == $event.getRequestId().toString(), timerType == "Operation", expired )
1258         $lock : TargetLock (requestID == $event.getRequestId())
1259     then
1260
1261     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1262     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1263     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1264                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1265                 $event, $manager, $operation, $lock, $operation, $opTimer);
1266
1267     //
1268     // Tell it its timed out
1269     //
1270     $operation.setOperationHasTimedOut();
1271     //
1272     // Create a notification for it ("DB Write - end operation")
1273     //
1274     VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1275     notification.setFrom("policy");
1276     notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1277     notification.setPolicyScope($params.getPolicyScope());
1278     notification.setPolicyVersion($params.getPolicyVersion());
1279     notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1280     notification.setMessage($operation.getOperationHistory());
1281     notification.setHistory($operation.getHistory());
1282     //
1283     // Let interested parties know
1284     //
1285     PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1286     //
1287     // Get rid of the timer
1288     //
1289     retract($opTimer);
1290     //
1291     // Ensure the operation is complete
1292     //
1293     if ($operation.isOperationComplete() == true) {
1294         //
1295         // It is complete, remove it from memory
1296         //
1297         retract($operation);
1298         //
1299         // Complete the operation
1300         //
1301         modify($manager) {finishOperation($operation)};
1302     } else {
1303         //
1304         // Just doing this will kick off the LOCKED rule again
1305         //
1306         modify($operation) {};
1307     }
1308 end
1309
1310 /*
1311 *
1312 * This is the timer that manages the overall control loop timeout.
1313 *
1314 */
1315 rule "EVENT.MANAGER.TIMEOUT"
1316     when
1317         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1318         $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
1319         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1320             requestID == $event.getRequestId() )
1321         $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1322             requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", expired )
1323     then
1324
1325     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1326     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1327
1328     logger.debug("{}: {}: event={}",
1329               $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1330               $event);
1331     //
1332     // Tell the Event Manager it has timed out
1333     //
1334     VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1335     if (notification != null) {
1336         notification.setFrom("policy");
1337         notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1338         notification.setPolicyScope($params.getPolicyScope());
1339         notification.setPolicyVersion($params.getPolicyVersion());
1340         //
1341         // Let interested parties know
1342         //
1343         PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1344     }
1345     //
1346     // Retract the event
1347     //
1348     retract($event);
1349 end
1350
1351 /*
1352 *
1353 * This rule cleans up the manager and other objects after an event has
1354 * been retracted.
1355 *
1356 */
1357 rule "EVENT.MANAGER.CLEANUP"
1358     when
1359         $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1360         $operations : LinkedList()
1361                         from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, 
1362                             onset.getRequestId() == $requestId ) )
1363         $timers : LinkedList()
1364                         from collect( ControlLoopTimer( closedLoopControlName == $clName, 
1365                             requestID == $requestId.toString() ) )
1366         $locks : LinkedList()
1367                         from collect( TargetLock (requestID == $requestId) )
1368         not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1369     then
1370
1371     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1372     logger.info("{}: {}", $clName, drools.getRule().getName());
1373
1374     logger.debug("{}: {}: manager={} timers={} operations={}",
1375               $clName, drools.getRule().getName(),
1376               $manager, $timers.size(), $operations.size());
1377
1378     //
1379     // Retract EVERYTHING
1380     //
1381     retract($manager);
1382
1383     for(Object manager: $operations) {
1384         retract((ControlLoopOperationManager) manager);
1385     }
1386     for(Object timer: $timers) {
1387         retract((ControlLoopTimer) timer);
1388     }
1389     for(Object lock: $locks) {
1390         TargetLock tgt = (TargetLock) lock;
1391         //
1392         // Ensure we release the lock
1393         //
1394         PolicyGuard.unlockTarget(tgt);
1395         retract(tgt);
1396     }
1397 end
1398
1399 /*
1400 *
1401 * This rule will clean up any rogue onsets where there is no
1402 * ControlLoopParams object corresponding to the onset event.
1403 *
1404 */
1405 rule "EVENT.CLEANUP"
1406     when
1407         $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1408         not ( ControlLoopParams( getClosedLoopControlName() == $clName) )
1409     then
1410
1411     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1412     logger.info("{}: {}", $clName, drools.getRule().getName());
1413     logger.debug("{}: {}: orphan onset event={}",
1414                 $clName, drools.getRule().getName(), $event);
1415
1416     retract($event);
1417 end
1418
1419 /*
1420 *
1421 * This rule responds to SDNR Response Events.
1422 *
1423 */
1424 rule "SDNR.RESPONSE"
1425     when
1426         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1427         $event : VirtualControlLoopEvent( closedLoopControlName == $clName, 
1428             closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1429         $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), 
1430             requestID == $event.getRequestId() )
1431         $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), 
1432             onset.getRequestId() == $event.getRequestId() )
1433         $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), 
1434             requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1435         $lock : TargetLock (requestID == $event.getRequestId())
1436         $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1437     then
1438
1439     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1440     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1441     logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1442                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1443                 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1444
1445     //
1446     // Get the result of the operation
1447     //
1448     PolicyResult policyResult = $operation.onResponse($response);
1449     if (policyResult != null) {
1450       logger.debug("{}: {}: operation finished - result={}",
1451                   $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1452                   policyResult);
1453
1454       //
1455       // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1456       //
1457       VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1458       notification.setFrom("policy");
1459       notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1460       notification.setPolicyScope($params.getPolicyScope());
1461       notification.setPolicyVersion($params.getPolicyVersion());
1462       notification.setMessage($operation.getOperationHistory());
1463       notification.setHistory($operation.getHistory());
1464       if (policyResult.equals(PolicyResult.SUCCESS)) {
1465           notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1466       } else {
1467           notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1468       }
1469       PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1470       //
1471       // Ensure the operation is complete
1472       //
1473       if ($operation.isOperationComplete() == true) {
1474           //
1475           // It is complete, remove it from memory
1476           //
1477           retract($operation);
1478           //
1479           // We must also retract the timer object
1480           // NOTE: We could write a Rule to do this
1481           //
1482           retract($opTimer);
1483           //
1484           // Complete the operation
1485           //
1486           modify($manager) {finishOperation($operation)};
1487       } else {
1488           //
1489           // Just doing this will kick off the LOCKED rule again
1490           //
1491           modify($operation) {};
1492       }
1493     } else {
1494         //
1495         // Its not finished yet (i.e. expecting more Response objects)
1496         //
1497         // Or possibly it is a leftover response that we timed the request out previously
1498         //
1499     }
1500     //
1501     // We are going to retract these objects from memory
1502     //
1503     retract($response);
1504 end
1505
1506 /*
1507 *
1508 * Clean Up any lingering SDNR reponses.
1509 *
1510 */
1511 rule "SDNR.RESPONSE.CLEANUP"
1512     when
1513         $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1514         $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1515         not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1516     then
1517
1518     Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1519     logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1520     logger.debug("{}: {}: orphan sdnr response={}",
1521                 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
1522     //
1523     // Retract it
1524     //
1525     retract($response);
1526 end