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.onap.policy.drools.system.PolicyEngine;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
52 public class ControlLoopEventManager implements LockCallback, Serializable {
57 private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
59 private static final long serialVersionUID = -1216568161322872641L;
60 public final String closedLoopControlName;
61 public final UUID requestID;
63 private String controlLoopResult;
64 private transient ControlLoopProcessor processor = null;
65 private VirtualControlLoopEvent onset;
66 private Integer numOnsets = 0;
67 private Integer numAbatements = 0;
68 private VirtualControlLoopEvent abatement;
69 private FinalResult controlLoopTimedOut = null;
71 private boolean isActivated = false;
72 private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<>();
73 private ControlLoopOperationManager currentOperation = null;
74 private transient TargetLock targetLock = null;
75 private AAIGETVnfResponse vnfResponse = null;
76 private AAIGETVserverResponse vserverResponse = null;
77 private static String aaiHostURL;
78 private static String aaiUser;
79 private static String aaiPassword;
81 private static Collection<String> requiredAAIKeys = new ArrayList<>();
83 requiredAAIKeys.add("AICVServerSelfLink");
84 requiredAAIKeys.add("AICIdentity");
85 requiredAAIKeys.add("is_closed_loop_disabled");
86 requiredAAIKeys.add("VM_NAME");
89 public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
90 this.closedLoopControlName = closedLoopControlName;
91 this.requestID = requestID;
94 public String getControlLoopResult() {
95 return controlLoopResult;
98 public void setControlLoopResult(String controlLoopResult) {
99 this.controlLoopResult = controlLoopResult;
102 public Integer getNumOnsets() {
106 public void setNumOnsets(Integer numOnsets) {
107 this.numOnsets = numOnsets;
110 public Integer getNumAbatements() {
111 return numAbatements;
114 public void setNumAbatements(Integer numAbatements) {
115 this.numAbatements = numAbatements;
118 public boolean isActivated() {
122 public void setActivated(boolean isActivated) {
123 this.isActivated = isActivated;
126 public VirtualControlLoopEvent getOnsetEvent() {
130 public VirtualControlLoopEvent getAbatementEvent() {
131 return this.abatement;
134 public ControlLoopProcessor getProcessor() {
135 return this.processor;
138 public VirtualControlLoopNotification activate(VirtualControlLoopEvent event) {
139 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
142 // This method should ONLY be called ONCE
144 if (this.isActivated) {
145 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
148 // Syntax check the event
150 checkEventSyntax(event);
152 // At this point we are good to go with this event
157 notification.notification = ControlLoopNotificationType.ACTIVE;
159 // Set ourselves as active
161 this.isActivated = true;
162 } catch (ControlLoopException e) {
163 logger.error("{}: activate threw: ",this, e);
164 notification.notification = ControlLoopNotificationType.REJECTED;
165 notification.message = e.getMessage();
172 public VirtualControlLoopNotification activate(String yamlSpecification, VirtualControlLoopEvent event) {
173 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
176 // This method should ONLY be called ONCE
178 if (this.isActivated) {
179 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
182 // Syntax check the event
184 checkEventSyntax(event);
189 if (yamlSpecification == null || yamlSpecification.length() < 1) {
190 throw new ControlLoopException("yaml specification is null or 0 length");
192 String decodedYaml = null;
194 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
195 if (decodedYaml != null && decodedYaml.length() > 0) {
196 yamlSpecification = decodedYaml;
198 } catch (UnsupportedEncodingException e) {
199 logger.error("{}: activate threw: ",this, e);
202 // Parse the YAML specification
204 this.processor = new ControlLoopProcessor(yamlSpecification);
207 // At this point we are good to go with this event
214 notification.notification = ControlLoopNotificationType.ACTIVE;
216 // Set ourselves as active
218 this.isActivated = true;
219 } catch (ControlLoopException e) {
220 logger.error("{}: activate threw: ",this, e);
221 notification.notification = ControlLoopNotificationType.REJECTED;
222 notification.message = e.getMessage();
227 public VirtualControlLoopNotification isControlLoopFinal() throws ControlLoopException {
229 // Check if they activated us
231 if (this.isActivated == false) {
232 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
235 // Make sure we are expecting this call.
237 if (this.onset == null) {
238 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
241 // Ok, start creating the notification
243 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
245 // Check if the overall control loop has timed out
247 if (this.isControlLoopTimedOut()) {
249 // Yes we have timed out
251 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
252 notification.message = "Control Loop timed out";
253 notification.history.addAll(this.controlLoopHistory);
257 // Check if the current policy is Final
259 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
260 if (result == null) {
262 // we are not at a final result
268 case FINAL_FAILURE_EXCEPTION:
269 notification.message = "Exception in processing closed loop";
271 case FINAL_FAILURE_RETRIES:
272 case FINAL_FAILURE_TIMEOUT:
273 case FINAL_FAILURE_GUARD:
274 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
277 notification.notification = ControlLoopNotificationType.FINAL_OPENLOOP;
280 notification.notification = ControlLoopNotificationType.FINAL_SUCCESS;
286 // Be sure to add all the history
288 notification.history.addAll(this.controlLoopHistory);
292 public ControlLoopOperationManager processControlLoop() throws ControlLoopException {
294 // Check if they activated us
296 if (this.isActivated == false) {
297 throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
300 // Make sure we are expecting this call.
302 if (this.onset == null) {
303 throw new ControlLoopException("No onset event for ControlLoopEventManager.");
306 // Is there a current operation?
308 if (this.currentOperation != null) {
310 // Throw an exception, or simply return the current operation?
312 throw new ControlLoopException("Already working an Operation, do not call this method.");
315 // Ensure we are not FINAL
317 VirtualControlLoopNotification notification = this.isControlLoopFinal();
318 if (notification != null) {
320 // This is weird, we require them to call the isControlLoopFinal() method first
322 // We should really abstract this and avoid throwing an exception, because it really
323 // isn't an exception.
325 throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
328 // Not final so get the policy that needs to be worked on.
330 Policy policy = this.processor.getCurrentPolicy();
331 if (policy == null) {
332 throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
335 // And setup an operation
337 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
341 return this.currentOperation;
344 public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
346 // Verify we have a current operation
348 if (this.currentOperation != null) {
350 // Validate they are finishing the current operation
351 // PLD - this is simply comparing the policy. Do we want to equals the whole object?
353 if (this.currentOperation.policy.equals(operation.policy)) {
354 logger.debug("Finishing {} result is {}", this.currentOperation.policy.getRecipe(), this.currentOperation.getOperationResult());
358 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
360 // Move to the next Policy
362 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
364 // Just null this out
366 this.currentOperation = null;
368 // TODO: Release our lock
372 logger.debug("Cannot finish current operation {} does not match given operation {}", this.currentOperation.policy, operation.policy);
375 throw new ControlLoopException("No operation to finish.");
378 public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
382 if (this.currentOperation == null) {
383 throw new ControlLoopException("Do not have a current operation.");
386 // Have we acquired it already?
388 if (this.targetLock != null) {
390 // TODO: Make sure the current lock is for the same target.
391 // Currently, it should be. But in the future it may not.
393 return new LockResult<GuardResult, TargetLock>(GuardResult.LOCK_ACQUIRED, this.targetLock);
398 LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
399 this.currentOperation.policy.getTarget().getType(),
400 this.getTargetInstance(this.currentOperation.policy),
401 this.onset.requestID,
406 if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
408 // Yes, let's save it
410 this.targetLock = lockResult.getB();
416 public synchronized TargetLock unlockCurrentOperation() {
417 if (this.targetLock == null) {
420 if (PolicyGuard.unlockTarget(this.targetLock) == true) {
421 TargetLock returnLock = this.targetLock;
422 this.targetLock = null;
428 public enum NEW_EVENT_STATUS {
432 SUBSEQUENT_ABATEMENT,
437 public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) {
439 this.checkEventSyntax(event);
440 if (event.closedLoopEventStatus == ControlLoopEventStatus.ONSET) {
442 // Check if this is our original ONSET
444 if (event.equals(this.onset)) {
448 return NEW_EVENT_STATUS.FIRST_ONSET;
451 // Log that we got an onset
454 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
455 } else if (event.closedLoopEventStatus == ControlLoopEventStatus.ABATED) {
457 // Have we already got an abatement?
459 if (this.abatement == null) {
463 this.abatement = event;
465 // Keep track that we received another
467 this.numAbatements++;
471 return NEW_EVENT_STATUS.FIRST_ABATEMENT;
474 // Keep track that we received another
476 this.numAbatements++;
480 return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
483 return NEW_EVENT_STATUS.SYNTAX_ERROR;
485 } catch (ControlLoopException e) {
486 logger.error("{}: onNewEvent threw: ",this, e);
487 return NEW_EVENT_STATUS.SYNTAX_ERROR;
491 public VirtualControlLoopNotification setControlLoopTimedOut() {
492 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
493 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
494 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
495 notification.message = "Control Loop timed out";
496 notification.history.addAll(this.controlLoopHistory);
500 public boolean isControlLoopTimedOut() {
501 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
504 public int getControlLoopTimeout(Integer defaultTimeout) {
505 if (this.processor != null && this.processor.getControlLoop() != null) {
506 return this.processor.getControlLoop().getTimeout();
508 if (defaultTimeout != null) {
509 return defaultTimeout;
514 public AAIGETVnfResponse getVnfResponse() {
518 public AAIGETVserverResponse getVserverResponse() {
519 return vserverResponse;
522 public void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
523 if (event.closedLoopEventStatus == null ||
524 (event.closedLoopEventStatus != ControlLoopEventStatus.ONSET &&
525 event.closedLoopEventStatus != ControlLoopEventStatus.ABATED)) {
526 throw new ControlLoopException("Invalid value in closedLoopEventStatus");
528 if (event.closedLoopControlName == null || event.closedLoopControlName.length() < 1) {
529 throw new ControlLoopException("No control loop name");
531 if (event.requestID == null) {
532 throw new ControlLoopException("No request ID");
534 if (event.AAI == null) {
535 throw new ControlLoopException("AAI is null");
537 if (event.AAI.get("generic-vnf.vnf-id") == null && event.AAI.get("vserver.vserver-name") == null &&
538 event.AAI.get("generic-vnf.vnf-name") == null) {
539 throw new ControlLoopException("generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
541 if (event.AAI.get("vserver.is-closed-loop-disabled") == null) {
543 if (event.AAI.get("generic-vnf.vnf-id") != null) {
544 vnfResponse = getAAIVnfInfo(event);
545 if (vnfResponse == null) {
546 throw new ControlLoopException("AAI Response is null (query by vnf-id)");
548 if (vnfResponse.requestError != null) {
549 throw new ControlLoopException("AAI Responded with a request error (query by vnf-id)");
551 if (isClosedLoopDisabled(vnfResponse) == true) {
552 throw new ControlLoopException("is-closed-loop-disabled is set to true");
554 } else if (event.AAI.get("generic-vnf.vnf-name") != null) {
555 vnfResponse = getAAIVnfInfo(event);
556 if (vnfResponse == null) {
557 throw new ControlLoopException("AAI Response is null (query by vnf-name)");
559 if (vnfResponse.requestError != null) {
560 throw new ControlLoopException("AAI Responded with a request error (query by vnf-name)");
562 if (isClosedLoopDisabled(vnfResponse) == true) {
563 throw new ControlLoopException("is-closed-loop-disabled is set to true");
565 } else if (event.AAI.get("vserver.vserver-name") != null) {
566 vserverResponse = getAAIVserverInfo(event);
567 if (vserverResponse == null) {
568 throw new ControlLoopException("AAI Response is null (query by vserver-name)");
570 if (vserverResponse.requestError != null) {
571 throw new ControlLoopException("AAI responded with a request error (query by vserver-name)");
573 if (isClosedLoopDisabled(vserverResponse) == true) {
574 throw new ControlLoopException("is-closed-loop-disabled is set to true");
577 } catch (Exception e) {
578 logger.error("Exception from getAAIInfo: ", e);
579 throw new ControlLoopException("Exception from getAAIInfo: " + e.toString());
581 } else if (isClosedLoopDisabled(event)) {
582 throw new ControlLoopException("is-closed-loop-disabled is set to true");
584 if (event.target == null || event.target.length() < 1) {
585 throw new ControlLoopException("No target field");
587 if (! event.target.equalsIgnoreCase("VM_NAME") &&
588 ! event.target.equalsIgnoreCase("VNF_NAME") &&
589 ! event.target.equalsIgnoreCase("vserver.vserver-name") &&
590 ! event.target.equalsIgnoreCase("generic-vnf.vnf-id") &&
591 ! event.target.equalsIgnoreCase("generic-vnf.vnf-name") ) {
592 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
597 public static boolean isClosedLoopDisabled(AAIGETVnfResponse aaiResponse) {
598 if (aaiResponse != null && aaiResponse.isClosedLoopDisabled != null) {
599 String value = aaiResponse.isClosedLoopDisabled;
600 if ("true".equalsIgnoreCase(value) || "T".equalsIgnoreCase(value) ||
601 "yes".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value)) {
609 public static boolean isClosedLoopDisabled(AAIGETVserverResponse aaiResponse) {
610 if (aaiResponse != null && aaiResponse.isClosedLoopDisabled != null) {
611 String value = aaiResponse.isClosedLoopDisabled;
612 if ("true".equalsIgnoreCase(value) || "T".equalsIgnoreCase(value) ||
613 "yes".equalsIgnoreCase(value) || "Y".equalsIgnoreCase(value)) {
621 public static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
622 if ("true".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
623 "T".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
624 "yes".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled")) ||
625 "Y".equalsIgnoreCase(event.AAI.get("vserver.is-closed-loop-disabled"))) {
631 public static AAIGETVserverResponse getAAIVserverInfo(VirtualControlLoopEvent event) throws ControlLoopException {
632 UUID requestID = event.requestID;
633 AAIGETVserverResponse response = null;
634 String vserverName = event.AAI.get("vserver.vserver-name");
637 if (vserverName != null) {
638 aaiHostURL = PolicyEngine.manager.getEnvironmentProperty("aai.url");
639 aaiUser = PolicyEngine.manager.getEnvironmentProperty("aai.username");
640 aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
641 String aaiGetQueryByVserver = "/aai/v11/nodes/vservers?vserver-name=";
642 String url = aaiHostURL + aaiGetQueryByVserver;
643 logger.info("url: " + url);
644 response = AAIManager.getQueryByVserverName(url, aaiUser, aaiPassword, requestID, vserverName);
646 } catch (Exception e) {
647 logger.error("getAAIVserverInfo exception: ", e);
648 throw new ControlLoopException("Exception in getAAIVserverInfo: ", e);
654 public static AAIGETVnfResponse getAAIVnfInfo(VirtualControlLoopEvent event) throws ControlLoopException {
655 UUID requestID = event.requestID;
656 AAIGETVnfResponse response = null;
657 String vnfName = event.AAI.get("generic-vnf.vnf-name");
658 String vnfID = event.AAI.get("generic-vnf.vnf-id");
660 aaiHostURL = PolicyEngine.manager.getEnvironmentProperty("aai.url");
661 aaiUser = PolicyEngine.manager.getEnvironmentProperty("aai.username");
662 aaiPassword = PolicyEngine.manager.getEnvironmentProperty("aai.password");
665 if (vnfName != null) {
666 String aaiGetQueryByVnfName = "/aai/v11/network/generic-vnfs/generic-vnf?vnf-name=";
667 String url = aaiHostURL + aaiGetQueryByVnfName;
668 logger.info("url: " + url);
669 response = AAIManager.getQueryByVnfName(url, aaiUser, aaiPassword, requestID, vnfName);
670 } else if (vnfID != null) {
671 String aaiGetQueryByVnfID = "/aai/v11/network/generic-vnfs/generic-vnf/";
672 String url = aaiHostURL + aaiGetQueryByVnfID;
673 logger.info("url: " + url);
674 response = AAIManager.getQueryByVnfID(url, aaiUser, aaiPassword, requestID, vnfID);
676 } catch (Exception e) {
677 logger.error("getAAIVnfInfo exception: ", e);
678 throw new ControlLoopException("Exception in getAAIVnfInfo: ", e);
685 public boolean isActive() {
691 public boolean releaseLock() {
696 public String getTargetInstance(Policy policy) {
697 if (policy.getTarget() != null) {
698 if (policy.getTarget().getType() != null) {
699 switch(policy.getTarget().getType()) {
704 if (this.onset.target.equalsIgnoreCase("vserver.vserver-name")) {
705 return this.onset.AAI.get("vserver.vserver-name");
707 else if (this.onset.target.equalsIgnoreCase("generic-vnf.vnf-id")) {
708 return this.onset.AAI.get("generic-vnf.vnf-id");
710 else if (this.onset.target.equalsIgnoreCase("generic-vnf.vnf-name")) {
711 return this.onset.AAI.get("generic-vnf.vnf-name");
723 public String toString() {
724 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestID=" + requestID
725 + ", processor=" + processor + ", onset=" + (onset != null ? onset.requestID : "null") + ", numOnsets=" + numOnsets + ", numAbatements="
726 + numAbatements + ", isActivated="
727 + isActivated + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";