2 * ============LICENSE_START=======================================================
3 * controlloop event manager
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.controlloop.eventmanager;
23 import java.io.Serializable;
24 import java.io.UnsupportedEncodingException;
25 import java.net.URLDecoder;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.LinkedList;
29 import java.util.UUID;
31 import org.onap.policy.aai.AAIGETVnfResponse;
32 import org.onap.policy.aai.AAIGETVserverResponse;
33 import org.onap.policy.aai.AAIManager;
34 import org.onap.policy.controlloop.ControlLoopEventStatus;
35 import org.onap.policy.controlloop.ControlLoopException;
36 import org.onap.policy.controlloop.ControlLoopNotificationType;
37 import org.onap.policy.controlloop.ControlLoopOperation;
38 import org.onap.policy.controlloop.VirtualControlLoopEvent;
39 import org.onap.policy.controlloop.VirtualControlLoopNotification;
40 import org.onap.policy.controlloop.policy.FinalResult;
41 import org.onap.policy.controlloop.policy.Policy;
42 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
43 import org.onap.policy.guard.GuardResult;
44 import org.onap.policy.guard.LockCallback;
45 import org.onap.policy.guard.PolicyGuard;
46 import org.onap.policy.guard.PolicyGuard.LockResult;
47 import org.onap.policy.guard.TargetLock;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
51 public class ControlLoopEventManager implements LockCallback, Serializable {
56 private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
58 private static final long serialVersionUID = -1216568161322872641L;
59 public final String closedLoopControlName;
60 public final UUID requestID;
62 private String controlLoopResult;
63 private transient ControlLoopProcessor processor = null;
64 private VirtualControlLoopEvent onset;
65 private Integer numOnsets = 0;
66 private Integer numAbatements = 0;
67 private VirtualControlLoopEvent abatement;
68 private FinalResult controlLoopTimedOut = null;
70 private boolean isActivated = false;
71 private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
72 private ControlLoopOperationManager currentOperation = null;
73 private transient TargetLock targetLock = null;
74 private static AAIGETVnfResponse vnfResponse = null;
75 private static AAIGETVserverResponse vserverResponse = null;
77 private static Collection<String> requiredAAIKeys = new ArrayList<>();
79 requiredAAIKeys.add("AICVServerSelfLink");
80 requiredAAIKeys.add("AICIdentity");
81 requiredAAIKeys.add("is_closed_loop_disabled");
82 requiredAAIKeys.add("VM_NAME");
85 public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
86 this.closedLoopControlName = closedLoopControlName;
87 this.requestID = requestID;
90 public String getControlLoopResult() {
91 return controlLoopResult;
94 public void setControlLoopResult(String controlLoopResult) {
95 this.controlLoopResult = controlLoopResult;
98 public Integer getNumOnsets() {
102 public void setNumOnsets(Integer numOnsets) {
103 this.numOnsets = numOnsets;
106 public Integer getNumAbatements() {
107 return numAbatements;
110 public void setNumAbatements(Integer numAbatements) {
111 this.numAbatements = numAbatements;
114 public boolean isActivated() {
118 public void setActivated(boolean isActivated) {
119 this.isActivated = isActivated;
122 public VirtualControlLoopEvent getOnsetEvent() {
126 public VirtualControlLoopEvent getAbatementEvent() {
127 return this.abatement;
130 public ControlLoopProcessor getProcessor() {
131 return this.processor;
134 public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
135 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
138 // This method should ONLY be called ONCE
140 if (this.isActivated) {
141 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
144 // Syntax check the event
146 checkEventSyntax(event);
148 // At this point we are good to go with this event
153 notification.notification = ControlLoopNotificationType.ACTIVE;
155 // Set ourselves as active
157 this.isActivated = true;
158 } catch (ControlLoopException e) {
159 logger.error("{}: activate threw: ",this, e);
160 notification.notification = ControlLoopNotificationType.REJECTED;
161 notification.message = e.getMessage();
168 public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
169 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
172 // This method should ONLY be called ONCE
174 if (this.isActivated) {
175 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
178 // Syntax check the event
180 checkEventSyntax(event);
185 if (yamlSpecification == null || yamlSpecification.length() < 1) {
186 throw new ControlLoopException("yaml specification is null or 0 length");
188 String decodedYaml = null;
190 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
191 if (decodedYaml != null && decodedYaml.length() > 0) {
192 yamlSpecification = decodedYaml;
194 } catch (UnsupportedEncodingException e) {
195 logger.error("{}: activate threw: ",this, e);
198 // Parse the YAML specification
200 this.processor = new ControlLoopProcessor(yamlSpecification);
203 // At this point we are good to go with this event
210 notification.notification = ControlLoopNotificationType.ACTIVE;
212 // Set ourselves as active
214 this.isActivated = true;
215 } catch (ControlLoopException e) {
216 logger.error("{}: activate threw: ",this, e);
217 notification.notification = ControlLoopNotificationType.REJECTED;
218 notification.message = e.getMessage();
223 public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
225 // Check if they activated us
227 if (this.isActivated == false) {
228 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
231 // Make sure we are expecting this call.
233 if (this.onset == null) {
234 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
237 // Ok, start creating the notification
239 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
241 // Check if the overall control loop has timed out
243 if (this.isControlLoopTimedOut()) {
245 // Yes we have timed out
247 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
248 notification.message = "Control Loop timed out";
249 notification.history.addAll(this.controlLoopHistory);
253 // Check if the current policy is Final
255 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
256 if (result == null) {
258 // we are not at a final result
265 case FINAL_FAILURE_EXCEPTION:
266 case FINAL_FAILURE_RETRIES:
267 case FINAL_FAILURE_TIMEOUT:
268 case FINAL_FAILURE_GUARD:
269 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
272 notification.notification = ControlLoopNotificationType.FINAL_OPENLOOP;
275 notification.notification = ControlLoopNotificationType.FINAL_SUCCESS;
281 // Be sure to add all the history
283 notification.history.addAll(this.controlLoopHistory);
287 public ControlLoopOperationManager processControlLoop() throws ControlLoopException {
289 // Check if they activated us
291 if (this.isActivated == false) {
292 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
295 // Make sure we are expecting this call.
297 if (this.onset == null) {
298 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
301 // Is there a current operation?
303 if (this.currentOperation != null) {
305 // Throw an exception, or simply return the current operation?
307 throw new ControlLoopException("Already working an Operation, do not call this method.");
310 // Ensure we are not FINAL
312 VirtualControlLoopNotification notification = this.isControlLoopFinal();
313 if (notification != null) {
315 // This is weird, we require them to call the isControlLoopFinal() method first
317 // We should really abstract this and avoid throwing an exception, because it really
318 // isn't an exception.
320 throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
323 // Not final so get the policy that needs to be worked on.
325 Policy policy = this.processor.getCurrentPolicy();
326 if (policy == null) {
327 throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
330 // And setup an operation
332 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
336 return this.currentOperation;
339 public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
341 // Verify we have a current operation
343 if (this.currentOperation != null) {
345 // Validate they are finishing the current operation
346 // PLD - this is simply comparing the policy. Do we want to equals the whole object?
348 if (this.currentOperation.policy.equals(operation.policy)) {
349 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(), this.currentOperation.getOperationResult());
353 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
355 // Move to the next Policy
357 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
359 // Just null this out
361 this.currentOperation = null;
363 // TODO: Release our lock
367 logger.debug("Cannot finish current operation {} does not match given operation {}", this.currentOperation.policy, operation.policy);
370 throw new ControlLoopException("No operation to finish.");
373 public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
377 if (this.currentOperation == null) {
378 throw new ControlLoopException("Do not have a current operation.");
381 // Have we acquired it already?
383 if (this.targetLock != null) {
385 // TODO: Make sure the current lock is for the same target.
386 // Currently, it should be. But in the future it may not.
388 return new LockResult<GuardResult, TargetLock>(GuardResult.LOCK_ACQUIRED, this.targetLock);
393 LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
394 this.currentOperation.policy.getTarget().getType(),
395 this.getTargetInstance(this.currentOperation.policy),
396 this.onset.requestID,
401 if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
403 // Yes, let's save it
405 this.targetLock = lockResult.getB();
411 public synchronized TargetLock unlockCurrentOperation() {
412 if (this.targetLock == null) {
415 if (PolicyGuard.unlockTarget(this.targetLock) == true) {
416 TargetLock returnLock = this.targetLock;
417 this.targetLock = null;
423 public enum NEW_EVENT_STATUS {
427 SUBSEQUENT_ABATEMENT,
432 public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) {
434 ControlLoopEventManager.checkEventSyntax(event);
435 if (event.closedLoopEventStatus == ControlLoopEventStatus.ONSET) {
437 // Check if this is our original ONSET
439 if (event.equals(this.onset)) {
443 return NEW_EVENT_STATUS.FIRST_ONSET;
446 // Log that we got an onset
449 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
450 } else if (event.closedLoopEventStatus == ControlLoopEventStatus.ABATED) {
452 // Have we already got an abatement?
454 if (this.abatement == null) {
458 this.abatement = event;
460 // Keep track that we received another
462 this.numAbatements++;
466 return NEW_EVENT_STATUS.FIRST_ABATEMENT;
469 // Keep track that we received another
471 this.numAbatements++;
475 return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
478 return NEW_EVENT_STATUS.SYNTAX_ERROR;
480 } catch (ControlLoopException e) {
481 logger.error("{}: onNewEvent threw: ",this, e);
482 return NEW_EVENT_STATUS.SYNTAX_ERROR;
486 public VirtualControlLoopNotification setControlLoopTimedOut() {
487 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
488 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
489 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
490 notification.message = "Control Loop timed out";
491 notification.history.addAll(this.controlLoopHistory);
495 public boolean isControlLoopTimedOut() {
496 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
499 public int getControlLoopTimeout(Integer defaultTimeout) {
500 if (this.processor != null && this.processor.getControlLoop() != null) {
501 return this.processor.getControlLoop().getTimeout();
503 if (defaultTimeout != null) {
504 return defaultTimeout;
509 public AAIGETVnfResponse getVnfResponse() {
513 public AAIGETVserverResponse getVserverResponse() {
514 return vserverResponse;
517 public static void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
518 if (event.closedLoopEventStatus == null ||
519 (event.closedLoopEventStatus != ControlLoopEventStatus.ONSET &&
520 event.closedLoopEventStatus != ControlLoopEventStatus.ABATED)) {
521 throw new ControlLoopException("Invalid value in closedLoopEventStatus");
523 if (event.closedLoopControlName == null || event.closedLoopControlName.length() < 1) {
524 throw new ControlLoopException("No control loop name");
526 if (event.requestID == null) {
527 throw new ControlLoopException("No request ID");
529 if (event.AAI == null) {
530 throw new ControlLoopException("AAI is null");
532 if (event.AAI.get("generic-vnf.vnf-id") == null && event.AAI.get("vserver.vserver-name") == null &&
533 event.AAI.get("generic-vnf.vnf-name") == null) {
534 throw new ControlLoopException("generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
536 if (event.AAI.get("vserver.is-closed-loop-disabled") == null) {
538 if (event.AAI.get("generic-vnf.vnf-id") != null) {
539 vnfResponse = getAAIVnfInfo(event);
540 if (vnfResponse == null) {
541 throw new ControlLoopException("AAI Response is null (query by vnf-id)");
543 if (isClosedLoopDisabled(vnfResponse) == true) {
544 throw new ControlLoopException("is-closed-loop-disabled is set to true");
546 } else if (event.AAI.get("generic-vnf.vnf-name") != null) {
547 vnfResponse = getAAIVnfInfo(event);
548 if (vnfResponse == null) {
549 throw new ControlLoopException("AAI Response is null (query by vnf-name)");
551 if (isClosedLoopDisabled(vnfResponse) == true) {
552 throw new ControlLoopException("is-closed-loop-disabled is set to true");
554 } else if (event.AAI.get("vserver.vserver-name") != null) {
555 vserverResponse = getAAIVserverInfo(event);
556 if (vserverResponse == null) {
557 throw new ControlLoopException("AAI Response is null (query by vserver-name)");
559 if (isClosedLoopDisabled(vserverResponse) == true) {
560 throw new ControlLoopException("is-closed-loop-disabled is set to true");
563 } catch (Exception e) {
564 logger.error("Exception from getAAIInfo: ", e);
565 throw new ControlLoopException("Exception from getAAIInfo: " + e.toString());
567 } else if (isClosedLoopDisabled(event)) {
568 throw new ControlLoopException("is-closed-loop-disabled is set to true");
570 if (event.target == null || event.target.length() < 1) {
571 throw new ControlLoopException("No target field");
573 if (! event.target.equalsIgnoreCase("VM_NAME") &&
574 ! event.target.equalsIgnoreCase("VNF_NAME") &&
575 ! event.target.equalsIgnoreCase("vserver.vserver-name") &&
576 ! event.target.equalsIgnoreCase("generic-vnf.vnf-id") &&
577 ! event.target.equalsIgnoreCase("generic-vnf.vnf-name") ) {
578 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
583 public static boolean isClosedLoopDisabled(AAIGETVnfResponse aaiResponse) {
584 if (aaiResponse != null && aaiResponse.isClosedLoopDisabled != null) {
585 String value = aaiResponse.isClosedLoopDisabled;
586 if ("true".equalsIgnoreCase(value) || "T".equalsIgnoreCase(value) ||
587 "yes".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value)) {
595 public static boolean isClosedLoopDisabled(AAIGETVserverResponse aaiResponse) {
596 if (aaiResponse != null && aaiResponse.isClosedLoopDisabled != null) {
597 String value = aaiResponse.isClosedLoopDisabled;
598 if ("true".equalsIgnoreCase(value) || "T".equalsIgnoreCase(value) ||
599 "yes".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value)) {
607 public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
608 if ("true".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
609 "T".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
610 "yes".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
611 "Y".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled"))) {
617 public static AAIGETVserverResponse getAAIVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
618 String user = "POLICY";
619 String password = "POLICY";
620 UUID requestID = event.requestID;
621 AAIGETVserverResponse response = null;
622 String vserverName = event.AAI.get("vserver.vserver-name");
625 if (vserverName != null) {
626 String url = "https://aai-ext1.test.att.com:8443/aai/v11/nodes/vservers?vserver-name=";
627 response = AAIManager.getQueryByVserverName(url, user, password, requestID, vserverName);
629 } catch (Exception e) {
630 logger.error("getAAIVserverInfo exception: ", e);
631 throw new ControlLoopException("Exception in getAAIVserverInfo: ", e);
637 public static AAIGETVnfResponse getAAIVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
638 String user = "POLICY";
639 String password = "POLICY";
640 UUID requestID = event.requestID;
641 AAIGETVnfResponse response = null;
642 String vnfName = event.AAI.get("generic-vnf.vnf-name");
643 String vnfID = event.AAI.get("generic-vnf.vnf-id");
646 if (vnfName != null) {
647 String url = "https://aai-ext1.test.att.com:8443/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
648 response = AAIManager.getQueryByVnfName(url, user, password, requestID, vnfName);
649 } else if (vnfID != null) {
650 String url = "https://aai-ext1.test.att.com:8443/aai/v11/network/generic-vnfs/generic-vnf/";
651 response = AAIManager.getQueryByVnfID(url, user, password, requestID, vnfID);
653 } catch (Exception e) {
654 logger.error("getAAIVnfInfo exception: ", e);
655 throw new ControlLoopException("Exception in getAAIVnfInfo: ", e);
662 public boolean isActive() {
668 public boolean releaseLock() {
673 public String getTargetInstance(Policy policy) {
674 if (policy.getTarget() != null) {
675 if (policy.getTarget().getType() != null) {
676 switch(policy.getTarget().getType()) {
681 if (this.onset.target.equalsIgnoreCase("vserver.vserver-name")) {
682 return this.onset.AAI.get("vserver.vserver-name");
684 else if (this.onset.target.equalsIgnoreCase("generic-vnf.vnf-id")) {
685 return this.onset.AAI.get("generic-vnf.vnf-id");
687 else if (this.onset.target.equalsIgnoreCase("generic-vnf.vnf-name")) {
688 return this.onset.AAI.get("generic-vnf.vnf-name");
700 public String toString() {
701 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestID=" + requestID
702 + ", processor=" + processor + ", onset=" + (onset != null ? onset.requestID : "null") + ", numOnsets=" + numOnsets + ", numAbatements="
703 + numAbatements + ", isActivated="
704 + isActivated + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";