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 static org.onap.policy.controlloop.ControlLoopTargetType.PNF;
24 import static org.onap.policy.controlloop.ControlLoopTargetType.VM;
25 import static org.onap.policy.controlloop.ControlLoopTargetType.VNF;
27 import java.io.Serializable;
28 import java.io.UnsupportedEncodingException;
29 import java.net.URLDecoder;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.LinkedList;
36 import java.util.List;
38 import java.util.NoSuchElementException;
40 import java.util.UUID;
41 import java.util.stream.Collectors;
42 import java.util.stream.Stream;
43 import org.apache.commons.lang3.StringUtils;
44 import org.onap.policy.aai.AaiCqResponse;
45 import org.onap.policy.aai.AaiGetVnfResponse;
46 import org.onap.policy.aai.AaiGetVserverResponse;
47 import org.onap.policy.aai.AaiManager;
48 import org.onap.policy.aai.AaiNqInstanceFilters;
49 import org.onap.policy.aai.AaiNqNamedQuery;
50 import org.onap.policy.aai.AaiNqQueryParameters;
51 import org.onap.policy.aai.AaiNqRequest;
52 import org.onap.policy.aai.AaiNqResponse;
53 import org.onap.policy.aai.AaiNqResponseWrapper;
54 import org.onap.policy.aai.AaiNqVServer;
55 import org.onap.policy.aai.util.AaiException;
56 import org.onap.policy.controlloop.ControlLoopEventStatus;
57 import org.onap.policy.controlloop.ControlLoopException;
58 import org.onap.policy.controlloop.ControlLoopNotificationType;
59 import org.onap.policy.controlloop.ControlLoopOperation;
60 import org.onap.policy.controlloop.VirtualControlLoopEvent;
61 import org.onap.policy.controlloop.VirtualControlLoopNotification;
62 import org.onap.policy.controlloop.policy.FinalResult;
63 import org.onap.policy.controlloop.policy.Policy;
64 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
65 import org.onap.policy.drools.core.lock.Lock;
66 import org.onap.policy.drools.core.lock.LockCallback;
67 import org.onap.policy.drools.core.lock.LockImpl;
68 import org.onap.policy.drools.core.lock.LockState;
69 import org.onap.policy.drools.system.PolicyEngineConstants;
70 import org.onap.policy.drools.utils.Pair;
71 import org.onap.policy.rest.RestManager;
72 import org.onap.policy.so.util.Serialization;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
76 public class ControlLoopEventManager implements Serializable {
77 public static final String PROV_STATUS_ACTIVE = "ACTIVE";
78 private static final String VM_NAME = "VM_NAME";
79 private static final String VNF_NAME = "VNF_NAME";
80 public static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
81 public static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
82 public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
83 public static final String GENERIC_VNF_IS_CLOSED_LOOP_DISABLED = "generic-vnf.is-closed-loop-disabled";
84 public static final String VSERVER_IS_CLOSED_LOOP_DISABLED = "vserver.is-closed-loop-disabled";
85 private static final String PNF_IS_IN_MAINT = "pnf.in-maint";
86 public static final String GENERIC_VNF_PROV_STATUS = "generic-vnf.prov-status";
87 public static final String VSERVER_PROV_STATUS = "vserver.prov-status";
88 public static final String PNF_ID = "pnf.pnf-id";
89 public static final String PNF_NAME = "pnf.pnf-name";
91 public static final String AAI_URL = "aai.url";
92 public static final String AAI_USERNAME_PROPERTY = "aai.username";
93 public static final String AAI_PASS_PROPERTY = "aai.password";
95 private static final String QUERY_AAI_ERROR_MSG = "Exception from queryAai: ";
98 * Additional time, in seconds, to add to a "lock" request. This ensures that the lock won't expire right before an
99 * operation completes.
101 private static final int ADDITIONAL_LOCK_SEC = 60;
103 private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
105 private static final long serialVersionUID = -1216568161322872641L;
107 private static final Set<String> VALID_TARGETS;
110 VALID_TARGETS = Collections.unmodifiableSet(new HashSet<>(
111 Stream.of(VM_NAME, VNF_NAME, VSERVER_VSERVER_NAME, GENERIC_VNF_VNF_ID, GENERIC_VNF_VNF_NAME, PNF_NAME)
112 .map(String::toLowerCase).collect(Collectors.toList())));
115 public final String closedLoopControlName;
116 private final UUID requestId;
118 private String controlLoopResult;
119 private ControlLoopProcessor processor = null;
120 private VirtualControlLoopEvent onset;
121 private Integer numOnsets = 0;
122 private Integer numAbatements = 0;
123 private VirtualControlLoopEvent abatement;
124 private FinalResult controlLoopTimedOut = null;
126 private boolean isActivated = false;
127 private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
128 private ControlLoopOperationManager currentOperation = null;
129 private ControlLoopOperationManager lastOperationManager = null;
130 private transient Lock targetLock = null;
131 private AaiGetVnfResponse vnfResponse = null;
132 private AaiGetVserverResponse vserverResponse = null;
133 private boolean useTargetLock = true;
136 * Wrapper for AAI vserver named-query response. This is initialized in a lazy fashion.
138 private AaiNqResponseWrapper nqVserverResponse = null;
140 private static Collection<String> requiredAAIKeys = new ArrayList<>();
143 requiredAAIKeys.add("AICVServerSelfLink");
144 requiredAAIKeys.add("AICIdentity");
145 requiredAAIKeys.add("is_closed_loop_disabled");
146 requiredAAIKeys.add(VM_NAME);
150 * Constructs the object.
152 * @param closedLoopControlName name of the control loop
153 * @param requestId ID of the request with which this manager is associated
155 public ControlLoopEventManager(String closedLoopControlName, UUID requestId) {
156 this.closedLoopControlName = closedLoopControlName;
157 this.requestId = requestId;
160 public String getClosedLoopControlName() {
161 return closedLoopControlName;
164 public String getControlLoopResult() {
165 return controlLoopResult;
168 public void setControlLoopResult(String controlLoopResult) {
169 this.controlLoopResult = controlLoopResult;
172 public Integer getNumOnsets() {
176 public void setNumOnsets(Integer numOnsets) {
177 this.numOnsets = numOnsets;
180 public Integer getNumAbatements() {
181 return numAbatements;
184 public void setNumAbatements(Integer numAbatements) {
185 this.numAbatements = numAbatements;
188 public boolean isActivated() {
192 public void setActivated(boolean isActivated) {
193 this.isActivated = isActivated;
196 public boolean useTargetLock() {
197 return useTargetLock();
200 public void setUseTargetLock(boolean useTargetLock) {
201 this.useTargetLock = useTargetLock;
204 public VirtualControlLoopEvent getOnsetEvent() {
208 public VirtualControlLoopEvent getAbatementEvent() {
209 return this.abatement;
212 public ControlLoopProcessor getProcessor() {
213 return this.processor;
216 public UUID getRequestId() {
221 * Activate a control loop event.
223 * @param event the event
224 * @return the VirtualControlLoopNotification
226 public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
227 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
230 // This method should ONLY be called ONCE
232 if (this.isActivated) {
233 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
236 // Syntax check the event
238 checkEventSyntax(event);
241 // At this point we are good to go with this event
246 notification.setNotification(ControlLoopNotificationType.ACTIVE);
248 // Set ourselves as active
250 this.isActivated = true;
251 } catch (ControlLoopException e) {
252 logger.error("{}: activate by event threw: ", this, e);
253 notification.setNotification(ControlLoopNotificationType.REJECTED);
254 notification.setMessage(e.getMessage());
260 * Activate a control loop event.
262 * @param yamlSpecification the yaml specification
263 * @param event the event
264 * @return the VirtualControlLoopNotification
266 public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
267 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
270 // This method should ONLY be called ONCE
272 if (this.isActivated) {
273 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
276 // Syntax check the event
278 checkEventSyntax(event);
283 if (yamlSpecification == null || yamlSpecification.length() < 1) {
284 throw new ControlLoopException("yaml specification is null or 0 length");
286 } catch (ControlLoopException e) {
287 logger.error("{}: activate by YAML specification and event threw: ", this, e);
288 notification.setNotification(ControlLoopNotificationType.REJECTED);
289 notification.setMessage(e.getMessage());
293 String decodedYaml = null;
295 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
296 if (decodedYaml != null && decodedYaml.length() > 0) {
297 yamlSpecification = decodedYaml;
299 } catch (UnsupportedEncodingException e) {
300 logger.error("{}: YAML decode in activate by YAML specification and event threw: ", this, e);
301 notification.setNotification(ControlLoopNotificationType.REJECTED);
302 notification.setMessage(e.getMessage());
308 // Parse the YAML specification
310 this.processor = new ControlLoopProcessor(yamlSpecification);
312 // At this point we are good to go with this event
319 notification.setNotification(ControlLoopNotificationType.ACTIVE);
321 // Set ourselves as active
323 this.isActivated = true;
324 } catch (ControlLoopException e) {
325 logger.error("{}: activate by YAML specification and event threw: ", this, e);
326 notification.setNotification(ControlLoopNotificationType.REJECTED);
327 notification.setMessage(e.getMessage());
333 * Check if the control loop is final.
335 * @return a VirtualControlLoopNotification if the control loop is final, otherwise <code>null</code> is returned
336 * @throws ControlLoopException if an error occurs
338 public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
339 validateFinalControlLoop();
341 // Ok, start creating the notification
343 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
345 // Check if the overall control loop has timed out
347 if (this.isControlLoopTimedOut()) {
349 // Yes we have timed out
351 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
352 notification.setMessage("Control Loop timed out");
353 notification.getHistory().addAll(this.controlLoopHistory);
357 // Check if the current policy is Final
359 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
360 if (result == null) {
362 // we are not at a final result
368 case FINAL_FAILURE_EXCEPTION:
369 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
370 notification.setMessage("Exception in processing closed loop");
373 case FINAL_FAILURE_RETRIES:
374 case FINAL_FAILURE_TIMEOUT:
375 case FINAL_FAILURE_GUARD:
376 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
379 notification.setNotification(ControlLoopNotificationType.FINAL_OPENLOOP);
382 notification.setNotification(ControlLoopNotificationType.FINAL_SUCCESS);
388 // Be sure to add all the history
390 notification.getHistory().addAll(this.controlLoopHistory);
394 private void validateFinalControlLoop() throws ControlLoopException {
396 // Check if they activated us
398 if (!this.isActivated) {
399 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
402 // Make sure we are expecting this call.
404 if (this.onset == null) {
405 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
410 * Process the control loop.
412 * @return a ControlLoopOperationManager
413 * @throws ControlLoopException if an error occurs
415 public ControlLoopOperationManager processControlLoop() throws ControlLoopException {
416 validateFinalControlLoop();
418 // Is there a current operation?
420 if (this.currentOperation != null) {
422 // Throw an exception, or simply return the current operation?
424 throw new ControlLoopException("Already working an Operation, do not call this method.");
427 // Ensure we are not FINAL
429 VirtualControlLoopNotification notification = this.isControlLoopFinal();
430 if (notification != null) {
432 // This is weird, we require them to call the isControlLoopFinal() method first
434 // We should really abstract this and avoid throwing an exception, because it really
435 // isn't an exception.
437 throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
440 // Not final so get the policy that needs to be worked on.
442 Policy policy = this.processor.getCurrentPolicy();
443 if (policy == null) {
444 throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
447 // And setup an operation
449 this.lastOperationManager = this.currentOperation;
450 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
454 return this.currentOperation;
458 * Finish an operation.
460 * @param operation the operation
462 public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
464 // Verify we have a current operation
466 if (this.currentOperation != null) {
468 // Validate they are finishing the current operation
469 // PLD - this is simply comparing the policy. Do we want to equals the whole object?
471 if (this.currentOperation.policy.equals(operation.policy)) {
472 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(),
473 this.currentOperation.getOperationResult());
477 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
479 // Move to the next Policy
481 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
483 // Just null this out
485 this.lastOperationManager = this.currentOperation;
486 this.currentOperation = null;
489 // Don't release the lock - it may be re-used by the next operation
494 logger.debug("Cannot finish current operation {} does not match given operation {}",
495 this.currentOperation.policy, operation.policy);
498 throw new ControlLoopException("No operation to finish.");
502 * Obtain a lock for the current operation.
504 * @param callback call-back to be invoked when the lock state changes
505 * @return a pair containing the old lock and the new lock, either of which may be null
506 * @throws ControlLoopException if an error occurs
508 public synchronized Pair<Lock, Lock> lockCurrentOperation(LockCallback callback) throws ControlLoopException {
512 if (this.currentOperation == null) {
513 throw new ControlLoopException("Do not have a current operation.");
517 // Release the old lock if it's for a different resource.
520 if (this.targetLock != null
521 && !this.targetLock.getResourceId().equals(this.currentOperation.getTargetEntity())) {
522 logger.debug("{}: different resource - releasing old lock", getClosedLoopControlName());
523 oldLock = this.targetLock;
524 this.targetLock = null;
527 // keep the lock a little longer than the operation, including retries
528 int optimeout = Math.max(1, this.currentOperation.getOperationTimeout());
529 int nattempts = 1 + Math.max(0, this.currentOperation.getMaxRetries());
530 int holdSec = optimeout * nattempts + ADDITIONAL_LOCK_SEC;
533 // Have we acquired it already?
535 if (this.targetLock != null) {
536 // we have the lock - just extend it
537 this.targetLock.extend(holdSec, callback);
538 return new Pair<>(oldLock, null);
540 } else if (this.useTargetLock) {
541 this.targetLock = createRealLock(this.currentOperation.getTargetEntity(), this.onset.getRequestId(),
543 return new Pair<>(oldLock, this.targetLock);
546 // Not using target locks - create a lock w/o actually locking.
547 logger.debug("{}: not using target locking; using pseudo locks", getClosedLoopControlName());
548 this.targetLock = createPseudoLock(this.currentOperation.getTargetEntity(), this.onset.getRequestId(),
551 // Note: no need to invoke callback, as the lock is already ACTIVE
553 return new Pair<>(oldLock, this.targetLock);
558 * Releases the lock for the current operation, deleting it from working memory.
560 * @return the lock, if the operation was locked, {@code null} otherwise
562 public synchronized Lock unlockCurrentOperation() {
563 if (this.targetLock == null) {
567 Lock lock = this.targetLock;
568 this.targetLock = null;
575 public enum NewEventStatus {
576 FIRST_ONSET, SUBSEQUENT_ONSET, FIRST_ABATEMENT, SUBSEQUENT_ABATEMENT, SYNTAX_ERROR;
580 * An event onset/abatement.
582 * @param event the event
584 * @throws AaiException if an error occurs retrieving information from A&AI
586 public NewEventStatus onNewEvent(VirtualControlLoopEvent event) throws AaiException {
588 this.checkEventSyntax(event);
589 if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ONSET) {
591 // Check if this is our original ONSET
593 if (event.equals(this.onset)) {
595 // Query A&AI if needed
602 return NewEventStatus.FIRST_ONSET;
605 // Log that we got an onset
608 return NewEventStatus.SUBSEQUENT_ONSET;
609 } else if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
611 // Have we already got an abatement?
613 if (this.abatement == null) {
617 this.abatement = event;
619 // Keep track that we received another
621 this.numAbatements++;
625 return NewEventStatus.FIRST_ABATEMENT;
628 // Keep track that we received another
630 this.numAbatements++;
634 return NewEventStatus.SUBSEQUENT_ABATEMENT;
637 } catch (ControlLoopException e) {
638 logger.error("{}: onNewEvent threw: ", this, e);
640 return NewEventStatus.SYNTAX_ERROR;
645 * Commit the abatement to the history database.
647 * @param message the abatement message
648 * @param outcome the abatement outcome
650 public void commitAbatement(String message, String outcome) {
651 if (this.lastOperationManager == null) {
652 logger.error("{}: commitAbatement: no operation manager", this);
656 this.lastOperationManager.commitAbatement(message, outcome);
657 } catch (NoSuchElementException e) {
658 logger.error("{}: commitAbatement threw an exception ", this, e);
664 * Set the control loop time out.
666 * @return a VirtualControlLoopNotification
668 public VirtualControlLoopNotification setControlLoopTimedOut() {
669 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
670 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
671 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
672 notification.setMessage("Control Loop timed out");
673 notification.getHistory().addAll(this.controlLoopHistory);
677 public boolean isControlLoopTimedOut() {
678 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
682 * Get the control loop timeout.
684 * @param defaultTimeout the default timeout
685 * @return the timeout
687 public int getControlLoopTimeout(Integer defaultTimeout) {
688 if (this.processor != null && this.processor.getControlLoop() != null) {
689 Integer timeout = this.processor.getControlLoop().getTimeout();
690 if (timeout != null && timeout > 0) {
694 if (defaultTimeout != null) {
695 return defaultTimeout;
700 public AaiGetVnfResponse getVnfResponse() {
704 public AaiGetVserverResponse getVserverResponse() {
705 return vserverResponse;
709 * Check an event syntax.
711 * @param event the event syntax
712 * @throws ControlLoopException if an error occurs
714 public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
715 validateStatus(event);
716 if (StringUtils.isBlank(event.getClosedLoopControlName())) {
717 throw new ControlLoopException("No control loop name");
719 if (event.getRequestId() == null) {
720 throw new ControlLoopException("No request ID");
722 if (event.getClosedLoopEventStatus() == ControlLoopEventStatus.ABATED) {
725 if (StringUtils.isBlank(event.getTarget())) {
726 throw new ControlLoopException("No target field");
727 } else if (!VALID_TARGETS.contains(event.getTarget().toLowerCase())) {
728 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
730 validateAaiData(event);
733 private void validateStatus(VirtualControlLoopEvent event) throws ControlLoopException {
734 if (event.getClosedLoopEventStatus() == null
735 || (event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET
736 && event.getClosedLoopEventStatus() != ControlLoopEventStatus.ABATED)) {
737 throw new ControlLoopException("Invalid value in closedLoopEventStatus");
741 private void validateAaiData(VirtualControlLoopEvent event) throws ControlLoopException {
742 Map<String, String> eventAai = event.getAai();
743 if (eventAai == null) {
744 throw new ControlLoopException("AAI is null");
746 switch (event.getTargetType()) {
749 if (eventAai.get(GENERIC_VNF_VNF_ID) == null && eventAai.get(VSERVER_VSERVER_NAME) == null
750 && eventAai.get(GENERIC_VNF_VNF_NAME) == null) {
751 throw new ControlLoopException(
752 "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
756 if (eventAai.get(PNF_NAME) == null) {
757 throw new ControlLoopException("AAI PNF object key pnf-name is missing");
761 throw new ControlLoopException("The target type is not supported");
766 * Query A&AI for an event.
768 * @param event the event
769 * @throws AaiException if an error occurs retrieving information from A&AI
771 public void queryAai(VirtualControlLoopEvent event) throws AaiException {
773 Map<String, String> aai = event.getAai();
775 if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)
776 || aai.containsKey(PNF_IS_IN_MAINT)) {
778 if (isClosedLoopDisabled(event)) {
779 throw new AaiException(
780 "is-closed-loop-disabled is set to true on VServer or VNF or in-maint is set to true for PNF");
783 if (isProvStatusInactive(event)) {
784 throw new AaiException("prov-status is not ACTIVE on VServer or VNF or PNF");
787 // no need to query, as we already have the data
791 if (vnfResponse != null || vserverResponse != null) {
792 // query has already been performed
797 if (aai.containsKey(GENERIC_VNF_VNF_ID) || aai.containsKey(GENERIC_VNF_VNF_NAME)) {
798 vnfResponse = getAaiVnfInfo(event);
799 processVnfResponse(vnfResponse, aai.containsKey(GENERIC_VNF_VNF_ID));
800 } else if (aai.containsKey(VSERVER_VSERVER_NAME)) {
801 vserverResponse = getAaiVserverInfo(event);
802 processVServerResponse(vserverResponse);
804 } catch (AaiException e) {
805 logger.error(QUERY_AAI_ERROR_MSG, e);
807 } catch (Exception e) {
808 logger.error(QUERY_AAI_ERROR_MSG, e);
809 throw new AaiException(QUERY_AAI_ERROR_MSG + e.toString());
814 * Process a response from A&AI for a VNF.
816 * @param aaiResponse the response from A&AI
817 * @param queryByVnfId <code>true</code> if the query was based on vnf-id, <code>false</code> if the query was based
819 * @throws AaiException if an error occurs processing the response
821 private static void processVnfResponse(AaiGetVnfResponse aaiResponse, boolean queryByVnfId) throws AaiException {
822 String queryTypeString = (queryByVnfId ? "vnf-id" : "vnf-name");
824 if (aaiResponse == null) {
825 throw new AaiException("AAI Response is null (query by " + queryTypeString + ")");
827 if (aaiResponse.getRequestError() != null) {
828 throw new AaiException("AAI Responded with a request error (query by " + queryTypeString + ")");
831 if (aaiResponse.getIsClosedLoopDisabled()) {
832 throw new AaiException("is-closed-loop-disabled is set to true (query by " + queryTypeString + ")");
835 if (!PROV_STATUS_ACTIVE.equals(aaiResponse.getProvStatus())) {
836 throw new AaiException("prov-status is not ACTIVE (query by " + queryTypeString + ")");
841 * Process a response from A&AI for a VServer.
843 * @param aaiResponse the response from A&AI
844 * @throws AaiException if an error occurs processing the response
846 private static void processVServerResponse(AaiGetVserverResponse aaiResponse) throws AaiException {
847 if (aaiResponse == null) {
848 throw new AaiException("AAI Response is null (query by vserver-name)");
850 if (aaiResponse.getRequestError() != null) {
851 throw new AaiException("AAI Responded with a request error (query by vserver-name)");
854 List<AaiNqVServer> lst = aaiResponse.getVserver();
859 AaiNqVServer svr = lst.get(0);
860 if (svr.getIsClosedLoopDisabled()) {
861 throw new AaiException("is-closed-loop-disabled is set to true (query by vserver-name)");
864 if (!PROV_STATUS_ACTIVE.equals(svr.getProvStatus())) {
865 throw new AaiException("prov-status is not ACTIVE (query by vserver-name)");
870 * Is closed loop disabled for an event.
872 * @param event the event
873 * @return <code>true</code> if the control loop is disabled, <code>false</code> otherwise
875 public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
876 Map<String, String> aai = event.getAai();
877 return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
878 || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED))
879 || isAaiTrue(aai.get(PNF_IS_IN_MAINT)));
883 * Does provisioning status, for an event, have a value other than ACTIVE.
885 * @param event the event
886 * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null}, {@code false} otherwise
888 protected static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
889 Map<String, String> aai = event.getAai();
890 return (!PROV_STATUS_ACTIVE.equals(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
891 || !PROV_STATUS_ACTIVE.equals(aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
895 * Determines the boolean value represented by the given AAI field value.
897 * @param aaiValue value to be examined
898 * @return the boolean value represented by the field value, or {@code false} if the value is {@code null}
900 protected static boolean isAaiTrue(String aaiValue) {
901 return ("true".equalsIgnoreCase(aaiValue) || "T".equalsIgnoreCase(aaiValue) || "yes".equalsIgnoreCase(aaiValue)
902 || "Y".equalsIgnoreCase(aaiValue));
906 * Get the A&AI VService information for an event.
908 * @param event the event
909 * @return a AaiGetVserverResponse
910 * @throws ControlLoopException if an error occurs
912 public static AaiGetVserverResponse getAaiVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
913 UUID requestId = event.getRequestId();
914 AaiGetVserverResponse response = null;
915 String vserverName = event.getAai().get(VSERVER_VSERVER_NAME);
918 if (vserverName != null) {
919 String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
920 String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
921 String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
922 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
923 String url = aaiHostUrl + aaiGetQueryByVserver;
924 logger.info("AAI Host URL by VServer: {}", url);
925 response = new AaiManager(new RestManager()).getQueryByVserverName(url, aaiUser, aaiPassword, requestId,
928 } catch (Exception e) {
929 logger.error("getAaiVserverInfo exception: ", e);
930 throw new ControlLoopException("Exception in getAaiVserverInfo: ", e);
937 * Get A&AI VNF information for an event.
939 * @param event the event
940 * @return a AaiGetVnfResponse
941 * @throws ControlLoopException if an error occurs
943 public static AaiGetVnfResponse getAaiVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
944 UUID requestId = event.getRequestId();
945 AaiGetVnfResponse response = null;
946 String vnfName = event.getAai().get(GENERIC_VNF_VNF_NAME);
947 String vnfId = event.getAai().get(GENERIC_VNF_VNF_ID);
949 String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
950 String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
951 String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
954 if (vnfName != null) {
955 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
956 String url = aaiHostUrl + aaiGetQueryByVnfName;
957 logger.info("AAI Host URL by VNF name: {}", url);
958 response = new AaiManager(new RestManager()).getQueryByVnfName(url, aaiUser, aaiPassword, requestId,
960 } else if (vnfId != null) {
961 String aaiGetQueryByVnfId = "/aai/v11/network/generic-vnfs/generic-vnf/";
962 String url = aaiHostUrl + aaiGetQueryByVnfId;
963 logger.info("AAI Host URL by VNF ID: {}", url);
965 new AaiManager(new RestManager()).getQueryByVnfId(url, aaiUser, aaiPassword, requestId, vnfId);
967 } catch (Exception e) {
968 logger.error("getAaiVnfInfo exception: ", e);
969 throw new ControlLoopException("Exception in getAaiVnfInfo: ", e);
976 * Gets the output from the AAI vserver named-query, using the cache, if appropriate.
978 * @return output from the AAI vserver named-query
980 public AaiNqResponseWrapper getNqVserverFromAai() {
981 if (nqVserverResponse != null) {
983 return nqVserverResponse;
986 String vserverName = onset.getAai().get(VSERVER_VSERVER_NAME);
987 if (vserverName == null) {
988 logger.warn("Missing vserver-name for AAI request {}", onset.getRequestId());
991 AaiNqRequest aaiNqRequest = getAaiNqRequest(vserverName);
993 if (logger.isDebugEnabled()) {
994 logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
997 AaiNqResponse aaiNqResponse = new AaiManager(new RestManager()).postQuery(getPeManagerEnvProperty(AAI_URL),
998 getPeManagerEnvProperty(AAI_USERNAME_PROPERTY), getPeManagerEnvProperty(AAI_PASS_PROPERTY),
999 aaiNqRequest, onset.getRequestId());
1001 // Check AAI response
1002 if (aaiNqResponse == null) {
1003 logger.warn("No response received from AAI for request {}", aaiNqRequest);
1007 // Create AAINQResponseWrapper
1008 nqVserverResponse = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
1010 if (logger.isDebugEnabled()) {
1011 logger.debug("AAI Named Query Response: ");
1012 logger.debug(Serialization.gsonPretty.toJson(nqVserverResponse.getAaiNqResponse()));
1015 return nqVserverResponse;
1019 * Gets an AAI Named Query Request object.
1021 * @param vserverName vserver name.
1022 * @return the AAI Named Query Request object.
1024 public static AaiNqRequest getAaiNqRequest(String vserverName) {
1025 // create AAI named-query request with UUID started with ""
1026 AaiNqRequest aaiNqRequest = new AaiNqRequest();
1027 AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
1028 AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
1029 final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
1032 aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
1033 aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
1034 aaiNqRequest.setQueryParameters(aaiNqQueryParam);
1038 Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
1039 Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
1040 aaiNqInstanceFilterMapItem.put("vserver-name", vserverName);
1041 aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
1042 aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
1043 aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
1044 return aaiNqRequest;
1048 * This method reads and validates environmental properties coming from the policy engine. Null properties cause an
1049 * {@link IllegalArgumentException} runtime exception to be thrown
1051 * @param enginePropertyName the name of the parameter to retrieve
1052 * @return the property value
1054 private static String getPeManagerEnvProperty(String enginePropertyName) {
1055 String enginePropertyValue = PolicyEngineConstants.getManager().getEnvironmentProperty(enginePropertyName);
1056 if (enginePropertyValue == null) {
1057 throw new IllegalArgumentException("The value of policy engine manager environment property \""
1058 + enginePropertyName + "\" may not be null");
1060 return enginePropertyValue;
1064 public String toString() {
1065 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestId=" + requestId
1066 + ", processor=" + processor + ", onset=" + (onset != null ? onset.getRequestId() : "null")
1067 + ", numOnsets=" + numOnsets + ", numAbatements=" + numAbatements + ", isActivated=" + isActivated
1068 + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";
1072 * This function calls Aai Custom Query and responds with the AaiCqResponse.
1074 * @param event input event
1075 * @return AaiCqResponse Response from Aai for custom query. Can not be null.
1076 * @throws AaiException if error occurs
1078 public AaiCqResponse getCqResponse(VirtualControlLoopEvent event) throws AaiException {
1080 Map<String, String> aai = event.getAai();
1082 if (aai.containsKey(VSERVER_IS_CLOSED_LOOP_DISABLED) || aai.containsKey(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED)) {
1084 if (isClosedLoopDisabled(event)) {
1085 throw new AaiException("is-closed-loop-disabled is set to true on VServer or VNF");
1088 if (isProvStatusInactive(event)) {
1089 throw new AaiException("prov-status is not ACTIVE on VServer or VNF");
1093 if (!aai.containsKey(VSERVER_VSERVER_NAME)) {
1094 throw new AaiException("Vserver name is missing");
1097 UUID reqId = event.getRequestId();
1098 AaiCqResponse response = null;
1099 String vserverId = event.getAai().get(VSERVER_VSERVER_NAME);
1101 String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
1102 String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
1103 String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
1105 response = new AaiManager(new RestManager()).getCustomQueryResponse(aaiHostUrl, aaiUser, aaiPassword, reqId,
1108 if (response == null) {
1109 throw new AaiException("Aai response is undefined");
1117 * Get the specified pnf data from aai.
1118 * @param event the event containing pnf id.
1119 * @return pnf key value data.
1120 * @throws AaiException if an aai error occurs.
1122 public Map<String, String> getPnf(VirtualControlLoopEvent event) throws AaiException {
1123 Map<String, String> aai = event.getAai();
1125 if (!aai.containsKey(PNF_NAME)) {
1126 throw new AaiException("Missing unique identifier for PNF AAI object in the event.");
1129 UUID reqId = event.getRequestId();
1130 String pnfName = event.getAai().get(PNF_NAME);
1131 String aaiHostUrl = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_URL);
1132 String aaiUser = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_USERNAME_PROPERTY);
1133 String aaiPassword = PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_PASS_PROPERTY);
1135 Map<String, String> pnfParams =
1136 new AaiManager(new RestManager()).getPnf(aaiHostUrl, aaiUser, aaiPassword, reqId, pnfName);
1138 if (pnfParams == null) {
1139 throw new AaiException("Aai response is undefined");
1145 // the following methods may be overridden by junit tests
1147 protected Lock createRealLock(String targetEntity, UUID requestId, int holdSec, LockCallback callback) {
1148 return PolicyEngineConstants.getManager().createLock(targetEntity, requestId.toString(), holdSec, callback,
1152 // note: the "callback" is required, because it will be invoked when lock.extend() is
1154 protected Lock createPseudoLock(String targetEntity, UUID requestId, int holdSec, LockCallback callback) {
1155 return new LockImpl(LockState.ACTIVE, targetEntity, requestId.toString(), holdSec, callback);