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.aai.util.AAIException;
35 import org.onap.policy.controlloop.ControlLoopEventStatus;
36 import org.onap.policy.controlloop.ControlLoopException;
37 import org.onap.policy.controlloop.ControlLoopNotificationType;
38 import org.onap.policy.controlloop.ControlLoopOperation;
39 import org.onap.policy.controlloop.VirtualControlLoopEvent;
40 import org.onap.policy.controlloop.VirtualControlLoopNotification;
41 import org.onap.policy.controlloop.policy.FinalResult;
42 import org.onap.policy.controlloop.policy.Policy;
43 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
44 import org.onap.policy.guard.GuardResult;
45 import org.onap.policy.guard.LockCallback;
46 import org.onap.policy.guard.PolicyGuard;
47 import org.onap.policy.guard.PolicyGuard.LockResult;
48 import org.onap.policy.guard.TargetLock;
49 import org.onap.policy.drools.system.PolicyEngine;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class ControlLoopEventManager implements LockCallback, Serializable {
58 private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
60 private static final long serialVersionUID = -1216568161322872641L;
61 public final String closedLoopControlName;
62 public final UUID requestID;
64 private String controlLoopResult;
65 private transient ControlLoopProcessor processor = null;
66 private VirtualControlLoopEvent onset;
67 private Integer numOnsets = 0;
68 private Integer numAbatements = 0;
69 private VirtualControlLoopEvent abatement;
70 private FinalResult controlLoopTimedOut = null;
72 private boolean isActivated = false;
73 private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
74 private ControlLoopOperationManager currentOperation = null;
75 private transient TargetLock targetLock = null;
76 private AAIGETVnfResponse vnfResponse = null;
77 private AAIGETVserverResponse vserverResponse = null;
78 private static String aaiHostURL;
79 private static String aaiUser;
80 private static String aaiPassword;
82 private static Collection<String> requiredAAIKeys = new ArrayList<>();
84 requiredAAIKeys.add("AICVServerSelfLink");
85 requiredAAIKeys.add("AICIdentity");
86 requiredAAIKeys.add("is_closed_loop_disabled");
87 requiredAAIKeys.add("VM_NAME");
90 public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
91 this.closedLoopControlName = closedLoopControlName;
92 this.requestID = requestID;
95 public String getControlLoopResult() {
96 return controlLoopResult;
99 public void setControlLoopResult(String controlLoopResult) {
100 this.controlLoopResult = controlLoopResult;
103 public Integer getNumOnsets() {
107 public void setNumOnsets(Integer numOnsets) {
108 this.numOnsets = numOnsets;
111 public Integer getNumAbatements() {
112 return numAbatements;
115 public void setNumAbatements(Integer numAbatements) {
116 this.numAbatements = numAbatements;
119 public boolean isActivated() {
123 public void setActivated(boolean isActivated) {
124 this.isActivated = isActivated;
127 public VirtualControlLoopEvent getOnsetEvent() {
131 public VirtualControlLoopEvent getAbatementEvent() {
132 return this.abatement;
135 public ControlLoopProcessor getProcessor() {
136 return this.processor;
139 public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
140 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
143 // This method should ONLY be called ONCE
145 if (this.isActivated) {
146 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
149 // Syntax check the event
151 checkEventSyntax(event);
153 // At this point we are good to go with this event
158 notification.notification = ControlLoopNotificationType.ACTIVE;
160 // Set ourselves as active
162 this.isActivated = true;
163 } catch (ControlLoopException e) {
164 logger.error("{}: activate threw: ",this, e);
165 notification.notification = ControlLoopNotificationType.REJECTED;
166 notification.message = e.getMessage();
173 public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
174 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
177 // This method should ONLY be called ONCE
179 if (this.isActivated) {
180 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
183 // Syntax check the event
185 checkEventSyntax(event);
190 if (yamlSpecification == null || yamlSpecification.length() < 1) {
191 throw new ControlLoopException("yaml specification is null or 0 length");
193 String decodedYaml = null;
195 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
196 if (decodedYaml != null && decodedYaml.length() > 0) {
197 yamlSpecification = decodedYaml;
199 } catch (UnsupportedEncodingException e) {
200 logger.error("{}: activate threw: ",this, e);
203 // Parse the YAML specification
205 this.processor = new ControlLoopProcessor(yamlSpecification);
208 // At this point we are good to go with this event
215 notification.notification = ControlLoopNotificationType.ACTIVE;
217 // Set ourselves as active
219 this.isActivated = true;
220 } catch (ControlLoopException e) {
221 logger.error("{}: activate threw: ",this, e);
222 notification.notification = ControlLoopNotificationType.REJECTED;
223 notification.message = e.getMessage();
228 public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
230 // Check if they activated us
232 if (this.isActivated == false) {
233 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
236 // Make sure we are expecting this call.
238 if (this.onset == null) {
239 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
242 // Ok, start creating the notification
244 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
246 // Check if the overall control loop has timed out
248 if (this.isControlLoopTimedOut()) {
250 // Yes we have timed out
252 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
253 notification.message = "Control Loop timed out";
254 notification.history.addAll(this.controlLoopHistory);
258 // Check if the current policy is Final
260 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
261 if (result == null) {
263 // we are not at a final result
269 case FINAL_FAILURE_EXCEPTION:
270 notification.message = "Exception in processing closed loop";
272 case FINAL_FAILURE_RETRIES:
273 case FINAL_FAILURE_TIMEOUT:
274 case FINAL_FAILURE_GUARD:
275 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
278 notification.notification = ControlLoopNotificationType.FINAL_OPENLOOP;
281 notification.notification = ControlLoopNotificationType.FINAL_SUCCESS;
287 // Be sure to add all the history
289 notification.history.addAll(this.controlLoopHistory);
293 public ControlLoopOperationManager processControlLoop() throws ControlLoopException, AAIException {
295 // Check if they activated us
297 if (this.isActivated == false) {
298 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
301 // Make sure we are expecting this call.
303 if (this.onset == null) {
304 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
307 // Is there a current operation?
309 if (this.currentOperation != null) {
311 // Throw an exception, or simply return the current operation?
313 throw new ControlLoopException("Already working an Operation, do not call this method.");
316 // Ensure we are not FINAL
318 VirtualControlLoopNotification notification = this.isControlLoopFinal();
319 if (notification != null) {
321 // This is weird, we require them to call the isControlLoopFinal() method first
323 // We should really abstract this and avoid throwing an exception, because it really
324 // isn't an exception.
326 throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
329 // Not final so get the policy that needs to be worked on.
331 Policy policy = this.processor.getCurrentPolicy();
332 if (policy == null) {
333 throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
336 // And setup an operation
338 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
342 return this.currentOperation;
345 public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
347 // Verify we have a current operation
349 if (this.currentOperation != null) {
351 // Validate they are finishing the current operation
352 // PLD - this is simply comparing the policy. Do we want to equals the whole object?
354 if (this.currentOperation.policy.equals(operation.policy)) {
355 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(), this.currentOperation.getOperationResult());
359 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
361 // Move to the next Policy
363 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
365 // Just null this out
367 this.currentOperation = null;
369 // TODO: Release our lock
373 logger.debug("Cannot finish current operation {} does not match given operation {}", this.currentOperation.policy, operation.policy);
376 throw new ControlLoopException("No operation to finish.");
379 public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
383 if (this.currentOperation == null) {
384 throw new ControlLoopException("Do not have a current operation.");
387 // Have we acquired it already?
389 if (this.targetLock != null) {
391 // TODO: Make sure the current lock is for the same target.
392 // Currently, it should be. But in the future it may not.
394 return new LockResult<GuardResult, TargetLock>(GuardResult.LOCK_ACQUIRED, this.targetLock);
399 LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
400 this.currentOperation.policy.getTarget().getType(),
401 this.currentOperation.getTargetEntity(),
402 this.onset.requestID,
407 if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
409 // Yes, let's save it
411 this.targetLock = lockResult.getB();
417 public synchronized TargetLock unlockCurrentOperation() {
418 if (this.targetLock == null) {
421 if (PolicyGuard.unlockTarget(this.targetLock) == true) {
422 TargetLock returnLock = this.targetLock;
423 this.targetLock = null;
429 public enum NEW_EVENT_STATUS {
433 SUBSEQUENT_ABATEMENT,
438 public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) {
440 this.checkEventSyntax(event);
441 if (event.closedLoopEventStatus == ControlLoopEventStatus.ONSET) {
443 // Check if this is our original ONSET
445 if (event.equals(this.onset)) {
449 return NEW_EVENT_STATUS.FIRST_ONSET;
452 // Log that we got an onset
455 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
456 } else if (event.closedLoopEventStatus == ControlLoopEventStatus.ABATED) {
458 // Have we already got an abatement?
460 if (this.abatement == null) {
464 this.abatement = event;
466 // Keep track that we received another
468 this.numAbatements++;
472 return NEW_EVENT_STATUS.FIRST_ABATEMENT;
475 // Keep track that we received another
477 this.numAbatements++;
481 return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
484 return NEW_EVENT_STATUS.SYNTAX_ERROR;
486 } catch (ControlLoopException e) {
487 logger.error("{}: onNewEvent threw: ",this, e);
488 return NEW_EVENT_STATUS.SYNTAX_ERROR;
492 public VirtualControlLoopNotification setControlLoopTimedOut() {
493 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
494 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
495 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
496 notification.message = "Control Loop timed out";
497 notification.history.addAll(this.controlLoopHistory);
501 public boolean isControlLoopTimedOut() {
502 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
505 public int getControlLoopTimeout(Integer defaultTimeout) {
506 if (this.processor != null && this.processor.getControlLoop() != null) {
507 return this.processor.getControlLoop().getTimeout();
509 if (defaultTimeout != null) {
510 return defaultTimeout;
515 public AAIGETVnfResponse getVnfResponse() {
519 public AAIGETVserverResponse getVserverResponse() {
520 return vserverResponse;
523 public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
524 if (event.closedLoopEventStatus == null ||
525 (event.closedLoopEventStatus != ControlLoopEventStatus.ONSET &&
526 event.closedLoopEventStatus != ControlLoopEventStatus.ABATED)) {
527 throw new ControlLoopException("Invalid value in closedLoopEventStatus");
529 if (event.closedLoopControlName == null || event.closedLoopControlName.length() < 1) {
530 throw new ControlLoopException("No control loop name");
532 if (event.requestID == null) {
533 throw new ControlLoopException("No request ID");
535 if (event.closedLoopEventStatus == ControlLoopEventStatus.ABATED) {
538 if (event.AAI == null) {
539 throw new ControlLoopException("AAI is null");
541 if (event.AAI.get("generic-vnf.vnf-id") == null && event.AAI.get("vserver.vserver-name") == null &&
542 event.AAI.get("generic-vnf.vnf-name") == null) {
543 throw new ControlLoopException("generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
545 if (event.AAI.get("vserver.is-closed-loop-disabled") == null) {
547 if (event.AAI.get("generic-vnf.vnf-id") != null) {
548 vnfResponse = getAAIVnfInfo(event);
549 if (vnfResponse == null) {
550 throw new ControlLoopException("AAI Response is null (query by vnf-id)");
552 if (vnfResponse.requestError != null) {
553 throw new ControlLoopException("AAI Responded with a request error (query by vnf-id)");
555 if (isClosedLoopDisabled(vnfResponse) == true) {
556 throw new ControlLoopException("is-closed-loop-disabled is set to true");
558 } else if (event.AAI.get("generic-vnf.vnf-name") != null) {
559 vnfResponse = getAAIVnfInfo(event);
560 if (vnfResponse == null) {
561 throw new ControlLoopException("AAI Response is null (query by vnf-name)");
563 if (vnfResponse.requestError != null) {
564 throw new ControlLoopException("AAI Responded with a request error (query by vnf-name)");
566 if (isClosedLoopDisabled(vnfResponse) == true) {
567 throw new ControlLoopException("is-closed-loop-disabled is set to true");
569 } else if (event.AAI.get("vserver.vserver-name") != null) {
570 vserverResponse = getAAIVserverInfo(event);
571 if (vserverResponse == null) {
572 throw new ControlLoopException("AAI Response is null (query by vserver-name)");
574 if (vserverResponse.requestError != null) {
575 throw new ControlLoopException("AAI responded with a request error (query by vserver-name)");
577 if (isClosedLoopDisabled(vserverResponse) == true) {
578 throw new ControlLoopException("is-closed-loop-disabled is set to true");
581 } catch (Exception e) {
582 logger.error("Exception from getAAIInfo: ", e);
583 throw new ControlLoopException("Exception from getAAIInfo: " + e.toString());
585 } else if (isClosedLoopDisabled(event)) {
586 throw new ControlLoopException("is-closed-loop-disabled is set to true");
588 if (event.target == null || event.target.length() < 1) {
589 throw new ControlLoopException("No target field");
590 } else if (! event.target.equalsIgnoreCase("VM_NAME") &&
591 ! event.target.equalsIgnoreCase("VNF_NAME") &&
592 ! event.target.equalsIgnoreCase("vserver.vserver-name") &&
593 ! event.target.equalsIgnoreCase("generic-vnf.vnf-id") &&
594 ! event.target.equalsIgnoreCase("generic-vnf.vnf-name") ) {
595 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
599 public static boolean isClosedLoopDisabled(AAIGETVnfResponse aaiResponse) {
600 if (aaiResponse != null && aaiResponse.isClosedLoopDisabled != null) {
601 String value = aaiResponse.isClosedLoopDisabled;
602 if ("true".equalsIgnoreCase(value) || "T".equalsIgnoreCase(value) ||
603 "yes".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value)) {
611 public static boolean isClosedLoopDisabled(AAIGETVserverResponse aaiResponse) {
612 if (aaiResponse != null && aaiResponse.isClosedLoopDisabled != null) {
613 String value = aaiResponse.isClosedLoopDisabled;
614 if ("true".equalsIgnoreCase(value) || "T".equalsIgnoreCase(value) ||
615 "yes".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value)) {
623 public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
624 if ("true".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
625 "T".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
626 "yes".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
627 "Y".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled"))) {
633 public static AAIGETVserverResponse getAAIVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
634 UUID requestID = event.requestID;
635 AAIGETVserverResponse response = null;
636 String vserverName = event.AAI.get("vserver.vserver-name");
639 if (vserverName != null) {
640 aaiHostURL = PolicyEngine.manager.getEnvironmentProperty("aai.url");
641 aaiUser = PolicyEngine.manager.getEnvironmentProperty("aai.username");
642 aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
643 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
644 String url = aaiHostURL + aaiGetQueryByVserver;
645 logger.info("url: " + url);
646 response = AAIManager.getQueryByVserverName(url, aaiUser, aaiPassword, requestID, vserverName);
648 } catch (Exception e) {
649 logger.error("getAAIVserverInfo exception: ", e);
650 throw new ControlLoopException("Exception in getAAIVserverInfo: ", e);
656 public static AAIGETVnfResponse getAAIVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
657 UUID requestID = event.requestID;
658 AAIGETVnfResponse response = null;
659 String vnfName = event.AAI.get("generic-vnf.vnf-name");
660 String vnfID = event.AAI.get("generic-vnf.vnf-id");
662 aaiHostURL = PolicyEngine.manager.getEnvironmentProperty("aai.url");
663 aaiUser = PolicyEngine.manager.getEnvironmentProperty("aai.username");
664 aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
667 if (vnfName != null) {
668 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
669 String url = aaiHostURL + aaiGetQueryByVnfName;
670 logger.info("url: " + url);
671 response = AAIManager.getQueryByVnfName(url, aaiUser, aaiPassword, requestID, vnfName);
672 } else if (vnfID != null) {
673 String aaiGetQueryByVnfID = "/aai/v11/network/generic-vnfs/generic-vnf/";
674 String url = aaiHostURL + aaiGetQueryByVnfID;
675 logger.info("url: " + url);
676 response = AAIManager.getQueryByVnfID(url, aaiUser, aaiPassword, requestID, vnfID);
678 } catch (Exception e) {
679 logger.error("getAAIVnfInfo exception: ", e);
680 throw new ControlLoopException("Exception in getAAIVnfInfo: ", e);
687 public boolean isActive() {
693 public boolean releaseLock() {
699 public String toString() {
700 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestID=" + requestID
701 + ", processor=" + processor + ", onset=" + (onset != null ? onset.requestID : "null") + ", numOnsets=" + numOnsets + ", numAbatements="
702 + numAbatements + ", isActivated="
703 + isActivated + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";