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