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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.controlloop.eventmanager;
 
  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;
 
  32 import java.util.UUID;
 
  33 import java.util.NoSuchElementException;
 
  35 import org.onap.policy.aai.AaiGetVnfResponse;
 
  36 import org.onap.policy.aai.AaiGetVserverResponse;
 
  37 import org.onap.policy.aai.AaiManager;
 
  38 import org.onap.policy.aai.AaiNqInstanceFilters;
 
  39 import org.onap.policy.aai.AaiNqNamedQuery;
 
  40 import org.onap.policy.aai.AaiNqQueryParameters;
 
  41 import org.onap.policy.aai.AaiNqRequest;
 
  42 import org.onap.policy.aai.AaiNqResponse;
 
  43 import org.onap.policy.aai.AaiNqResponseWrapper;
 
  44 import org.onap.policy.aai.AaiNqVServer;
 
  45 import org.onap.policy.aai.util.AaiException;
 
  46 import org.onap.policy.controlloop.ControlLoopEventStatus;
 
  47 import org.onap.policy.controlloop.ControlLoopException;
 
  48 import org.onap.policy.controlloop.ControlLoopNotificationType;
 
  49 import org.onap.policy.controlloop.ControlLoopOperation;
 
  50 import org.onap.policy.controlloop.VirtualControlLoopEvent;
 
  51 import org.onap.policy.controlloop.VirtualControlLoopNotification;
 
  52 import org.onap.policy.controlloop.policy.FinalResult;
 
  53 import org.onap.policy.controlloop.policy.Policy;
 
  54 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
 
  55 import org.onap.policy.drools.system.PolicyEngine;
 
  56 import org.onap.policy.guard.GuardResult;
 
  57 import org.onap.policy.guard.LockCallback;
 
  58 import org.onap.policy.guard.PolicyGuard;
 
  59 import org.onap.policy.guard.PolicyGuard.LockResult;
 
  60 import org.onap.policy.guard.TargetLock;
 
  61 import org.onap.policy.rest.RESTManager;
 
  62 import org.onap.policy.so.util.Serialization;
 
  63 import org.slf4j.Logger;
 
  64 import org.slf4j.LoggerFactory;
 
  66 public class ControlLoopEventManager implements LockCallback, Serializable {
 
  67     public static final String PROV_STATUS_ACTIVE = "ACTIVE";
 
  68     private static final String VM_NAME = "VM_NAME";
 
  69     private static final String VNF_NAME = "VNF_NAME";
 
  70     public static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
 
  71     public static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
 
  72     public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
 
  73     public static final String GENERIC_VNF_IS_CLOSED_LOOP_DISABLED = "generic-vnf.is-closed-loop-disabled";
 
  74     public static final String VSERVER_IS_CLOSED_LOOP_DISABLED = "vserver.is-closed-loop-disabled";
 
  75     public static final String GENERIC_VNF_PROV_STATUS = "generic-vnf.prov-status";
 
  76     public static final String VSERVER_PROV_STATUS = "vserver.prov-status";
 
  78     private static final String AAI_URL = "aai.url";
 
  79     private static final String AAI_USERNAME = "aai.username";
 
  80     private static final String AAI_PASSWD = "aai.password";
 
  82     private static final String QUERY_AAI_ERROR_MSG = "Exception from queryAai: ";
 
  85      * Additional time, in seconds, to add to a "lock" request. This ensures that the lock
 
  86      * won't expire right before an operation completes.
 
  88     private static final int ADDITIONAL_LOCK_SEC = 60;
 
  90     private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
 
  92     private static final long serialVersionUID = -1216568161322872641L;
 
  93     public final String closedLoopControlName;
 
  94     public final UUID requestID;
 
  96     private String controlLoopResult;
 
  97     private ControlLoopProcessor processor = null;
 
  98     private VirtualControlLoopEvent onset;
 
  99     private Integer numOnsets = 0;
 
 100     private Integer numAbatements = 0;
 
 101     private VirtualControlLoopEvent abatement;
 
 102     private FinalResult controlLoopTimedOut = null;
 
 104     private boolean isActivated = false;
 
 105     private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
 
 106     private ControlLoopOperationManager currentOperation = null;
 
 107     private ControlLoopOperationManager lastOperationManager = null;
 
 108     private transient TargetLock targetLock = null;
 
 109     private AaiGetVnfResponse vnfResponse = null;
 
 110     private AaiGetVserverResponse vserverResponse = null;
 
 111     private boolean useTargetLock = true;
 
 114      * Wrapper for AAI vserver named-query response. This is initialized in a lazy
 
 117     private AaiNqResponseWrapper nqVserverResponse = null;
 
 119     private static Collection<String> requiredAAIKeys = new ArrayList<>();
 
 122         requiredAAIKeys.add("AICVServerSelfLink");
 
 123         requiredAAIKeys.add("AICIdentity");
 
 124         requiredAAIKeys.add("is_closed_loop_disabled");
 
 125         requiredAAIKeys.add(VM_NAME);
 
 128     public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
 
 129         this.closedLoopControlName = closedLoopControlName;
 
 130         this.requestID = requestID;
 
 133     public String getClosedLoopControlName() {
 
 134         return closedLoopControlName;
 
 137     public String getControlLoopResult() {
 
 138         return controlLoopResult;
 
 141     public void setControlLoopResult(String controlLoopResult) {
 
 142         this.controlLoopResult = controlLoopResult;
 
 145     public Integer getNumOnsets() {
 
 149     public void setNumOnsets(Integer numOnsets) {
 
 150         this.numOnsets = numOnsets;
 
 153     public Integer getNumAbatements() {
 
 154         return numAbatements;
 
 157     public void setNumAbatements(Integer numAbatements) {
 
 158         this.numAbatements = numAbatements;
 
 161     public boolean isActivated() {
 
 165     public void setActivated(boolean isActivated) {
 
 166         this.isActivated = isActivated;
 
 169     public boolean useTargetLock() {
 
 170         return useTargetLock();
 
 173     public void setUseTargetLock(boolean useTargetLock) {
 
 174         this.useTargetLock = useTargetLock;
 
 177     public VirtualControlLoopEvent getOnsetEvent() {
 
 181     public VirtualControlLoopEvent getAbatementEvent() {
 
 182         return this.abatement;
 
 185     public ControlLoopProcessor getProcessor() {
 
 186         return this.processor;
 
 189     public UUID getRequestID() {
 
 194      * Activate a control loop event.
 
 196      * @param event the event
 
 197      * @return the VirtualControlLoopNotification
 
 199     public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
 
 200         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
 
 203             // This method should ONLY be called ONCE
 
 205             if (this.isActivated) {
 
 206                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
 
 209             // Syntax check the event
 
 211             checkEventSyntax(event);
 
 214             // At this point we are good to go with this event
 
 219             notification.setNotification(ControlLoopNotificationType.ACTIVE);
 
 221             // Set ourselves as active
 
 223             this.isActivated = true;
 
 224         } catch (ControlLoopException e) {
 
 225             logger.error("{}: activate by event threw: ", this, e);
 
 226             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 227             notification.setMessage(e.getMessage());
 
 233      * Activate a control loop event.
 
 235      * @param yamlSpecification the yaml specification
 
 236      * @param event the event
 
 237      * @return the VirtualControlLoopNotification
 
 239     public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
 
 240         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
 
 243             // This method should ONLY be called ONCE
 
 245             if (this.isActivated) {
 
 246                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
 
 249             // Syntax check the event
 
 251             checkEventSyntax(event);
 
 256             if (yamlSpecification == null || yamlSpecification.length() < 1) {
 
 257                 throw new ControlLoopException("yaml specification is null or 0 length");
 
 259         } catch (ControlLoopException e) {
 
 260             logger.error("{}: activate by YAML specification and event threw: ", this, e);
 
 261             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 262             notification.setMessage(e.getMessage());
 
 266         String decodedYaml = null;
 
 268             decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
 
 269             if (decodedYaml != null && decodedYaml.length() > 0) {
 
 270                 yamlSpecification = decodedYaml;
 
 272         } catch (UnsupportedEncodingException e) {
 
 273             logger.error("{}: YAML decode in activate by YAML specification and event threw: ", this, e);
 
 274             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 275             notification.setMessage(e.getMessage());
 
 281             // Parse the YAML specification
 
 283             this.processor = new ControlLoopProcessor(yamlSpecification);
 
 285             // At this point we are good to go with this event
 
 292             notification.setNotification(ControlLoopNotificationType.ACTIVE);
 
 294             // Set ourselves as active
 
 296             this.isActivated = true;
 
 297         } catch (ControlLoopException e) {
 
 298             logger.error("{}: activate by YAML specification and event threw: ", this, e);
 
 299             notification.setNotification(ControlLoopNotificationType.REJECTED);
 
 300             notification.setMessage(e.getMessage());
 
 306      * Check if the control loop is final.
 
 308      * @return a VirtualControlLoopNotification if the control loop is final, otherwise
 
 309      *         <code>null</code> is returned
 
 310      * @throws ControlLoopException if an error occurs
 
 312     public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
 
 314         // Check if they activated us
 
 316         if (!this.isActivated) {
 
 317             throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
 
 320         // Make sure we are expecting this call.
 
 322         if (this.onset == null) {
 
 323             throw new ControlLoopException("No onset event for ControlLoopEventManager.");
 
 326         // Ok, start creating the notification
 
 328         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
 
 330         // Check if the overall control loop has timed out
 
 332         if (this.isControlLoopTimedOut()) {
 
 334             // Yes we have timed out
 
 336             notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 337             notification.setMessage("Control Loop timed out");
 
 338             notification.getHistory().addAll(this.controlLoopHistory);
 
 342         // Check if the current policy is Final
 
 344         FinalResult result = this.processor.checkIsCurrentPolicyFinal();
 
 345         if (result == null) {
 
 347             // we are not at a final result
 
 353             case FINAL_FAILURE_EXCEPTION:
 
 354                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 355                 notification.setMessage("Exception in processing closed loop");
 
 358             case FINAL_FAILURE_RETRIES:
 
 359             case FINAL_FAILURE_TIMEOUT:
 
 360             case FINAL_FAILURE_GUARD:
 
 361                 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 364                 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
 
 367                 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
 
 373         // Be sure to add all the history
 
 375         notification.getHistory().addAll(this.controlLoopHistory);
 
 380      * Process the control loop.
 
 382      * @return a ControlLoopOperationManager
 
 383      * @throws ControlLoopException if an error occurs
 
 384      * @throws AaiException if an error occurs retrieving information from A&AI
 
 386     public ControlLoopOperationManager processControlLoop() throws ControlLoopException, AaiException {
 
 388         // Check if they activated us
 
 390         if (!this.isActivated) {
 
 391             throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
 
 394         // Make sure we are expecting this call.
 
 396         if (this.onset == null) {
 
 397             throw new ControlLoopException("No onset event for ControlLoopEventManager.");
 
 400         // Is there a current operation?
 
 402         if (this.currentOperation != null) {
 
 404             // Throw an exception, or simply return the current operation?
 
 406             throw new ControlLoopException("Already working an Operation, do not call this method.");
 
 409         // Ensure we are not FINAL
 
 411         VirtualControlLoopNotification notification = this.isControlLoopFinal();
 
 412         if (notification != null) {
 
 414             // This is weird, we require them to call the isControlLoopFinal() method first
 
 416             // We should really abstract this and avoid throwing an exception, because it really
 
 417             // isn't an exception.
 
 419             throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
 
 422         // Not final so get the policy that needs to be worked on.
 
 424         Policy policy = this.processor.getCurrentPolicy();
 
 425         if (policy == null) {
 
 426             throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
 
 429         // And setup an operation
 
 431         this.lastOperationManager = this.currentOperation;
 
 432         this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
 
 436         return this.currentOperation;
 
 440      * Finish an operation.
 
 442      * @param operation the operation
 
 444     public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
 
 446         // Verify we have a current operation
 
 448         if (this.currentOperation != null) {
 
 450             // Validate they are finishing the current operation
 
 451             // PLD - this is simply comparing the policy. Do we want to equals the whole object?
 
 453             if (this.currentOperation.policy.equals(operation.policy)) {
 
 454                 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(),
 
 455                         this.currentOperation.getOperationResult());
 
 459                 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
 
 461                 // Move to the next Policy
 
 463                 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
 
 465                 // Just null this out
 
 467                 this.lastOperationManager = this.currentOperation;
 
 468                 this.currentOperation = null;
 
 470                 // TODO: Release our lock
 
 474             logger.debug("Cannot finish current operation {} does not match given operation {}",
 
 475                     this.currentOperation.policy, operation.policy);
 
 478         throw new ControlLoopException("No operation to finish.");
 
 482      * Obtain a lock for the current operation.
 
 484      * @return the lock result
 
 485      * @throws ControlLoopException if an error occurs
 
 487     public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
 
 491         if (this.currentOperation == null) {
 
 492             throw new ControlLoopException("Do not have a current operation.");
 
 495         // Not using target locks? Create and return a lock w/o actually locking.
 
 497         if (!this.useTargetLock) {
 
 498             TargetLock lock = PolicyGuard.createTargetLock(this.currentOperation.policy.getTarget().getType(),
 
 499                                                            this.currentOperation.getTargetEntity(),
 
 500                                                            this.onset.getRequestId(), this);
 
 501             this.targetLock = lock;
 
 502             LockResult<GuardResult, TargetLock> lockResult = LockResult.createLockResult(GuardResult.LOCK_ACQUIRED, lock);
 
 506         // Have we acquired it already?
 
 508         if (this.targetLock != null) {
 
 510             // TODO: Make sure the current lock is for the same target.
 
 511             // Currently, it should be. But in the future it may not.
 
 513             GuardResult result = PolicyGuard.lockTarget(targetLock,
 
 514                             this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
 
 515             return new LockResult<>(result, this.targetLock);
 
 520             LockResult<GuardResult, TargetLock> lockResult =
 
 521                     PolicyGuard.lockTarget(this.currentOperation.policy.getTarget().getType(),
 
 522                             this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this,
 
 523                             this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
 
 527             if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
 
 529                 // Yes, let's save it
 
 531                 this.targetLock = lockResult.getB();
 
 538      * Release the lock for the current operation.
 
 540      * @return the target lock
 
 542     public synchronized TargetLock unlockCurrentOperation() {
 
 543         if (this.targetLock == null) {
 
 547         TargetLock returnLock = this.targetLock;
 
 548         this.targetLock = null;
 
 550         // if using target locking unlock before returning
 
 552         if (this.useTargetLock) {
 
 553             PolicyGuard.unlockTarget(returnLock);
 
 556         // always return the old target lock so rules can retract it
 
 560     public enum NEW_EVENT_STATUS {
 
 561         FIRST_ONSET, SUBSEQUENT_ONSET, FIRST_ABATEMENT, SUBSEQUENT_ABATEMENT, SYNTAX_ERROR;
 
 565      * An event onset/abatement.
 
 567      * @param event the event
 
 569      * @throws AaiException if an error occurs retrieving information from A&AI
 
 571     public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) throws AaiException {
 
 573             this.checkEventSyntax(event);
 
 574             if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ONSET) {
 
 576                 // Check if this is our original ONSET
 
 578                 if (event.equals(this.onset)) {
 
 580                     // Query A&AI if needed
 
 587                     return NEW_EVENT_STATUS.FIRST_ONSET;
 
 590                 // Log that we got an onset
 
 593                 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
 
 594             } else if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
 
 596                 // Have we already got an abatement?
 
 598                 if (this.abatement == null) {
 
 602                     this.abatement = event;
 
 604                     // Keep track that we received another
 
 606                     this.numAbatements++;
 
 610                     return NEW_EVENT_STATUS.FIRST_ABATEMENT;
 
 613                     // Keep track that we received another
 
 615                     this.numAbatements++;
 
 619                     return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
 
 622         } catch (ControlLoopException e) {
 
 623             logger.error("{}: onNewEvent threw: ", this, e);
 
 625         return NEW_EVENT_STATUS.SYNTAX_ERROR;
 
 630      * Commit the abatement to the history database.
 
 632      * @param message the abatement message
 
 633      * @param outcome the abatement outcome
 
 635     public void commitAbatement(String message, String outcome) {
 
 636         if (this.lastOperationManager == null) {
 
 637             logger.error("{}: commitAbatement: no operation manager", this);
 
 641             this.lastOperationManager.commitAbatement(message,outcome);          
 
 642         } catch (NoSuchElementException e) {
 
 643             logger.error("{}: commitAbatement threw an exception ", this, e);
 
 649      * Set the control loop time out.
 
 651      * @return a VirtualControlLoopNotification
 
 653     public VirtualControlLoopNotification setControlLoopTimedOut() {
 
 654         this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
 
 655         VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
 
 656         notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
 
 657         notification.setMessage("Control Loop timed out");
 
 658         notification.getHistory().addAll(this.controlLoopHistory);
 
 662     public boolean isControlLoopTimedOut() {
 
 663         return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
 
 667      * Get the control loop timeout.
 
 669      * @param defaultTimeout the default timeout
 
 670      * @return the timeout
 
 672     public int getControlLoopTimeout(Integer defaultTimeout) {
 
 673         if (this.processor != null && this.processor.getControlLoop() != null) {
 
 674             return this.processor.getControlLoop().getTimeout();
 
 676         if (defaultTimeout != null) {
 
 677             return defaultTimeout;
 
 682     public AaiGetVnfResponse getVnfResponse() {
 
 686     public AaiGetVserverResponse getVserverResponse() {
 
 687         return vserverResponse;
 
 691      * Check an event syntax.
 
 693      * @param event the event syntax
 
 694      * @throws ControlLoopException if an error occurs
 
 696     public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
 
 697         if (event.getClosedLoopEventStatus() == null
 
 698                 || (event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET
 
 699                         && event.getClosedLoopEventStatus() != ControlLoopEventStatus.ABATED)) {
 
 700             throw new ControlLoopException("Invalid value in closedLoopEventStatus");
 
 702         if (event.getClosedLoopControlName() == null || event.getClosedLoopControlName().length() < 1) {
 
 703             throw new ControlLoopException("No control loop name");
 
 705         if (event.getRequestId() == null) {
 
 706             throw new ControlLoopException("No request ID");
 
 708         if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
 
 711         if (event.getTarget() == null || event.getTarget().length() < 1) {
 
 712             throw new ControlLoopException("No target field");
 
 713         } else if (!VM_NAME.equalsIgnoreCase(event.getTarget()) && !VNF_NAME.equalsIgnoreCase(event.getTarget())
 
 714                 && !VSERVER_VSERVER_NAME.equalsIgnoreCase(event.getTarget())
 
 715                 && !GENERIC_VNF_VNF_ID.equalsIgnoreCase(event.getTarget())
 
 716                 && !GENERIC_VNF_VNF_NAME.equalsIgnoreCase(event.getTarget())) {
 
 717             throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
 
 719         if (event.getAai() == null) {
 
 720             throw new ControlLoopException("AAI is null");
 
 722         if (event.getAai().get(GENERIC_VNF_VNF_ID) == null && event.getAai().get(VSERVER_VSERVER_NAME) == null
 
 723                 && event.getAai().get(GENERIC_VNF_VNF_NAME) == null) {
 
 724             throw new ControlLoopException(
 
 725                     "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
 
 730      * Query A&AI for an event.
 
 732      * @param event the event
 
 733      * @throws AaiException if an error occurs retrieving information from A&AI
 
 735     public void queryAai(VirtualControlLoopEvent event) throws AaiException {
 
 737         Map<String, String> aai = event.getAai();
 
 739         if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
 
 741             if (isClosedLoopDisabled(event)) {
 
 742                 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
 
 745             if (isProvStatusInactive(event)) {
 
 746                 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
 
 749             // no need to query, as we already have the data
 
 753         if (vnfResponse != null || vserverResponse != null) {
 
 754             // query has already been performed
 
 759             if (aai.containsKey(GENERIC_VNF_VNF_ID) || aai.containsKey(GENERIC_VNF_VNF_NAME)) {
 
 760                 vnfResponse = getAAIVnfInfo(event);
 
 761                 processVNFResponse(vnfResponse, aai.containsKey(GENERIC_VNF_VNF_ID));
 
 762             } else if (aai.containsKey(VSERVER_VSERVER_NAME)) {
 
 763                 vserverResponse = getAAIVserverInfo(event);
 
 764                 processVServerResponse(vserverResponse);
 
 766         } catch (AaiException e) {
 
 767             logger.error(QUERY_AAI_ERROR_MSG, e);
 
 769         } catch (Exception e) {
 
 770             logger.error(QUERY_AAI_ERROR_MSG, e);
 
 771             throw new AaiException(QUERY_AAI_ERROR_MSG + e.toString());
 
 776      * Process a response from A&AI for a VNF.
 
 778      * @param aaiResponse the response from A&AI
 
 779      * @param queryByVnfId <code>true</code> if the query was based on vnf-id,
 
 780      *        <code>false</code> if the query was based on vnf-name
 
 781      * @throws AaiException if an error occurs processing the response
 
 783     private static void processVNFResponse(AaiGetVnfResponse aaiResponse, boolean queryByVNFID) throws AaiException {
 
 784         String queryTypeString = (queryByVNFID ? "vnf-id" : "vnf-name");
 
 786         if (aaiResponse == null) {
 
 787             throw new AaiException("AAI Response is null (query by " + queryTypeString + ")");
 
 789         if (aaiResponse.getRequestError() != null) {
 
 790             throw new AaiException("AAI Responded with a request error (query by " + queryTypeString + ")");
 
 793         if (aaiResponse.getIsClosedLoopDisabled()) {
 
 794             throw new AaiException("is-closed-loop-disabled is set to true (query by " + queryTypeString + ")");
 
 797         if (!PROV_STATUS_ACTIVE.equals(aaiResponse.getProvStatus())) {
 
 798             throw new AaiException("prov-status is not ACTIVE (query by " + queryTypeString + ")");
 
 803      * Process a response from A&AI for a VServer.
 
 805      * @param aaiResponse the response from A&AI
 
 806      * @throws AaiException if an error occurs processing the response
 
 808     private static void processVServerResponse(AaiGetVserverResponse aaiResponse) throws AaiException {
 
 809         if (aaiResponse == null) {
 
 810             throw new AaiException("AAI Response is null (query by vserver-name)");
 
 812         if (aaiResponse.getRequestError() != null) {
 
 813             throw new AaiException("AAI Responded with a request error (query by vserver-name)");
 
 816         List<AaiNqVServer> lst = aaiResponse.getVserver();
 
 821         AaiNqVServer svr = lst.get(0);
 
 822         if (svr.getIsClosedLoopDisabled()) {
 
 823             throw new AaiException("is-closed-loop-disabled is set to true (query by vserver-name)");
 
 826         if (!PROV_STATUS_ACTIVE.equals(svr.getProvStatus())) {
 
 827             throw new AaiException("prov-status is not ACTIVE (query by vserver-name)");
 
 832      * Is closed loop disabled for an event.
 
 834      * @param event the event
 
 835      * @return <code>true</code> if the control loop is disabled, <code>false</code>
 
 838     public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
 
 839         Map<String, String> aai = event.getAai();
 
 840         return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
 
 841                         || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)));
 
 845      * Does provisioning status, for an event, have a value other than ACTIVE.
 
 847      * @param event the event
 
 848      * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null},
 
 849      *         {@code false} otherwise
 
 851     protected static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
 
 852         Map<String, String> aai = event.getAai();
 
 853         return (!PROV_STATUS_ACTIVE.equals(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
 
 854                         || !PROV_STATUS_ACTIVE.equals(aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
 
 858      * Determines the boolean value represented by the given AAI field value.
 
 860      * @param aaiValue value to be examined
 
 861      * @return the boolean value represented by the field value, or {@code false} if the
 
 862      *         value is {@code null}
 
 864     protected static boolean isAaiTrue(String aaiValue) {
 
 865         return ("true".equalsIgnoreCase(aaiValue) || "T".equalsIgnoreCase(aaiValue) || "yes".equalsIgnoreCase(aaiValue)
 
 866                         || "Y".equalsIgnoreCase(aaiValue));
 
 870      * Get the A&AI VService information for an event.
 
 872      * @param event the event
 
 873      * @return a AaiGetVserverResponse
 
 874      * @throws ControlLoopException if an error occurs
 
 876     public static AaiGetVserverResponse getAAIVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
 
 877         UUID requestId = event.getRequestId();
 
 878         AaiGetVserverResponse response = null;
 
 879         String vserverName = event.getAai().get(VSERVER_VSERVER_NAME);
 
 882             if (vserverName != null) {
 
 883                 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
 
 884                 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME);
 
 885                 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASSWD);
 
 886                 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
 
 887                 String url = aaiHostUrl + aaiGetQueryByVserver;
 
 888                 logger.info("AAI Host URL by VServer: {}", url);
 
 889                 response = new AaiManager(new RESTManager()).getQueryByVserverName(url, aaiUser, aaiPassword, requestId,
 
 892         } catch (Exception e) {
 
 893             logger.error("getAAIVserverInfo exception: ", e);
 
 894             throw new ControlLoopException("Exception in getAAIVserverInfo: ", e);
 
 901      * Get A&AI VNF information for an event.
 
 903      * @param event the event
 
 904      * @return a AaiGetVnfResponse
 
 905      * @throws ControlLoopException if an error occurs
 
 907     public static AaiGetVnfResponse getAAIVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
 
 908         UUID requestId = event.getRequestId();
 
 909         AaiGetVnfResponse response = null;
 
 910         String vnfName = event.getAai().get(GENERIC_VNF_VNF_NAME);
 
 911         String vnfId = event.getAai().get(GENERIC_VNF_VNF_ID);
 
 913         String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
 
 914         String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME);
 
 915         String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASSWD);
 
 918             if (vnfName != null) {
 
 919                 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
 
 920                 String url = aaiHostUrl + aaiGetQueryByVnfName;
 
 921                 logger.info("AAI Host URL by VNF name: {}", url);
 
 922                 response = new AaiManager(new RESTManager()).getQueryByVnfName(url, aaiUser, aaiPassword, requestId,
 
 924             } else if (vnfId != null) {
 
 925                 String aaiGetQueryByVnfId = "/aai/v11/network/generic-vnfs/generic-vnf/";
 
 926                 String url = aaiHostUrl + aaiGetQueryByVnfId;
 
 927                 logger.info("AAI Host URL by VNF ID: {}", url);
 
 929                         new AaiManager(new RESTManager()).getQueryByVnfId(url, aaiUser, aaiPassword, requestId, vnfId);
 
 931         } catch (Exception e) {
 
 932             logger.error("getAAIVnfInfo exception: ", e);
 
 933             throw new ControlLoopException("Exception in getAAIVnfInfo: ", e);
 
 940      * Gets the output from the AAI vserver named-query, using the cache, if appropriate.
 
 941      * @return output from the AAI vserver named-query
 
 943     public AaiNqResponseWrapper getNqVserverFromAai() {
 
 944         if (nqVserverResponse != null) {
 
 946             return nqVserverResponse;
 
 949         String vserverName = onset.getAai().get(VSERVER_VSERVER_NAME);
 
 950         if (vserverName == null) {
 
 951             logger.warn("Missing vserver-name for AAI request {}", onset.getRequestId());
 
 955         // create AAI named-query request with UUID started with ""
 
 956         AaiNqRequest aaiNqRequest = new AaiNqRequest();
 
 957         AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
 
 958         AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
 
 959         final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
 
 962         aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
 
 963         aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
 
 964         aaiNqRequest.setQueryParameters(aaiNqQueryParam);
 
 968         Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
 
 969         Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
 
 970         aaiNqInstanceFilterMapItem.put("vserver-name", vserverName);
 
 971         aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
 
 972         aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
 
 973         aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
 
 975         if (logger.isDebugEnabled()) {
 
 976             logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
 
 979         AaiNqResponse aaiNqResponse = new AaiManager(new RESTManager()).postQuery(getPeManagerEnvProperty(AAI_URL),
 
 980                 getPeManagerEnvProperty(AAI_USERNAME), getPeManagerEnvProperty(AAI_PASSWD), aaiNqRequest,
 
 981                 onset.getRequestId());
 
 983         // Check AAI response
 
 984         if (aaiNqResponse == null) {
 
 985             logger.warn("No response received from AAI for request {}", aaiNqRequest);
 
 989         // Create AAINQResponseWrapper
 
 990         nqVserverResponse = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
 
 992         if (logger.isDebugEnabled()) {
 
 993             logger.debug("AAI Named Query Response: ");
 
 994             logger.debug(Serialization.gsonPretty.toJson(nqVserverResponse.getAaiNqResponse()));
 
 997         return nqVserverResponse;
 
1001      * This method reads and validates environmental properties coming from the policy engine. Null
 
1002      * properties cause an {@link IllegalArgumentException} runtime exception to be thrown
 
1004      * @param enginePropertyName the name of the parameter to retrieve
 
1005      * @return the property value
 
1007     private static String getPeManagerEnvProperty(String enginePropertyName) {
 
1008         String enginePropertyValue = PolicyEngine.manager.getEnvironmentProperty(enginePropertyName);
 
1009         if (enginePropertyValue == null) {
 
1010             throw new IllegalArgumentException("The value of policy engine manager environment property \""
 
1011                     + enginePropertyName + "\" may not be null");
 
1013         return enginePropertyValue;
 
1017     public boolean isActive() {
 
1023     public boolean releaseLock() {
 
1029     public String toString() {
 
1030         return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestID=" + requestID
 
1031                 + ", processor=" + processor + ", onset=" + (onset != null ? onset.getRequestId() : "null")
 
1032                 + ", numOnsets=" + numOnsets + ", numAbatements=" + numAbatements + ", isActivated=" + isActivated
 
1033                 + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";