4b438a94d7b91e7fb2eea6e60b3d8055837d511e
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * controlloop event manager
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.eventmanager;
22
23 import java.io.Serializable;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URLDecoder;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.HashMap;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.UUID;
33
34 import org.onap.policy.aai.AaiGetVnfResponse;
35 import org.onap.policy.aai.AaiGetVserverResponse;
36 import org.onap.policy.aai.AaiManager;
37 import org.onap.policy.aai.AaiNqInstanceFilters;
38 import org.onap.policy.aai.AaiNqNamedQuery;
39 import org.onap.policy.aai.AaiNqQueryParameters;
40 import org.onap.policy.aai.AaiNqRequest;
41 import org.onap.policy.aai.AaiNqResponse;
42 import org.onap.policy.aai.AaiNqResponseWrapper;
43 import org.onap.policy.aai.AaiNqVServer;
44 import org.onap.policy.aai.util.AaiException;
45 import org.onap.policy.controlloop.ControlLoopEventStatus;
46 import org.onap.policy.controlloop.ControlLoopException;
47 import org.onap.policy.controlloop.ControlLoopNotificationType;
48 import org.onap.policy.controlloop.ControlLoopOperation;
49 import org.onap.policy.controlloop.VirtualControlLoopEvent;
50 import org.onap.policy.controlloop.VirtualControlLoopNotification;
51 import org.onap.policy.controlloop.policy.FinalResult;
52 import org.onap.policy.controlloop.policy.Policy;
53 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
54 import org.onap.policy.drools.system.PolicyEngine;
55 import org.onap.policy.guard.GuardResult;
56 import org.onap.policy.guard.LockCallback;
57 import org.onap.policy.guard.PolicyGuard;
58 import org.onap.policy.guard.PolicyGuard.LockResult;
59 import org.onap.policy.guard.TargetLock;
60 import org.onap.policy.rest.RESTManager;
61 import org.onap.policy.so.util.Serialization;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 public class ControlLoopEventManager implements LockCallback, Serializable {
66     public static final String PROV_STATUS_ACTIVE = "ACTIVE";
67     private static final String VM_NAME = "VM_NAME";
68     private static final String VNF_NAME = "VNF_NAME";
69     public static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
70     public static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
71     public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
72     public static final String GENERIC_VNF_IS_CLOSED_LOOP_DISABLED = "generic-vnf.is-closed-loop-disabled";
73     public static final String VSERVER_IS_CLOSED_LOOP_DISABLED = "vserver.is-closed-loop-disabled";
74     public static final String GENERIC_VNF_PROV_STATUS = "generic-vnf.prov-status";
75     public static final String VSERVER_PROV_STATUS = "vserver.prov-status";
76
77     private static final String QUERY_AAI_ERROR_MSG = "Exception from queryAai: ";
78
79     /**
80      * Additional time, in seconds, to add to a "lock" request. This ensures that the lock
81      * won't expire right before an operation completes.
82      */
83     private static final int ADDITIONAL_LOCK_SEC = 60;
84
85     private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
86
87     private static final long serialVersionUID = -1216568161322872641L;
88     public final String closedLoopControlName;
89     public final UUID requestID;
90
91     private String controlLoopResult;
92     private transient ControlLoopProcessor processor = null;
93     private VirtualControlLoopEvent onset;
94     private Integer numOnsets = 0;
95     private Integer numAbatements = 0;
96     private VirtualControlLoopEvent abatement;
97     private FinalResult controlLoopTimedOut = null;
98
99     private boolean isActivated = false;
100     private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
101     private ControlLoopOperationManager currentOperation = null;
102     private transient TargetLock targetLock = null;
103     private AaiGetVnfResponse vnfResponse = null;
104     private AaiGetVserverResponse vserverResponse = null;
105
106     /**
107      * Wrapper for AAI vserver named-query response. This is initialized in a lazy
108      * fashion.
109      */
110     private AaiNqResponseWrapper nqVserverResponse = null;
111
112     private static Collection<String> requiredAAIKeys = new ArrayList<>();
113
114     static {
115         requiredAAIKeys.add("AICVServerSelfLink");
116         requiredAAIKeys.add("AICIdentity");
117         requiredAAIKeys.add("is_closed_loop_disabled");
118         requiredAAIKeys.add(VM_NAME);
119     }
120
121     public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
122         this.closedLoopControlName = closedLoopControlName;
123         this.requestID = requestID;
124     }
125
126     public String getClosedLoopControlName() {
127         return closedLoopControlName;
128     }
129
130     public String getControlLoopResult() {
131         return controlLoopResult;
132     }
133
134     public void setControlLoopResult(String controlLoopResult) {
135         this.controlLoopResult = controlLoopResult;
136     }
137
138     public Integer getNumOnsets() {
139         return numOnsets;
140     }
141
142     public void setNumOnsets(Integer numOnsets) {
143         this.numOnsets = numOnsets;
144     }
145
146     public Integer getNumAbatements() {
147         return numAbatements;
148     }
149
150     public void setNumAbatements(Integer numAbatements) {
151         this.numAbatements = numAbatements;
152     }
153
154     public boolean isActivated() {
155         return isActivated;
156     }
157
158     public void setActivated(boolean isActivated) {
159         this.isActivated = isActivated;
160     }
161
162     public VirtualControlLoopEvent getOnsetEvent() {
163         return this.onset;
164     }
165
166     public VirtualControlLoopEvent getAbatementEvent() {
167         return this.abatement;
168     }
169
170     public ControlLoopProcessor getProcessor() {
171         return this.processor;
172     }
173
174     public UUID getRequestID() {
175         return requestID;
176     }
177
178     /**
179      * Activate a control loop event.
180      *
181      * @param event the event
182      * @return the VirtualControlLoopNotification
183      */
184     public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
185         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
186         try {
187             //
188             // This method should ONLY be called ONCE
189             //
190             if (this.isActivated) {
191                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
192             }
193             //
194             // Syntax check the event
195             //
196             checkEventSyntax(event);
197
198             //
199             // At this point we are good to go with this event
200             //
201             this.onset = event;
202             this.numOnsets = 1;
203             //
204             notification.setNotification(ControlLoopNotificationType.ACTIVE);
205             //
206             // Set ourselves as active
207             //
208             this.isActivated = true;
209         } catch (ControlLoopException e) {
210             logger.error("{}: activate by event threw: ", this, e);
211             notification.setNotification(ControlLoopNotificationType.REJECTED);
212             notification.setMessage(e.getMessage());
213         }
214         return notification;
215     }
216
217     /**
218      * Activate a control loop event.
219      *
220      * @param yamlSpecification the yaml specification
221      * @param event the event
222      * @return the VirtualControlLoopNotification
223      */
224     public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
225         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
226         try {
227             //
228             // This method should ONLY be called ONCE
229             //
230             if (this.isActivated) {
231                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
232             }
233             //
234             // Syntax check the event
235             //
236             checkEventSyntax(event);
237
238             //
239             // Check the YAML
240             //
241             if (yamlSpecification == null || yamlSpecification.length() < 1) {
242                 throw new ControlLoopException("yaml specification is null or 0 length");
243             }
244         } catch (ControlLoopException e) {
245             logger.error("{}: activate by YAML specification and event threw: ", this, e);
246             notification.setNotification(ControlLoopNotificationType.REJECTED);
247             notification.setMessage(e.getMessage());
248             return notification;
249         }
250
251         String decodedYaml = null;
252         try {
253             decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
254             if (decodedYaml != null && decodedYaml.length() > 0) {
255                 yamlSpecification = decodedYaml;
256             }
257         } catch (UnsupportedEncodingException e) {
258             logger.error("{}: YAML decode in activate by YAML specification and event threw: ", this, e);
259             notification.setNotification(ControlLoopNotificationType.REJECTED);
260             notification.setMessage(e.getMessage());
261             return notification;
262         }
263
264         try {
265             //
266             // Parse the YAML specification
267             //
268             this.processor = new ControlLoopProcessor(yamlSpecification);
269
270             //
271             // At this point we are good to go with this event
272             //
273             this.onset = event;
274             this.numOnsets = 1;
275             //
276             //
277             //
278             notification.setNotification(ControlLoopNotificationType.ACTIVE);
279             //
280             // Set ourselves as active
281             //
282             this.isActivated = true;
283         } catch (ControlLoopException e) {
284             logger.error("{}: activate by YAML specification and event threw: ", this, e);
285             notification.setNotification(ControlLoopNotificationType.REJECTED);
286             notification.setMessage(e.getMessage());
287         }
288         return notification;
289     }
290
291     /**
292      * Check if the control loop is final.
293      *
294      * @return a VirtualControlLoopNotification if the control loop is final, otherwise
295      *         <code>null</code> is returned
296      * @throws ControlLoopException if an error occurs
297      */
298     public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
299         //
300         // Check if they activated us
301         //
302         if (!this.isActivated) {
303             throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
304         }
305         //
306         // Make sure we are expecting this call.
307         //
308         if (this.onset == null) {
309             throw new ControlLoopException("No onset event for ControlLoopEventManager.");
310         }
311         //
312         // Ok, start creating the notification
313         //
314         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
315         //
316         // Check if the overall control loop has timed out
317         //
318         if (this.isControlLoopTimedOut()) {
319             //
320             // Yes we have timed out
321             //
322             notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
323             notification.setMessage("Control Loop timed out");
324             notification.getHistory().addAll(this.controlLoopHistory);
325             return notification;
326         }
327         //
328         // Check if the current policy is Final
329         //
330         FinalResult result = this.processor.checkIsCurrentPolicyFinal();
331         if (result == null) {
332             //
333             // we are not at a final result
334             //
335             return null;
336         }
337
338         switch (result) {
339             case FINAL_FAILURE_EXCEPTION:
340                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
341                 notification.setMessage("Exception in processing closed loop");
342                 break;
343             case FINAL_FAILURE:
344             case FINAL_FAILURE_RETRIES:
345             case FINAL_FAILURE_TIMEOUT:
346             case FINAL_FAILURE_GUARD:
347                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
348                 break;
349             case FINAL_OPENLOOP:
350                 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
351                 break;
352             case FINAL_SUCCESS:
353                 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
354                 break;
355             default:
356                 return null;
357         }
358         //
359         // Be sure to add all the history
360         //
361         notification.getHistory().addAll(this.controlLoopHistory);
362         return notification;
363     }
364
365     /**
366      * Process the control loop.
367      *
368      * @return a ControlLoopOperationManager
369      * @throws ControlLoopException if an error occurs
370      * @throws AaiException if an error occurs retrieving information from A&AI
371      */
372     public ControlLoopOperationManager processControlLoop() throws ControlLoopException, AaiException {
373         //
374         // Check if they activated us
375         //
376         if (!this.isActivated) {
377             throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
378         }
379         //
380         // Make sure we are expecting this call.
381         //
382         if (this.onset == null) {
383             throw new ControlLoopException("No onset event for ControlLoopEventManager.");
384         }
385         //
386         // Is there a current operation?
387         //
388         if (this.currentOperation != null) {
389             //
390             // Throw an exception, or simply return the current operation?
391             //
392             throw new ControlLoopException("Already working an Operation, do not call this method.");
393         }
394         //
395         // Ensure we are not FINAL
396         //
397         VirtualControlLoopNotification notification = this.isControlLoopFinal();
398         if (notification != null) {
399             //
400             // This is weird, we require them to call the isControlLoopFinal() method first
401             //
402             // We should really abstract this and avoid throwing an exception, because it really
403             // isn't an exception.
404             //
405             throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
406         }
407         //
408         // Not final so get the policy that needs to be worked on.
409         //
410         Policy policy = this.processor.getCurrentPolicy();
411         if (policy == null) {
412             throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
413         }
414         //
415         // And setup an operation
416         //
417         this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
418         //
419         // Return it
420         //
421         return this.currentOperation;
422     }
423
424     /**
425      * Finish an operation.
426      *
427      * @param operation the operation
428      */
429     public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
430         //
431         // Verify we have a current operation
432         //
433         if (this.currentOperation != null) {
434             //
435             // Validate they are finishing the current operation
436             // PLD - this is simply comparing the policy. Do we want to equals the whole object?
437             //
438             if (this.currentOperation.policy.equals(operation.policy)) {
439                 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(),
440                         this.currentOperation.getOperationResult());
441                 //
442                 // Save history
443                 //
444                 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
445                 //
446                 // Move to the next Policy
447                 //
448                 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
449                 //
450                 // Just null this out
451                 //
452                 this.currentOperation = null;
453                 //
454                 // TODO: Release our lock
455                 //
456                 return;
457             }
458             logger.debug("Cannot finish current operation {} does not match given operation {}",
459                     this.currentOperation.policy, operation.policy);
460             return;
461         }
462         throw new ControlLoopException("No operation to finish.");
463     }
464
465     /**
466      * Obtain a lock for the current operation.
467      *
468      * @return the lock result
469      * @throws ControlLoopException if an error occurs
470      */
471     public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
472         //
473         // Sanity check
474         //
475         if (this.currentOperation == null) {
476             throw new ControlLoopException("Do not have a current operation.");
477         }
478         //
479         // Have we acquired it already?
480         //
481         if (this.targetLock != null) {
482             //
483             // TODO: Make sure the current lock is for the same target.
484             // Currently, it should be. But in the future it may not.
485             //
486             GuardResult result = PolicyGuard.lockTarget(targetLock,
487                             this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
488             return new LockResult<>(result, this.targetLock);
489         } else {
490             //
491             // Ask the Guard
492             //
493             LockResult<GuardResult, TargetLock> lockResult =
494                     PolicyGuard.lockTarget(this.currentOperation.policy.getTarget().getType(),
495                             this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this,
496                             this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
497             //
498             // Was it acquired?
499             //
500             if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
501                 //
502                 // Yes, let's save it
503                 //
504                 this.targetLock = lockResult.getB();
505             }
506             return lockResult;
507         }
508     }
509
510     /**
511      * Release the lock for the current operation.
512      *
513      * @return the target lock
514      */
515     public synchronized TargetLock unlockCurrentOperation() {
516         if (this.targetLock == null) {
517             return null;
518         }
519
520         TargetLock returnLock = this.targetLock;
521         this.targetLock = null;
522
523         PolicyGuard.unlockTarget(returnLock);
524
525         // always return the old target lock so rules can retract it
526         return returnLock;
527     }
528
529     public enum NEW_EVENT_STATUS {
530         FIRST_ONSET, SUBSEQUENT_ONSET, FIRST_ABATEMENT, SUBSEQUENT_ABATEMENT, SYNTAX_ERROR;
531     }
532
533     /**
534      * An event onset/abatement.
535      *
536      * @param event the event
537      * @return the status
538      * @throws AaiException if an error occurs retrieving information from A&AI
539      */
540     public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) throws AaiException {
541         try {
542             this.checkEventSyntax(event);
543             if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ONSET) {
544                 //
545                 // Check if this is our original ONSET
546                 //
547                 if (event.equals(this.onset)) {
548                     //
549                     // Query A&AI if needed
550                     //
551                     queryAai(event);
552
553                     //
554                     // DO NOT retract it
555                     //
556                     return NEW_EVENT_STATUS.FIRST_ONSET;
557                 }
558                 //
559                 // Log that we got an onset
560                 //
561                 this.numOnsets++;
562                 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
563             } else if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
564                 //
565                 // Have we already got an abatement?
566                 //
567                 if (this.abatement == null) {
568                     //
569                     // Save this
570                     //
571                     this.abatement = event;
572                     //
573                     // Keep track that we received another
574                     //
575                     this.numAbatements++;
576                     //
577                     //
578                     //
579                     return NEW_EVENT_STATUS.FIRST_ABATEMENT;
580                 } else {
581                     //
582                     // Keep track that we received another
583                     //
584                     this.numAbatements++;
585                     //
586                     //
587                     //
588                     return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
589                 }
590             }
591         } catch (ControlLoopException e) {
592             logger.error("{}: onNewEvent threw: ", this, e);
593         }
594         return NEW_EVENT_STATUS.SYNTAX_ERROR;
595     }
596
597     /**
598      * Set the control loop time out.
599      *
600      * @return a VirtualControlLoopNotification
601      */
602     public VirtualControlLoopNotification setControlLoopTimedOut() {
603         this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
604         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
605         notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
606         notification.setMessage("Control Loop timed out");
607         notification.getHistory().addAll(this.controlLoopHistory);
608         return notification;
609     }
610
611     public boolean isControlLoopTimedOut() {
612         return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
613     }
614
615     /**
616      * Get the control loop timeout.
617      *
618      * @param defaultTimeout the default timeout
619      * @return the timeout
620      */
621     public int getControlLoopTimeout(Integer defaultTimeout) {
622         if (this.processor != null && this.processor.getControlLoop() != null) {
623             return this.processor.getControlLoop().getTimeout();
624         }
625         if (defaultTimeout != null) {
626             return defaultTimeout;
627         }
628         return 0;
629     }
630
631     public AaiGetVnfResponse getVnfResponse() {
632         return vnfResponse;
633     }
634
635     public AaiGetVserverResponse getVserverResponse() {
636         return vserverResponse;
637     }
638
639     /**
640      * Check an event syntax.
641      *
642      * @param event the event syntax
643      * @throws ControlLoopException if an error occurs
644      */
645     public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
646         if (event.getClosedLoopEventStatus() == null
647                 || (event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET
648                         && event.getClosedLoopEventStatus() != ControlLoopEventStatus.ABATED)) {
649             throw new ControlLoopException("Invalid value in closedLoopEventStatus");
650         }
651         if (event.getClosedLoopControlName() == null || event.getClosedLoopControlName().length() < 1) {
652             throw new ControlLoopException("No control loop name");
653         }
654         if (event.getRequestId() == null) {
655             throw new ControlLoopException("No request ID");
656         }
657         if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
658             return;
659         }
660         if (event.getTarget() == null || event.getTarget().length() < 1) {
661             throw new ControlLoopException("No target field");
662         } else if (!VM_NAME.equalsIgnoreCase(event.getTarget()) && !VNF_NAME.equalsIgnoreCase(event.getTarget())
663                 && !VSERVER_VSERVER_NAME.equalsIgnoreCase(event.getTarget())
664                 && !GENERIC_VNF_VNF_ID.equalsIgnoreCase(event.getTarget())
665                 && !GENERIC_VNF_VNF_NAME.equalsIgnoreCase(event.getTarget())) {
666             throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
667         }
668         if (event.getAai() == null) {
669             throw new ControlLoopException("AAI is null");
670         }
671         if (event.getAai().get(GENERIC_VNF_VNF_ID) == null && event.getAai().get(VSERVER_VSERVER_NAME) == null
672                 && event.getAai().get(GENERIC_VNF_VNF_NAME) == null) {
673             throw new ControlLoopException(
674                     "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
675         }
676     }
677
678     /**
679      * Query A&AI for an event.
680      *
681      * @param event the event
682      * @throws AaiException if an error occurs retrieving information from A&AI
683      */
684     public void queryAai(VirtualControlLoopEvent event) throws AaiException {
685
686         Map<String, String> aai = event.getAai();
687
688         if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
689
690             if (isClosedLoopDisabled(event)) {
691                 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
692             }
693
694             if (isProvStatusInactive(event)) {
695                 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
696             }
697
698             // no need to query, as we already have the data
699             return;
700         }
701
702         if (vnfResponse != null || vserverResponse != null) {
703             // query has already been performed
704             return;
705         }
706
707         try {
708             if (aai.containsKey(GENERIC_VNF_VNF_ID) || aai.containsKey(GENERIC_VNF_VNF_NAME)) {
709                 vnfResponse = getAAIVnfInfo(event);
710                 processVNFResponse(vnfResponse, aai.containsKey(GENERIC_VNF_VNF_ID));
711             } else if (aai.containsKey(VSERVER_VSERVER_NAME)) {
712                 vserverResponse = getAAIVserverInfo(event);
713                 processVServerResponse(vserverResponse);
714             }
715         } catch (AaiException e) {
716             logger.error(QUERY_AAI_ERROR_MSG, e);
717             throw e;
718         } catch (Exception e) {
719             logger.error(QUERY_AAI_ERROR_MSG, e);
720             throw new AaiException(QUERY_AAI_ERROR_MSG + e.toString());
721         }
722     }
723
724     /**
725      * Process a response from A&AI for a VNF.
726      *
727      * @param aaiResponse the response from A&AI
728      * @param queryByVnfId <code>true</code> if the query was based on vnf-id,
729      *        <code>false</code> if the query was based on vnf-name
730      * @throws AaiException if an error occurs processing the response
731      */
732     private static void processVNFResponse(AaiGetVnfResponse aaiResponse, boolean queryByVNFID) throws AaiException {
733         String queryTypeString = (queryByVNFID ? "vnf-id" : "vnf-name");
734
735         if (aaiResponse == null) {
736             throw new AaiException("AAI Response is null (query by " + queryTypeString + ")");
737         }
738         if (aaiResponse.getRequestError() != null) {
739             throw new AaiException("AAI Responded with a request error (query by " + queryTypeString + ")");
740         }
741
742         if (aaiResponse.getIsClosedLoopDisabled()) {
743             throw new AaiException("is-closed-loop-disabled is set to true (query by " + queryTypeString + ")");
744         }
745
746         if (!PROV_STATUS_ACTIVE.equals(aaiResponse.getProvStatus())) {
747             throw new AaiException("prov-status is not ACTIVE (query by " + queryTypeString + ")");
748         }
749     }
750
751     /**
752      * Process a response from A&AI for a VServer.
753      *
754      * @param aaiResponse the response from A&AI
755      * @throws AaiException if an error occurs processing the response
756      */
757     private static void processVServerResponse(AaiGetVserverResponse aaiResponse) throws AaiException {
758         if (aaiResponse == null) {
759             throw new AaiException("AAI Response is null (query by vserver-name)");
760         }
761         if (aaiResponse.getRequestError() != null) {
762             throw new AaiException("AAI Responded with a request error (query by vserver-name)");
763         }
764
765         List<AaiNqVServer> lst = aaiResponse.getVserver();
766         if (lst.isEmpty()) {
767             return;
768         }
769
770         AaiNqVServer svr = lst.get(0);
771         if (svr.getIsClosedLoopDisabled()) {
772             throw new AaiException("is-closed-loop-disabled is set to true (query by vserver-name)");
773         }
774
775         if (!PROV_STATUS_ACTIVE.equals(svr.getProvStatus())) {
776             throw new AaiException("prov-status is not ACTIVE (query by vserver-name)");
777         }
778     }
779
780     /**
781      * Is closed loop disabled for an event.
782      *
783      * @param event the event
784      * @return <code>true</code> if the control loop is disabled, <code>false</code>
785      *         otherwise
786      */
787     public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
788         Map<String, String> aai = event.getAai();
789         return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
790                         || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)));
791     }
792
793     /**
794      * Does provisioning status, for an event, have a value other than ACTIVE.
795      *
796      * @param event the event
797      * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null},
798      *         {@code false} otherwise
799      */
800     protected static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
801         Map<String, String> aai = event.getAai();
802         return (!PROV_STATUS_ACTIVE.equals(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
803                         || !PROV_STATUS_ACTIVE.equals(aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
804     }
805
806     /**
807      * Determines the boolean value represented by the given AAI field value.
808      *
809      * @param aaiValue value to be examined
810      * @return the boolean value represented by the field value, or {@code false} if the
811      *         value is {@code null}
812      */
813     protected static boolean isAaiTrue(String aaiValue) {
814         return ("true".equalsIgnoreCase(aaiValue) || "T".equalsIgnoreCase(aaiValue) || "yes".equalsIgnoreCase(aaiValue)
815                         || "Y".equalsIgnoreCase(aaiValue));
816     }
817
818     /**
819      * Get the A&AI VService information for an event.
820      *
821      * @param event the event
822      * @return a AaiGetVserverResponse
823      * @throws ControlLoopException if an error occurs
824      */
825     public static AaiGetVserverResponse getAAIVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
826         UUID requestId = event.getRequestId();
827         AaiGetVserverResponse response = null;
828         String vserverName = event.getAai().get(VSERVER_VSERVER_NAME);
829
830         try {
831             if (vserverName != null) {
832                 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty("aai.url");
833                 String aaiUser = PolicyEngine.manager.getEnvironmentProperty("aai.username");
834                 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
835                 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
836                 String url = aaiHostUrl + aaiGetQueryByVserver;
837                 logger.info("AAI Host URL by VServer: {}", url);
838                 response = new AaiManager(new RESTManager()).getQueryByVserverName(url, aaiUser, aaiPassword, requestId,
839                         vserverName);
840             }
841         } catch (Exception e) {
842             logger.error("getAAIVserverInfo exception: ", e);
843             throw new ControlLoopException("Exception in getAAIVserverInfo: ", e);
844         }
845
846         return response;
847     }
848
849     /**
850      * Get A&AI VNF information for an event.
851      *
852      * @param event the event
853      * @return a AaiGetVnfResponse
854      * @throws ControlLoopException if an error occurs
855      */
856     public static AaiGetVnfResponse getAAIVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
857         UUID requestId = event.getRequestId();
858         AaiGetVnfResponse response = null;
859         String vnfName = event.getAai().get(GENERIC_VNF_VNF_NAME);
860         String vnfId = event.getAai().get(GENERIC_VNF_VNF_ID);
861
862         String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty("aai.url");
863         String aaiUser = PolicyEngine.manager.getEnvironmentProperty("aai.username");
864         String aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
865
866         try {
867             if (vnfName != null) {
868                 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
869                 String url = aaiHostUrl + aaiGetQueryByVnfName;
870                 logger.info("AAI Host URL by VNF name: {}", url);
871                 response = new AaiManager(new RESTManager()).getQueryByVnfName(url, aaiUser, aaiPassword, requestId,
872                         vnfName);
873             } else if (vnfId != null) {
874                 String aaiGetQueryByVnfId = "/aai/v11/network/generic-vnfs/generic-vnf/";
875                 String url = aaiHostUrl + aaiGetQueryByVnfId;
876                 logger.info("AAI Host URL by VNF ID: {}", url);
877                 response =
878                         new AaiManager(new RESTManager()).getQueryByVnfId(url, aaiUser, aaiPassword, requestId, vnfId);
879             }
880         } catch (Exception e) {
881             logger.error("getAAIVnfInfo exception: ", e);
882             throw new ControlLoopException("Exception in getAAIVnfInfo: ", e);
883         }
884
885         return response;
886     }
887
888     /**
889      * Gets the output from the AAI vserver named-query, using the cache, if appropriate.
890      * @return output from the AAI vserver named-query
891      */
892     public AaiNqResponseWrapper getNqVserverFromAai() {
893         if (nqVserverResponse != null) {
894             // already queried
895             return nqVserverResponse;
896         }
897
898         String vserverName = onset.getAai().get(VSERVER_VSERVER_NAME);
899         if (vserverName == null) {
900             logger.warn("Missing vserver-name for AAI request {}", onset.getRequestId());
901             return null;
902         }
903
904         // create AAI named-query request with UUID started with ""
905         AaiNqRequest aaiNqRequest = new AaiNqRequest();
906         AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
907         AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
908         final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
909
910         // queryParameters
911         // TODO: UUID.fromString($params.getAaiNamedQueryUUID()) AaiNamedQueryUUID
912         aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
913         aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
914         aaiNqRequest.setQueryParameters(aaiNqQueryParam);
915         //
916         // instanceFilters
917         //
918         Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
919         Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
920         aaiNqInstanceFilterMapItem.put("vserver-name", vserverName);
921         aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
922         aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
923         aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
924
925         if (logger.isDebugEnabled()) {
926             logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
927         }
928
929         AaiNqResponse aaiNqResponse = new AaiManager(new RESTManager()).postQuery(getPeManagerEnvProperty("aai.url"),
930                 getPeManagerEnvProperty("aai.username"), getPeManagerEnvProperty("aai.password"), aaiNqRequest,
931                 onset.getRequestId());
932
933         // Check AAI response
934         if (aaiNqResponse == null) {
935             logger.warn("No response received from AAI for request {}", aaiNqRequest);
936             return null;
937         }
938
939         // Create AAINQResponseWrapper
940         nqVserverResponse = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
941
942         if (logger.isDebugEnabled()) {
943             logger.debug("AAI Named Query Response: ");
944             logger.debug(Serialization.gsonPretty.toJson(nqVserverResponse.getAaiNqResponse()));
945         }
946
947         return nqVserverResponse;
948     }
949
950     /**
951      * This method reads and validates environmental properties coming from the policy engine. Null
952      * properties cause an {@link IllegalArgumentException} runtime exception to be thrown
953      *
954      * @param enginePropertyName the name of the parameter to retrieve
955      * @return the property value
956      */
957     private static String getPeManagerEnvProperty(String enginePropertyName) {
958         String enginePropertyValue = PolicyEngine.manager.getEnvironmentProperty(enginePropertyName);
959         if (enginePropertyValue == null) {
960             throw new IllegalArgumentException("The value of policy engine manager environment property \""
961                     + enginePropertyName + "\" may not be null");
962         }
963         return enginePropertyValue;
964     }
965
966     @Override
967     public boolean isActive() {
968         // TODO
969         return true;
970     }
971
972     @Override
973     public boolean releaseLock() {
974         // TODO
975         return false;
976     }
977
978     @Override
979     public String toString() {
980         return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestID=" + requestID
981                 + ", processor=" + processor + ", onset=" + (onset != null ? onset.getRequestId() : "null")
982                 + ", numOnsets=" + numOnsets + ", numAbatements=" + numAbatements + ", isActivated=" + isActivated
983                 + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";
984     }
985
986 }