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 private static final String AAI_URL = "aai.url";
85 private static final String AAI_USERNAME_PROPERTY = "aai.username";
86 private 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
402 * @throws AaiException if an error occurs retrieving information from A&AI
404 public ControlLoopOperationManager processControlLoop() throws ControlLoopException, AaiException {
405 validateFinalControlLoop();
407 // Is there a current operation?
409 if (this.currentOperation != null) {
411 // Throw an exception, or simply return the current operation?
413 throw new ControlLoopException("Already working an Operation, do not call this method.");
416 // Ensure we are not FINAL
418 VirtualControlLoopNotification notification = this.isControlLoopFinal();
419 if (notification != null) {
421 // This is weird, we require them to call the isControlLoopFinal() method first
423 // We should really abstract this and avoid throwing an exception, because it really
424 // isn't an exception.
426 throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
429 // Not final so get the policy that needs to be worked on.
431 Policy policy = this.processor.getCurrentPolicy();
432 if (policy == null) {
433 throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
436 // And setup an operation
438 this.lastOperationManager = this.currentOperation;
439 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
443 return this.currentOperation;
447 * Finish an operation.
449 * @param operation the operation
451 public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
453 // Verify we have a current operation
455 if (this.currentOperation != null) {
457 // Validate they are finishing the current operation
458 // PLD - this is simply comparing the policy. Do we want to equals the whole object?
460 if (this.currentOperation.policy.equals(operation.policy)) {
461 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(),
462 this.currentOperation.getOperationResult());
466 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
468 // Move to the next Policy
470 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
472 // Just null this out
474 this.lastOperationManager = this.currentOperation;
475 this.currentOperation = null;
477 // TODO: Release our lock
481 logger.debug("Cannot finish current operation {} does not match given operation {}",
482 this.currentOperation.policy, operation.policy);
485 throw new ControlLoopException("No operation to finish.");
489 * Obtain a lock for the current operation.
491 * @return the lock result
492 * @throws ControlLoopException if an error occurs
494 public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
498 if (this.currentOperation == null) {
499 throw new ControlLoopException("Do not have a current operation.");
502 // Not using target locks? Create and return a lock w/o actually locking.
504 if (!this.useTargetLock) {
505 TargetLock lock = PolicyGuard.createTargetLock(this.currentOperation.policy.getTarget().getType(),
506 this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this);
507 this.targetLock = lock;
508 return LockResult.createLockResult(GuardResult.LOCK_ACQUIRED, lock);
511 // Have we acquired it already?
513 if (this.targetLock != null) {
515 // TODO: Make sure the current lock is for the same target.
516 // Currently, it should be. But in the future it may not.
518 GuardResult result = PolicyGuard.lockTarget(targetLock,
519 this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
520 return new LockResult<>(result, this.targetLock);
525 LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
526 this.currentOperation.policy.getTarget().getType(), this.currentOperation.getTargetEntity(),
527 this.onset.getRequestId(), this, this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
531 if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
533 // Yes, let's save it
535 this.targetLock = lockResult.getB();
542 * Release the lock for the current operation.
544 * @return the target lock
546 public synchronized TargetLock unlockCurrentOperation() {
547 if (this.targetLock == null) {
551 TargetLock returnLock = this.targetLock;
552 this.targetLock = null;
554 // if using target locking unlock before returning
556 if (this.useTargetLock) {
557 PolicyGuard.unlockTarget(returnLock);
560 // always return the old target lock so rules can retract it
564 public enum NewEventStatus {
565 FIRST_ONSET, SUBSEQUENT_ONSET, FIRST_ABATEMENT, SUBSEQUENT_ABATEMENT, SYNTAX_ERROR;
569 * An event onset/abatement.
571 * @param event the event
573 * @throws AaiException if an error occurs retrieving information from A&AI
575 public NewEventStatus onNewEvent(VirtualControlLoopEvent event) throws AaiException {
577 this.checkEventSyntax(event);
578 if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ONSET) {
580 // Check if this is our original ONSET
582 if (event.equals(this.onset)) {
584 // Query A&AI if needed
591 return NewEventStatus.FIRST_ONSET;
594 // Log that we got an onset
597 return NewEventStatus.SUBSEQUENT_ONSET;
598 } else if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
600 // Have we already got an abatement?
602 if (this.abatement == null) {
606 this.abatement = event;
608 // Keep track that we received another
610 this.numAbatements++;
614 return NewEventStatus.FIRST_ABATEMENT;
617 // Keep track that we received another
619 this.numAbatements++;
623 return NewEventStatus.SUBSEQUENT_ABATEMENT;
626 } catch (ControlLoopException e) {
627 logger.error("{}: onNewEvent threw: ", this, e);
629 return NewEventStatus.SYNTAX_ERROR;
634 * Commit the abatement to the history database.
636 * @param message the abatement message
637 * @param outcome the abatement outcome
639 public void commitAbatement(String message, String outcome) {
640 if (this.lastOperationManager == null) {
641 logger.error("{}: commitAbatement: no operation manager", this);
645 this.lastOperationManager.commitAbatement(message, outcome);
646 } catch (NoSuchElementException e) {
647 logger.error("{}: commitAbatement threw an exception ", this, e);
653 * Set the control loop time out.
655 * @return a VirtualControlLoopNotification
657 public VirtualControlLoopNotification setControlLoopTimedOut() {
658 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
659 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
660 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
661 notification.setMessage("Control Loop timed out");
662 notification.getHistory().addAll(this.controlLoopHistory);
666 public boolean isControlLoopTimedOut() {
667 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
671 * Get the control loop timeout.
673 * @param defaultTimeout the default timeout
674 * @return the timeout
676 public int getControlLoopTimeout(Integer defaultTimeout) {
677 if (this.processor != null && this.processor.getControlLoop() != null) {
678 Integer timeout = this.processor.getControlLoop().getTimeout();
679 if (timeout != null && timeout > 0) {
683 if (defaultTimeout != null) {
684 return defaultTimeout;
689 public AaiGetVnfResponse getVnfResponse() {
693 public AaiGetVserverResponse getVserverResponse() {
694 return vserverResponse;
698 * Check an event syntax.
700 * @param event the event syntax
701 * @throws ControlLoopException if an error occurs
703 public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
704 validateStatus(event);
705 if (StringUtils.isBlank(event.getClosedLoopControlName())) {
706 throw new ControlLoopException("No control loop name");
708 if (event.getRequestId() == null) {
709 throw new ControlLoopException("No request ID");
711 if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
714 if (StringUtils.isBlank(event.getTarget())) {
715 throw new ControlLoopException("No target field");
716 } else if (!VALID_TARGETS.contains(event.getTarget().toLowerCase())) {
717 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
719 validateAaiData(event);
722 private void validateStatus(VirtualControlLoopEvent event) throws ControlLoopException {
723 if (event.getClosedLoopEventStatus() == null
724 || (event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET
725 && event.getClosedLoopEventStatus() != ControlLoopEventStatus.ABATED)) {
726 throw new ControlLoopException("Invalid value in closedLoopEventStatus");
730 private void validateAaiData(VirtualControlLoopEvent event) throws ControlLoopException {
731 if (event.getAai() == null) {
732 throw new ControlLoopException("AAI is null");
734 if (event.getAai().get(GENERIC_VNF_VNF_ID) == null && event.getAai().get(VSERVER_VSERVER_NAME) == null
735 && event.getAai().get(GENERIC_VNF_VNF_NAME) == null) {
736 throw new ControlLoopException(
737 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
742 * Query A&AI for an event.
744 * @param event the event
745 * @throws AaiException if an error occurs retrieving information from A&AI
747 public void queryAai(VirtualControlLoopEvent event) throws AaiException {
749 Map<String, String> aai = event.getAai();
751 if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
753 if (isClosedLoopDisabled(event)) {
754 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
757 if (isProvStatusInactive(event)) {
758 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
761 // no need to query, as we already have the data
765 if (vnfResponse != null || vserverResponse != null) {
766 // query has already been performed
771 if (aai.containsKey(GENERIC_VNF_VNF_ID) || aai.containsKey(GENERIC_VNF_VNF_NAME)) {
772 vnfResponse = getAaiVnfInfo(event);
773 processVnfResponse(vnfResponse, aai.containsKey(GENERIC_VNF_VNF_ID));
774 } else if (aai.containsKey(VSERVER_VSERVER_NAME)) {
775 vserverResponse = getAaiVserverInfo(event);
776 processVServerResponse(vserverResponse);
778 } catch (AaiException e) {
779 logger.error(QUERY_AAI_ERROR_MSG, e);
781 } catch (Exception e) {
782 logger.error(QUERY_AAI_ERROR_MSG, e);
783 throw new AaiException(QUERY_AAI_ERROR_MSG + e.toString());
788 * Process a response from A&AI for a VNF.
790 * @param aaiResponse the response from A&AI
791 * @param queryByVnfId <code>true</code> if the query was based on vnf-id, <code>false</code> if the query was based
793 * @throws AaiException if an error occurs processing the response
795 private static void processVnfResponse(AaiGetVnfResponse aaiResponse, boolean queryByVnfId) throws AaiException {
796 String queryTypeString = (queryByVnfId ? "vnf-id" : "vnf-name");
798 if (aaiResponse == null) {
799 throw new AaiException("AAI Response is null (query by " + queryTypeString + ")");
801 if (aaiResponse.getRequestError() != null) {
802 throw new AaiException("AAI Responded with a request error (query by " + queryTypeString + ")");
805 if (aaiResponse.getIsClosedLoopDisabled()) {
806 throw new AaiException("is-closed-loop-disabled is set to true (query by " + queryTypeString + ")");
809 if (!PROV_STATUS_ACTIVE.equals(aaiResponse.getProvStatus())) {
810 throw new AaiException("prov-status is not ACTIVE (query by " + queryTypeString + ")");
815 * Process a response from A&AI for a VServer.
817 * @param aaiResponse the response from A&AI
818 * @throws AaiException if an error occurs processing the response
820 private static void processVServerResponse(AaiGetVserverResponse aaiResponse) throws AaiException {
821 if (aaiResponse == null) {
822 throw new AaiException("AAI Response is null (query by vserver-name)");
824 if (aaiResponse.getRequestError() != null) {
825 throw new AaiException("AAI Responded with a request error (query by vserver-name)");
828 List<AaiNqVServer> lst = aaiResponse.getVserver();
833 AaiNqVServer svr = lst.get(0);
834 if (svr.getIsClosedLoopDisabled()) {
835 throw new AaiException("is-closed-loop-disabled is set to true (query by vserver-name)");
838 if (!PROV_STATUS_ACTIVE.equals(svr.getProvStatus())) {
839 throw new AaiException("prov-status is not ACTIVE (query by vserver-name)");
844 * Is closed loop disabled for an event.
846 * @param event the event
847 * @return <code>true</code> if the control loop is disabled, <code>false</code> otherwise
849 public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
850 Map<String, String> aai = event.getAai();
851 return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
852 || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)));
856 * Does provisioning status, for an event, have a value other than ACTIVE.
858 * @param event the event
859 * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null}, {@code false} otherwise
861 protected static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
862 Map<String, String> aai = event.getAai();
863 return (!PROV_STATUS_ACTIVE.equals(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
864 || !PROV_STATUS_ACTIVE.equals(aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
868 * Determines the boolean value represented by the given AAI field value.
870 * @param aaiValue value to be examined
871 * @return the boolean value represented by the field value, or {@code false} if the value is {@code null}
873 protected static boolean isAaiTrue(String aaiValue) {
874 return ("true".equalsIgnoreCase(aaiValue) || "T".equalsIgnoreCase(aaiValue) || "yes".equalsIgnoreCase(aaiValue)
875 || "Y".equalsIgnoreCase(aaiValue));
879 * Get the A&AI VService information for an event.
881 * @param event the event
882 * @return a AaiGetVserverResponse
883 * @throws ControlLoopException if an error occurs
885 public static AaiGetVserverResponse getAaiVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
886 UUID requestId = event.getRequestId();
887 AaiGetVserverResponse response = null;
888 String vserverName = event.getAai().get(VSERVER_VSERVER_NAME);
891 if (vserverName != null) {
892 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
893 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME_PROPERTY);
894 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASS_PROPERTY);
895 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
896 String url = aaiHostUrl + aaiGetQueryByVserver;
897 logger.info("AAI Host URL by VServer: {}", url);
898 response = new AaiManager(new RestManager()).getQueryByVserverName(url, aaiUser, aaiPassword, requestId,
901 } catch (Exception e) {
902 logger.error("getAaiVserverInfo exception: ", e);
903 throw new ControlLoopException("Exception in getAaiVserverInfo: ", e);
910 * Get A&AI VNF information for an event.
912 * @param event the event
913 * @return a AaiGetVnfResponse
914 * @throws ControlLoopException if an error occurs
916 public static AaiGetVnfResponse getAaiVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
917 UUID requestId = event.getRequestId();
918 AaiGetVnfResponse response = null;
919 String vnfName = event.getAai().get(GENERIC_VNF_VNF_NAME);
920 String vnfId = event.getAai().get(GENERIC_VNF_VNF_ID);
922 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
923 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME_PROPERTY);
924 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASS_PROPERTY);
927 if (vnfName != null) {
928 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
929 String url = aaiHostUrl + aaiGetQueryByVnfName;
930 logger.info("AAI Host URL by VNF name: {}", url);
931 response = new AaiManager(new RestManager()).getQueryByVnfName(url, aaiUser, aaiPassword, requestId,
933 } else if (vnfId != null) {
934 String aaiGetQueryByVnfId = "/aai/v11/network/generic-vnfs/generic-vnf/";
935 String url = aaiHostUrl + aaiGetQueryByVnfId;
936 logger.info("AAI Host URL by VNF ID: {}", url);
938 new AaiManager(new RestManager()).getQueryByVnfId(url, aaiUser, aaiPassword, requestId, vnfId);
940 } catch (Exception e) {
941 logger.error("getAaiVnfInfo exception: ", e);
942 throw new ControlLoopException("Exception in getAaiVnfInfo: ", e);
949 * Gets the output from the AAI vserver named-query, using the cache, if appropriate.
951 * @return output from the AAI vserver named-query
953 public AaiNqResponseWrapper getNqVserverFromAai() {
954 if (nqVserverResponse != null) {
956 return nqVserverResponse;
959 String vserverName = onset.getAai().get(VSERVER_VSERVER_NAME);
960 if (vserverName == null) {
961 logger.warn("Missing vserver-name for AAI request {}", onset.getRequestId());
965 // create AAI named-query request with UUID started with ""
966 AaiNqRequest aaiNqRequest = new AaiNqRequest();
967 AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
968 AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
969 final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
972 aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
973 aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
974 aaiNqRequest.setQueryParameters(aaiNqQueryParam);
978 Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
979 Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
980 aaiNqInstanceFilterMapItem.put("vserver-name", vserverName);
981 aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
982 aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
983 aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
985 if (logger.isDebugEnabled()) {
986 logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
989 AaiNqResponse aaiNqResponse = new AaiManager(new RestManager()).postQuery(getPeManagerEnvProperty(AAI_URL),
990 getPeManagerEnvProperty(AAI_USERNAME_PROPERTY), getPeManagerEnvProperty(AAI_PASS_PROPERTY),
991 aaiNqRequest, onset.getRequestId());
993 // Check AAI response
994 if (aaiNqResponse == null) {
995 logger.warn("No response received from AAI for request {}", aaiNqRequest);
999 // Create AAINQResponseWrapper
1000 nqVserverResponse = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
1002 if (logger.isDebugEnabled()) {
1003 logger.debug("AAI Named Query Response: ");
1004 logger.debug(Serialization.gsonPretty.toJson(nqVserverResponse.getAaiNqResponse()));
1007 return nqVserverResponse;
1011 * This method reads and validates environmental properties coming from the policy engine. Null properties cause an
1012 * {@link IllegalArgumentException} runtime exception to be thrown
1014 * @param enginePropertyName the name of the parameter to retrieve
1015 * @return the property value
1017 private static String getPeManagerEnvProperty(String enginePropertyName) {
1018 String enginePropertyValue = PolicyEngine.manager.getEnvironmentProperty(enginePropertyName);
1019 if (enginePropertyValue == null) {
1020 throw new IllegalArgumentException("The value of policy engine manager environment property \""
1021 + enginePropertyName + "\" may not be null");
1023 return enginePropertyValue;
1027 public boolean isActive() {
1033 public boolean releaseLock() {
1039 public String toString() {
1040 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestId=" + requestId
1041 + ", processor=" + processor + ", onset=" + (onset != null ? onset.getRequestId() : "null")
1042 + ", numOnsets=" + numOnsets + ", numAbatements=" + numAbatements + ", isActivated=" + isActivated
1043 + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";
1047 * This function calls Aai Custom Query and responds with the AaiCqResponse.
1049 * @param event input event
1050 * @return AaiCqResponse Response from Aai for custom query
1051 * @throws AaiException if error occurs
1053 public AaiCqResponse getCqResponse(VirtualControlLoopEvent event) throws AaiException {
1055 Map<String, String> aai = event.getAai();
1057 if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
1059 if (isClosedLoopDisabled(event)) {
1060 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
1063 if (isProvStatusInactive(event)) {
1064 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
1068 if (!aai.containsKey(VSERVER_VSERVER_NAME)) {
1069 throw new AaiException("Vserver name is missing");
1072 UUID reqId = event.getRequestId();
1073 AaiCqResponse response = null;
1074 String vserverId = event.getAai().get(VSERVER_VSERVER_NAME);
1076 String aaiHostUrl = PolicyEngine.manager.getEnvironmentProperty(AAI_URL);
1077 String aaiUser = PolicyEngine.manager.getEnvironmentProperty(AAI_USERNAME_PROPERTY);
1078 String aaiPassword = PolicyEngine.manager.getEnvironmentProperty(AAI_PASS_PROPERTY);
1080 response = new AaiManager(new RestManager()).getCustomQueryResponse(aaiHostUrl, aaiUser, aaiPassword, reqId,