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