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