2 * ============LICENSE_START=======================================================
3 * controlloop event manager
4 * ================================================================================
5 * Copyright (C) 2017-2019 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.Arrays;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.LinkedList;
33 import java.util.List;
35 import java.util.NoSuchElementException;
37 import java.util.UUID;
38 import java.util.stream.Collectors;
39 import org.apache.commons.lang3.StringUtils;
40 import org.onap.policy.aai.AaiCqResponse;
41 import org.onap.policy.aai.AaiGetVnfResponse;
42 import org.onap.policy.aai.AaiGetVserverResponse;
43 import org.onap.policy.aai.AaiManager;
44 import org.onap.policy.aai.AaiNqInstanceFilters;
45 import org.onap.policy.aai.AaiNqNamedQuery;
46 import org.onap.policy.aai.AaiNqQueryParameters;
47 import org.onap.policy.aai.AaiNqRequest;
48 import org.onap.policy.aai.AaiNqResponse;
49 import org.onap.policy.aai.AaiNqResponseWrapper;
50 import org.onap.policy.aai.AaiNqVServer;
51 import org.onap.policy.aai.util.AaiException;
52 import org.onap.policy.controlloop.ControlLoopEventStatus;
53 import org.onap.policy.controlloop.ControlLoopException;
54 import org.onap.policy.controlloop.ControlLoopNotificationType;
55 import org.onap.policy.controlloop.ControlLoopOperation;
56 import org.onap.policy.controlloop.VirtualControlLoopEvent;
57 import org.onap.policy.controlloop.VirtualControlLoopNotification;
58 import org.onap.policy.controlloop.policy.FinalResult;
59 import org.onap.policy.controlloop.policy.Policy;
60 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
61 import org.onap.policy.drools.system.PolicyEngine;
62 import org.onap.policy.guard.GuardResult;
63 import org.onap.policy.guard.LockCallback;
64 import org.onap.policy.guard.PolicyGuard;
65 import org.onap.policy.guard.PolicyGuard.LockResult;
66 import org.onap.policy.guard.TargetLock;
67 import org.onap.policy.rest.RestManager;
68 import org.onap.policy.so.util.Serialization;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 public class ControlLoopEventManager implements LockCallback, Serializable {
73 public static final String PROV_STATUS_ACTIVE = "ACTIVE";
74 private static final String VM_NAME = "VM_NAME";
75 private static final String VNF_NAME = "VNF_NAME";
76 public static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
77 public static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
78 public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
79 public static final String GENERIC_VNF_IS_CLOSED_LOOP_DISABLED = "generic-vnf.is-closed-loop-disabled";
80 public static final String VSERVER_IS_CLOSED_LOOP_DISABLED = "vserver.is-closed-loop-disabled";
81 public static final String GENERIC_VNF_PROV_STATUS = "generic-vnf.prov-status";
82 public static final String VSERVER_PROV_STATUS = "vserver.prov-status";
84 public static final String AAI_URL = "aai.url";
85 public static final String AAI_USERNAME_PROPERTY = "aai.username";
86 public static final String AAI_PASS_PROPERTY = "aai.password";
88 private static final String QUERY_AAI_ERROR_MSG = "Exception from queryAai: ";
91 * Additional time, in seconds, to add to a "lock" request. This ensures that the lock won't expire right before an
92 * operation completes.
94 private static final int ADDITIONAL_LOCK_SEC = 60;
96 private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
98 private static final long serialVersionUID = -1216568161322872641L;
100 private static final Set<String> VALID_TARGETS;
103 VALID_TARGETS = Collections.unmodifiableSet(new HashSet<>(
104 Arrays.asList(VM_NAME, VNF_NAME, VSERVER_VSERVER_NAME,
105 GENERIC_VNF_VNF_ID, GENERIC_VNF_VNF_NAME)
106 .stream().map(String::toLowerCase).collect(Collectors.toList())));
109 public final String closedLoopControlName;
110 private final UUID requestId;
112 private String controlLoopResult;
113 private ControlLoopProcessor processor = null;
114 private VirtualControlLoopEvent onset;
115 private Integer numOnsets = 0;
116 private Integer numAbatements = 0;
117 private VirtualControlLoopEvent abatement;
118 private FinalResult controlLoopTimedOut = null;
120 private boolean isActivated = false;
121 private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
122 private ControlLoopOperationManager currentOperation = null;
123 private ControlLoopOperationManager lastOperationManager = null;
124 private transient TargetLock targetLock = null;
125 private AaiGetVnfResponse vnfResponse = null;
126 private AaiGetVserverResponse vserverResponse = null;
127 private boolean useTargetLock = true;
130 * Wrapper for AAI vserver named-query response. This is initialized in a lazy fashion.
132 private AaiNqResponseWrapper nqVserverResponse = null;
134 private static Collection<String> requiredAAIKeys = new ArrayList<>();
137 requiredAAIKeys.add("AICVServerSelfLink");
138 requiredAAIKeys.add("AICIdentity");
139 requiredAAIKeys.add("is_closed_loop_disabled");
140 requiredAAIKeys.add(VM_NAME);
143 public ControlLoopEventManager(String closedLoopControlName, UUID requestId) {
144 this.closedLoopControlName = closedLoopControlName;
145 this.requestId = requestId;
148 public String getClosedLoopControlName() {
149 return closedLoopControlName;
152 public String getControlLoopResult() {
153 return controlLoopResult;
156 public void setControlLoopResult(String controlLoopResult) {
157 this.controlLoopResult = controlLoopResult;
160 public Integer getNumOnsets() {
164 public void setNumOnsets(Integer numOnsets) {
165 this.numOnsets = numOnsets;
168 public Integer getNumAbatements() {
169 return numAbatements;
172 public void setNumAbatements(Integer numAbatements) {
173 this.numAbatements = numAbatements;
176 public boolean isActivated() {
180 public void setActivated(boolean isActivated) {
181 this.isActivated = isActivated;
184 public boolean useTargetLock() {
185 return useTargetLock();
188 public void setUseTargetLock(boolean useTargetLock) {
189 this.useTargetLock = useTargetLock;
192 public VirtualControlLoopEvent getOnsetEvent() {
196 public VirtualControlLoopEvent getAbatementEvent() {
197 return this.abatement;
200 public ControlLoopProcessor getProcessor() {
201 return this.processor;
204 public UUID getRequestId() {
209 * Activate a control loop event.
211 * @param event the event
212 * @return the VirtualControlLoopNotification
214 public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
215 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
218 // This method should ONLY be called ONCE
220 if (this.isActivated) {
221 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
224 // Syntax check the event
226 checkEventSyntax(event);
229 // At this point we are good to go with this event
234 notification.setNotification(ControlLoopNotificationType.ACTIVE);
236 // Set ourselves as active
238 this.isActivated = true;
239 } catch (ControlLoopException e) {
240 logger.error("{}: activate by event threw: ", this, e);
241 notification.setNotification(ControlLoopNotificationType.REJECTED);
242 notification.setMessage(e.getMessage());
248 * Activate a control loop event.
250 * @param yamlSpecification the yaml specification
251 * @param event the event
252 * @return the VirtualControlLoopNotification
254 public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
255 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
258 // This method should ONLY be called ONCE
260 if (this.isActivated) {
261 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
264 // Syntax check the event
266 checkEventSyntax(event);
271 if (yamlSpecification == null || yamlSpecification.length() < 1) {
272 throw new ControlLoopException("yaml specification is null or 0 length");
274 } catch (ControlLoopException e) {
275 logger.error("{}: activate by YAML specification and event threw: ", this, e);
276 notification.setNotification(ControlLoopNotificationType.REJECTED);
277 notification.setMessage(e.getMessage());
281 String decodedYaml = null;
283 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
284 if (decodedYaml != null && decodedYaml.length() > 0) {
285 yamlSpecification = decodedYaml;
287 } catch (UnsupportedEncodingException e) {
288 logger.error("{}: YAML decode in activate by YAML specification and event threw: ", this, e);
289 notification.setNotification(ControlLoopNotificationType.REJECTED);
290 notification.setMessage(e.getMessage());
296 // Parse the YAML specification
298 this.processor = new ControlLoopProcessor(yamlSpecification);
300 // At this point we are good to go with this event
307 notification.setNotification(ControlLoopNotificationType.ACTIVE);
309 // Set ourselves as active
311 this.isActivated = true;
312 } catch (ControlLoopException e) {
313 logger.error("{}: activate by YAML specification and event threw: ", this, e);
314 notification.setNotification(ControlLoopNotificationType.REJECTED);
315 notification.setMessage(e.getMessage());
321 * Check if the control loop is final.
323 * @return a VirtualControlLoopNotification if the control loop is final, otherwise <code>null</code> is returned
324 * @throws ControlLoopException if an error occurs
326 public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
327 validateFinalControlLoop();
329 // Ok, start creating the notification
331 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
333 // Check if the overall control loop has timed out
335 if (this.isControlLoopTimedOut()) {
337 // Yes we have timed out
339 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
340 notification.setMessage("Control Loop timed out");
341 notification.getHistory().addAll(this.controlLoopHistory);
345 // Check if the current policy is Final
347 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
348 if (result == null) {
350 // we are not at a final result
356 case FINAL_FAILURE_EXCEPTION:
357 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
358 notification.setMessage("Exception in processing closed loop");
361 case FINAL_FAILURE_RETRIES:
362 case FINAL_FAILURE_TIMEOUT:
363 case FINAL_FAILURE_GUARD:
364 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
367 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
370 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
376 // Be sure to add all the history
378 notification.getHistory().addAll(this.controlLoopHistory);
382 private void validateFinalControlLoop() throws ControlLoopException {
384 // Check if they activated us
386 if (!this.isActivated) {
387 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
390 // Make sure we are expecting this call.
392 if (this.onset == null) {
393 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
398 * Process the control loop.
400 * @return a ControlLoopOperationManager
401 * @throws ControlLoopException if an error occurs
403 public ControlLoopOperationManager processControlLoop() throws ControlLoopException {
404 validateFinalControlLoop();
406 // Is there a current operation?
408 if (this.currentOperation != null) {
410 // Throw an exception, or simply return the current operation?
412 throw new ControlLoopException("Already working an Operation, do not call this method.");
415 // Ensure we are not FINAL
417 VirtualControlLoopNotification notification = this.isControlLoopFinal();
418 if (notification != null) {
420 // This is weird, we require them to call the isControlLoopFinal() method first
422 // We should really abstract this and avoid throwing an exception, because it really
423 // isn't an exception.
425 throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
428 // Not final so get the policy that needs to be worked on.
430 Policy policy = this.processor.getCurrentPolicy();
431 if (policy == null) {
432 throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
435 // And setup an operation
437 this.lastOperationManager = this.currentOperation;
438 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
442 return this.currentOperation;
446 * Finish an operation.
448 * @param operation the operation
450 public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
452 // Verify we have a current operation
454 if (this.currentOperation != null) {
456 // Validate they are finishing the current operation
457 // PLD - this is simply comparing the policy. Do we want to equals the whole object?
459 if (this.currentOperation.policy.equals(operation.policy)) {
460 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(),
461 this.currentOperation.getOperationResult());
465 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
467 // Move to the next Policy
469 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
471 // Just null this out
473 this.lastOperationManager = this.currentOperation;
474 this.currentOperation = null;
476 // TODO: Release our lock
480 logger.debug("Cannot finish current operation {} does not match given operation {}",
481 this.currentOperation.policy, operation.policy);
484 throw new ControlLoopException("No operation to finish.");
488 * Obtain a lock for the current operation.
490 * @return the lock result
491 * @throws ControlLoopException if an error occurs
493 public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
497 if (this.currentOperation == null) {
498 throw new ControlLoopException("Do not have a current operation.");
501 // Not using target locks? Create and return a lock w/o actually locking.
503 if (!this.useTargetLock) {
504 TargetLock lock = PolicyGuard.createTargetLock(this.currentOperation.policy.getTarget().getType(),
505 this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this);
506 this.targetLock = lock;
507 return LockResult.createLockResult(GuardResult.LOCK_ACQUIRED, lock);
510 // Have we acquired it already?
512 if (this.targetLock != null) {
514 // TODO: Make sure the current lock is for the same target.
515 // Currently, it should be. But in the future it may not.
517 GuardResult result = PolicyGuard.lockTarget(targetLock,
518 this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
519 return new LockResult<>(result, this.targetLock);
524 LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
525 this.currentOperation.policy.getTarget().getType(), this.currentOperation.getTargetEntity(),
526 this.onset.getRequestId(), this, this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
530 if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
532 // Yes, let's save it
534 this.targetLock = lockResult.getB();
541 * Release the lock for the current operation.
543 * @return the target lock
545 public synchronized TargetLock unlockCurrentOperation() {
546 if (this.targetLock == null) {
550 TargetLock returnLock = this.targetLock;
551 this.targetLock = null;
553 // if using target locking unlock before returning
555 if (this.useTargetLock) {
556 PolicyGuard.unlockTarget(returnLock);
559 // always return the old target lock so rules can retract it
563 public enum NewEventStatus {
564 FIRST_ONSET, SUBSEQUENT_ONSET, FIRST_ABATEMENT, SUBSEQUENT_ABATEMENT, SYNTAX_ERROR;
568 * An event onset/abatement.
570 * @param event the event
572 * @throws AaiException if an error occurs retrieving information from A&AI
574 public NewEventStatus onNewEvent(VirtualControlLoopEvent event) throws AaiException {
576 this.checkEventSyntax(event);
577 if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ONSET) {
579 // Check if this is our original ONSET
581 if (event.equals(this.onset)) {
583 // Query A&AI if needed
590 return NewEventStatus.FIRST_ONSET;
593 // Log that we got an onset
596 return NewEventStatus.SUBSEQUENT_ONSET;
597 } else if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
599 // Have we already got an abatement?
601 if (this.abatement == null) {
605 this.abatement = event;
607 // Keep track that we received another
609 this.numAbatements++;
613 return NewEventStatus.FIRST_ABATEMENT;
616 // Keep track that we received another
618 this.numAbatements++;
622 return NewEventStatus.SUBSEQUENT_ABATEMENT;
625 } catch (ControlLoopException e) {
626 logger.error("{}: onNewEvent threw: ", this, e);
628 return NewEventStatus.SYNTAX_ERROR;
633 * Commit the abatement to the history database.
635 * @param message the abatement message
636 * @param outcome the abatement outcome
638 public void commitAbatement(String message, String outcome) {
639 if (this.lastOperationManager == null) {
640 logger.error("{}: commitAbatement: no operation manager", this);
644 this.lastOperationManager.commitAbatement(message, outcome);
645 } catch (NoSuchElementException e) {
646 logger.error("{}: commitAbatement threw an exception ", this, e);
652 * Set the control loop time out.
654 * @return a VirtualControlLoopNotification
656 public VirtualControlLoopNotification setControlLoopTimedOut() {
657 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
658 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
659 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
660 notification.setMessage("Control Loop timed out");
661 notification.getHistory().addAll(this.controlLoopHistory);
665 public boolean isControlLoopTimedOut() {
666 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
670 * Get the control loop timeout.
672 * @param defaultTimeout the default timeout
673 * @return the timeout
675 public int getControlLoopTimeout(Integer defaultTimeout) {
676 if (this.processor != null && this.processor.getControlLoop() != null) {
677 Integer timeout = this.processor.getControlLoop().getTimeout();
678 if (timeout != null && timeout > 0) {
682 if (defaultTimeout != null) {
683 return defaultTimeout;
688 public AaiGetVnfResponse getVnfResponse() {
692 public AaiGetVserverResponse getVserverResponse() {
693 return vserverResponse;
697 * Check an event syntax.
699 * @param event the event syntax
700 * @throws ControlLoopException if an error occurs
702 public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
703 validateStatus(event);
704 if (StringUtils.isBlank(event.getClosedLoopControlName())) {
705 throw new ControlLoopException("No control loop name");
707 if (event.getRequestId() == null) {
708 throw new ControlLoopException("No request ID");
710 if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
713 if (StringUtils.isBlank(event.getTarget())) {
714 throw new ControlLoopException("No target field");
715 } else if (!VALID_TARGETS.contains(event.getTarget().toLowerCase())) {
716 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
718 validateAaiData(event);
721 private void validateStatus(VirtualControlLoopEvent event) throws ControlLoopException {
722 if (event.getClosedLoopEventStatus() == null
723 || (event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET
724 && event.getClosedLoopEventStatus() != ControlLoopEventStatus.ABATED)) {
725 throw new ControlLoopException("Invalid value in closedLoopEventStatus");
729 private void validateAaiData(VirtualControlLoopEvent event) throws ControlLoopException {
730 if (event.getAai() == null) {
731 throw new ControlLoopException("AAI is null");
733 if (event.getAai().get(GENERIC_VNF_VNF_ID) == null && event.getAai().get(VSERVER_VSERVER_NAME) == null
734 && event.getAai().get(GENERIC_VNF_VNF_NAME) == null) {
735 throw new ControlLoopException(
736 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
741 * Query A&AI for an event.
743 * @param event the event
744 * @throws AaiException if an error occurs retrieving information from A&AI
746 public void queryAai(VirtualControlLoopEvent event) throws AaiException {
748 Map<String, String> aai = event.getAai();
750 if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
752 if (isClosedLoopDisabled(event)) {
753 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
756 if (isProvStatusInactive(event)) {
757 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
760 // no need to query, as we already have the data
764 if (vnfResponse != null || vserverResponse != null) {
765 // query has already been performed
770 if (aai.containsKey(GENERIC_VNF_VNF_ID) || aai.containsKey(GENERIC_VNF_VNF_NAME)) {
771 vnfResponse = getAaiVnfInfo(event);
772 processVnfResponse(vnfResponse, aai.containsKey(GENERIC_VNF_VNF_ID));
773 } else if (aai.containsKey(VSERVER_VSERVER_NAME)) {
774 vserverResponse = getAaiVserverInfo(event);
775 processVServerResponse(vserverResponse);
777 } catch (AaiException e) {
778 logger.error(QUERY_AAI_ERROR_MSG, e);
780 } catch (Exception e) {
781 logger.error(QUERY_AAI_ERROR_MSG, e);
782 throw new AaiException(QUERY_AAI_ERROR_MSG + e.toString());
787 * Process a response from A&AI for a VNF.
789 * @param aaiResponse the response from A&AI
790 * @param queryByVnfId <code>true</code> if the query was based on vnf-id, <code>false</code> if the query was based
792 * @throws AaiException if an error occurs processing the response
794 private static void processVnfResponse(AaiGetVnfResponse aaiResponse, boolean queryByVnfId) throws AaiException {
795 String queryTypeString = (queryByVnfId ? "vnf-id" : "vnf-name");
797 if (aaiResponse == null) {
798 throw new AaiException("AAI Response is null (query by " + queryTypeString + ")");
800 if (aaiResponse.getRequestError() != null) {
801 throw new AaiException("AAI Responded with a request error (query by " + queryTypeString + ")");
804 if (aaiResponse.getIsClosedLoopDisabled()) {
805 throw new AaiException("is-closed-loop-disabled is set to true (query by " + queryTypeString + ")");
808 if (!PROV_STATUS_ACTIVE.equals(aaiResponse.getProvStatus())) {
809 throw new AaiException("prov-status is not ACTIVE (query by " + queryTypeString + ")");
814 * Process a response from A&AI for a VServer.
816 * @param aaiResponse the response from A&AI
817 * @throws AaiException if an error occurs processing the response
819 private static void processVServerResponse(AaiGetVserverResponse aaiResponse) throws AaiException {
820 if (aaiResponse == null) {
821 throw new AaiException("AAI Response is null (query by vserver-name)");
823 if (aaiResponse.getRequestError() != null) {
824 throw new AaiException("AAI Responded with a request error (query by vserver-name)");
827 List<AaiNqVServer> lst = aaiResponse.getVserver();
832 AaiNqVServer svr = lst.get(0);
833 if (svr.getIsClosedLoopDisabled()) {
834 throw new AaiException("is-closed-loop-disabled is set to true (query by vserver-name)");
837 if (!PROV_STATUS_ACTIVE.equals(svr.getProvStatus())) {
838 throw new AaiException("prov-status is not ACTIVE (query by vserver-name)");
843 * Is closed loop disabled for an event.
845 * @param event the event
846 * @return <code>true</code> if the control loop is disabled, <code>false</code> otherwise
848 public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
849 Map<String, String> aai = event.getAai();
850 return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
851 || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)));
855 * Does provisioning status, for an event, have a value other than ACTIVE.
857 * @param event the event
858 * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null}, {@code false} otherwise
860 protected static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
861 Map<String, String> aai = event.getAai();
862 return (!PROV_STATUS_ACTIVE.equals(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
863 || !PROV_STATUS_ACTIVE.equals(aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
867 * Determines the boolean value represented by the given AAI field value.
869 * @param aaiValue value to be examined
870 * @return the boolean value represented by the field value, or {@code false} if the value is {@code null}
872 protected static boolean isAaiTrue(String aaiValue) {
873 return ("true".equalsIgnoreCase(aaiValue) || "T".equalsIgnoreCase(aaiValue) || "yes".equalsIgnoreCase(aaiValue)
874 || "Y".equalsIgnoreCase(aaiValue));
878 * Get the A&AI VService information for an event.
880 * @param event the event
881 * @return a AaiGetVserverResponse
882 * @throws ControlLoopException if an error occurs
884 public static AaiGetVserverResponse getAaiVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
885 UUID requestId = event.getRequestId();
886 AaiGetVserverResponse response = null;
887 String vserverName = event.getAai().get(VSERVER_VSERVER_NAME);
890 if (vserverName != null) {
891 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
892 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME_PROPERTY);
893 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASS_PROPERTY);
894 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
895 String url = aaiHostUrl + aaiGetQueryByVserver;
896 logger.info("AAI Host URL by VServer: {}", url);
897 response = new AaiManager(new RestManager()).getQueryByVserverName(url, aaiUser, aaiPassword, requestId,
900 } catch (Exception e) {
901 logger.error("getAaiVserverInfo exception: ", e);
902 throw new ControlLoopException("Exception in getAaiVserverInfo: ", e);
909 * Get A&AI VNF information for an event.
911 * @param event the event
912 * @return a AaiGetVnfResponse
913 * @throws ControlLoopException if an error occurs
915 public static AaiGetVnfResponse getAaiVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
916 UUID requestId = event.getRequestId();
917 AaiGetVnfResponse response = null;
918 String vnfName = event.getAai().get(GENERIC_VNF_VNF_NAME);
919 String vnfId = event.getAai().get(GENERIC_VNF_VNF_ID);
921 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
922 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME_PROPERTY);
923 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASS_PROPERTY);
926 if (vnfName != null) {
927 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
928 String url = aaiHostUrl + aaiGetQueryByVnfName;
929 logger.info("AAI Host URL by VNF name: {}", url);
930 response = new AaiManager(new RestManager()).getQueryByVnfName(url, aaiUser, aaiPassword, requestId,
932 } else if (vnfId != null) {
933 String aaiGetQueryByVnfId = "/aai/v11/network/generic-vnfs/generic-vnf/";
934 String url = aaiHostUrl + aaiGetQueryByVnfId;
935 logger.info("AAI Host URL by VNF ID: {}", url);
937 new AaiManager(new RestManager()).getQueryByVnfId(url, aaiUser, aaiPassword, requestId, vnfId);
939 } catch (Exception e) {
940 logger.error("getAaiVnfInfo exception: ", e);
941 throw new ControlLoopException("Exception in getAaiVnfInfo: ", e);
948 * Gets the output from the AAI vserver named-query, using the cache, if appropriate.
950 * @return output from the AAI vserver named-query
952 public AaiNqResponseWrapper getNqVserverFromAai() {
953 if (nqVserverResponse != null) {
955 return nqVserverResponse;
958 String vserverName = onset.getAai().get(VSERVER_VSERVER_NAME);
959 if (vserverName == null) {
960 logger.warn("Missing vserver-name for AAI request {}", onset.getRequestId());
963 AaiNqRequest aaiNqRequest = getAaiNqRequest(vserverName);
965 if (logger.isDebugEnabled()) {
966 logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
969 AaiNqResponse aaiNqResponse = new AaiManager(new RestManager()).postQuery(getPeManagerEnvProperty(AAI_URL),
970 getPeManagerEnvProperty(AAI_USERNAME_PROPERTY), getPeManagerEnvProperty(AAI_PASS_PROPERTY),
971 aaiNqRequest, onset.getRequestId());
973 // Check AAI response
974 if (aaiNqResponse == null) {
975 logger.warn("No response received from AAI for request {}", aaiNqRequest);
979 // Create AAINQResponseWrapper
980 nqVserverResponse = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
982 if (logger.isDebugEnabled()) {
983 logger.debug("AAI Named Query Response: ");
984 logger.debug(Serialization.gsonPretty.toJson(nqVserverResponse.getAaiNqResponse()));
987 return nqVserverResponse;
991 * Gets an AAI Named Query Request object.
993 * @param vserverName vserver name.
994 * @return the AAI Named Query Request object.
996 public static AaiNqRequest getAaiNqRequest(String vserverName) {
997 // create AAI named-query request with UUID started with ""
998 AaiNqRequest aaiNqRequest = new AaiNqRequest();
999 AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
1000 AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
1001 final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
1004 aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
1005 aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
1006 aaiNqRequest.setQueryParameters(aaiNqQueryParam);
1010 Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
1011 Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
1012 aaiNqInstanceFilterMapItem.put("vserver-name", vserverName);
1013 aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
1014 aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
1015 aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
1016 return aaiNqRequest;
1020 * This method reads and validates environmental properties coming from the policy engine. Null properties cause an
1021 * {@link IllegalArgumentException} runtime exception to be thrown
1023 * @param enginePropertyName the name of the parameter to retrieve
1024 * @return the property value
1026 private static String getPeManagerEnvProperty(String enginePropertyName) {
1027 String enginePropertyValue = PolicyEngine.manager.getEnvironmentProperty(enginePropertyName);
1028 if (enginePropertyValue == null) {
1029 throw new IllegalArgumentException("The value of policy engine manager environment property \""
1030 + enginePropertyName + "\" may not be null");
1032 return enginePropertyValue;
1036 public boolean isActive() {
1042 public boolean releaseLock() {
1048 public String toString() {
1049 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestId=" + requestId
1050 + ", processor=" + processor + ", onset=" + (onset != null ? onset.getRequestId() : "null")
1051 + ", numOnsets=" + numOnsets + ", numAbatements=" + numAbatements + ", isActivated=" + isActivated
1052 + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";
1056 * This function calls Aai Custom Query and responds with the AaiCqResponse.
1058 * @param event input event
1059 * @return AaiCqResponse Response from Aai for custom query
1060 * @throws AaiException if error occurs
1062 public AaiCqResponse getCqResponse(VirtualControlLoopEvent event) throws AaiException {
1064 Map<String, String> aai = event.getAai();
1066 if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
1068 if (isClosedLoopDisabled(event)) {
1069 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
1072 if (isProvStatusInactive(event)) {
1073 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
1077 if (!aai.containsKey(VSERVER_VSERVER_NAME)) {
1078 throw new AaiException("Vserver name is missing");
1081 UUID reqId = event.getRequestId();
1082 AaiCqResponse response = null;
1083 String vserverId = event.getAai().get(VSERVER_VSERVER_NAME);
1085 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
1086 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME_PROPERTY);
1087 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASS_PROPERTY);
1089 response = new AaiManager(new RestManager()).getCustomQueryResponse(aaiHostUrl, aaiUser, aaiPassword, reqId,