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.controlloop.ControlLoopEventStatus;
 
  32 import org.onap.policy.controlloop.ControlLoopNotificationType;
 
  33 import org.onap.policy.controlloop.ControlLoopOperation;
 
  34 import org.onap.policy.controlloop.VirtualControlLoopEvent;
 
  35 import org.onap.policy.controlloop.VirtualControlLoopNotification;
 
  37 import org.onap.policy.controlloop.ControlLoopException;
 
  38 import org.onap.policy.controlloop.policy.FinalResult;
 
  39 import org.onap.policy.controlloop.policy.Policy;
 
  40 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
 
  41 import org.onap.policy.guard.GuardResult;
 
  42 import org.onap.policy.guard.LockCallback;
 
  43 import org.onap.policy.guard.PolicyGuard;
 
  44 import org.onap.policy.guard.PolicyGuard.LockResult;
 
  45 import org.onap.policy.guard.TargetLock;
 
  47 public class ControlLoopEventManager implements LockCallback, Serializable {
 
  52         private static final long serialVersionUID = -1216568161322872641L;
 
  53         public final String closedLoopControlName;
 
  54         public final UUID requestID;
 
  56         private String controlLoopResult;
 
  57         private ControlLoopProcessor processor = null;
 
  58         private VirtualControlLoopEvent onset;
 
  59         private Integer numOnsets = 0;
 
  60         private Integer numAbatements = 0;
 
  61         private VirtualControlLoopEvent abatement;
 
  62         private FinalResult controlLoopTimedOut = null;
 
  64         private boolean isActivated = false;
 
  65         private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<ControlLoopOperation>();
 
  66         private ControlLoopOperationManager currentOperation = null;
 
  67         private TargetLock targetLock = null;
 
  69         private static Collection<String> requiredAAIKeys = new ArrayList<String>();
 
  71                 requiredAAIKeys.add("AICVServerSelfLink");
 
  72                 requiredAAIKeys.add("AICIdentity");
 
  73                 requiredAAIKeys.add("is_closed_loop_disabled");
 
  74                 requiredAAIKeys.add("VM_NAME");
 
  77         public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
 
  78                 this.closedLoopControlName = closedLoopControlName;
 
  79                 this.requestID = requestID;
 
  82         public String getControlLoopResult() {
 
  83                 return controlLoopResult;
 
  86         public void setControlLoopResult(String controlLoopResult) {
 
  87                 this.controlLoopResult = controlLoopResult;
 
  90         public Integer getNumOnsets() {
 
  94         public void setNumOnsets(Integer numOnsets) {
 
  95                 this.numOnsets = numOnsets;
 
  98         public Integer getNumAbatements() {
 
 102         public void setNumAbatements(Integer numAbatements) {
 
 103                 this.numAbatements = numAbatements;
 
 106         public boolean isActivated() {
 
 110         public void setActivated(boolean isActivated) {
 
 111                 this.isActivated = isActivated;
 
 114         public VirtualControlLoopEvent  getOnsetEvent() {
 
 118         public VirtualControlLoopEvent getAbatementEvent() {
 
 119                 return this.abatement;
 
 122         public ControlLoopProcessor getProcessor() {
 
 123                 return this.processor;
 
 126         public VirtualControlLoopNotification   activate(VirtualControlLoopEvent event) {
 
 127                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
 
 130                         // This method should ONLY be called ONCE
 
 132                         if (this.isActivated) {
 
 133                                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
 
 136                         // Syntax check the event
 
 138                         checkEventSyntax(event);
 
 140                         // At this point we are good to go with this event
 
 145                         notification.notification = ControlLoopNotificationType.ACTIVE;
 
 147                         // Set ourselves as active
 
 149                         this.isActivated = true;
 
 150                 } catch (ControlLoopException e) {
 
 151                         notification.notification = ControlLoopNotificationType.REJECTED;
 
 152                         notification.message = e.getMessage();
 
 159         public VirtualControlLoopNotification   activate(String yamlSpecification, VirtualControlLoopEvent event) {
 
 160                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
 
 163                         // This method should ONLY be called ONCE
 
 165                         if (this.isActivated) {
 
 166                                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
 
 169                         // Syntax check the event
 
 171                         checkEventSyntax(event);
 
 176                         if (yamlSpecification == null || yamlSpecification.length() < 1) {
 
 177                                 throw new ControlLoopException("yaml specification is null or 0 length");
 
 179                         String decodedYaml = null;
 
 181                                 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
 
 182                                 if (decodedYaml != null && decodedYaml.length() > 0) {
 
 183                                         yamlSpecification = decodedYaml;
 
 185                         } catch (UnsupportedEncodingException e) {
 
 188                         // Parse the YAML specification
 
 190                         this.processor = new ControlLoopProcessor(yamlSpecification);
 
 193                         // At this point we are good to go with this event
 
 200                         notification.notification = ControlLoopNotificationType.ACTIVE;
 
 202                         // Set ourselves as active
 
 204                         this.isActivated = true;
 
 205                 } catch (ControlLoopException e) {
 
 206                         notification.notification = ControlLoopNotificationType.REJECTED;
 
 207                         notification.message = e.getMessage();
 
 212         public VirtualControlLoopNotification   isControlLoopFinal() throws ControlLoopException {
 
 214                 // Check if they activated us
 
 216                 if (this.isActivated == false) {
 
 217                         throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
 
 220                 // Make sure we are expecting this call.
 
 222                 if (this.onset == null) {
 
 223                         throw new ControlLoopException("No onset event for ControlLoopEventManager.");
 
 226                 // Ok, start creating the notification
 
 228                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
 
 230                 // Check if the overall control loop has timed out
 
 232                 if (this.isControlLoopTimedOut()) {
 
 234                         // Yes we have timed out
 
 236                         notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
 
 237                         notification.message = "Control Loop timed out";
 
 238                         notification.history.addAll(this.controlLoopHistory);
 
 242                 // Check if the current policy is Final
 
 244                 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
 
 245                 if (result == null) {
 
 247                         // we are not at a final result
 
 254                 case FINAL_FAILURE_EXCEPTION:
 
 255                 case FINAL_FAILURE_RETRIES:
 
 256                 case FINAL_FAILURE_TIMEOUT:
 
 257                 case FINAL_FAILURE_GUARD:
 
 258                         notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
 
 261                         notification.notification = ControlLoopNotificationType.FINAL_OPENLOOP;
 
 264                         notification.notification = ControlLoopNotificationType.FINAL_SUCCESS;
 
 270                 // Be sure to add all the history
 
 272                 notification.history.addAll(this.controlLoopHistory);
 
 276         public ControlLoopOperationManager      processControlLoop() throws ControlLoopException {
 
 278                 // Check if they activated us
 
 280                 if (this.isActivated == false) {
 
 281                         throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
 
 284                 // Make sure we are expecting this call.
 
 286                 if (this.onset == null) {
 
 287                         throw new ControlLoopException("No onset event for ControlLoopEventManager.");
 
 290                 // Is there a current operation?
 
 292                 if (this.currentOperation != null) {
 
 294                         // Throw an exception, or simply return the current operation?
 
 296                         throw new ControlLoopException("Already working an Operation, do not call this method.");
 
 299                 // Ensure we are not FINAL
 
 301                 VirtualControlLoopNotification notification = this.isControlLoopFinal();
 
 302                 if (notification != null) {
 
 304                         // This is weird, we require them to call the isControlLoopFinal() method first
 
 306                         // We should really abstract this and avoid throwing an exception, because it really
 
 307                         // isn't an exception.
 
 309                         throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
 
 312                 // Not final so get the policy that needs to be worked on.
 
 314                 Policy policy = this.processor.getCurrentPolicy();
 
 315                 if (policy == null) {
 
 316                         throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
 
 319                 // And setup an operation
 
 321                 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
 
 325                 return this.currentOperation;
 
 328         public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
 
 330                 // Verify we have a current operation
 
 332                 if (this.currentOperation != null) {
 
 334                         // Validate they are finishing the current operation
 
 335                         // PLD - this is simply comparing the policy. Do we want to equals the whole object?
 
 337                         if (this.currentOperation.policy.equals(operation.policy)) {
 
 338                                 System.out.println("Finishing " + this.currentOperation.policy.recipe + " result is " + this.currentOperation.getOperationResult());
 
 342                                 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
 
 344                                 // Move to the next Policy
 
 346                                 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
 
 348                                 // Just null this out
 
 350                                 this.currentOperation = null;
 
 352                                 // TODO: Release our lock
 
 356                         System.out.println("Cannot finish current operation " + this.currentOperation.policy + " does not match given operation " + operation.policy);
 
 359                 throw new ControlLoopException("No operation to finish.");
 
 362         public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
 
 366                 if (this.currentOperation == null) {
 
 367                         throw new ControlLoopException("Do not have a current operation.");
 
 370                 // Have we acquired it already?
 
 372                 if (this.targetLock != null) {
 
 374                         // TODO: Make sure the current lock is for the same target.
 
 375                         // Currently, it should be. But in the future it may not.
 
 377                         return new LockResult<GuardResult, TargetLock>(GuardResult.LOCK_ACQUIRED, this.targetLock);
 
 382                         LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
 
 383                                                                                                                                                 this.currentOperation.policy.target.type, 
 
 384                                                                                                                                                 this.getTargetInstance(this.currentOperation.policy),
 
 385                                                                                                                                                 this.onset.requestID,
 
 390                         if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
 
 392                                 // Yes, let's save it
 
 394                                 this.targetLock = lockResult.getB();
 
 400         public synchronized TargetLock unlockCurrentOperation() {
 
 401                 if (this.targetLock == null) {
 
 404                 if (PolicyGuard.unlockTarget(this.targetLock) == true) {
 
 405                         TargetLock returnLock = this.targetLock;
 
 406                         this.targetLock = null;
 
 412         public enum NEW_EVENT_STATUS {
 
 416                 SUBSEQUENT_ABATEMENT,
 
 421         public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) {
 
 423                         ControlLoopEventManager.checkEventSyntax(event);
 
 424                         if (event.closedLoopEventStatus == ControlLoopEventStatus.ONSET) {
 
 426                                 // Check if this is our original ONSET
 
 428                                 if (event.equals(this.onset)) {
 
 432                                         return NEW_EVENT_STATUS.FIRST_ONSET;
 
 435                                 // Log that we got an onset
 
 438                                 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
 
 439                         } else if (event.closedLoopEventStatus == ControlLoopEventStatus.ABATED) {
 
 441                                 // Have we already got an abatement?
 
 443                                 if (this.abatement == null) {
 
 447                                         this.abatement = event;
 
 449                                         // Keep track that we received another
 
 451                                         this.numAbatements++;
 
 455                                         return NEW_EVENT_STATUS.FIRST_ABATEMENT;
 
 458                                         // Keep track that we received another
 
 460                                         this.numAbatements++;
 
 464                                         return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
 
 467                                 return NEW_EVENT_STATUS.SYNTAX_ERROR;
 
 469                 } catch (ControlLoopException e) {
 
 470                         return NEW_EVENT_STATUS.SYNTAX_ERROR;
 
 474         public VirtualControlLoopNotification setControlLoopTimedOut() {
 
 475                 this.controlLoopTimedOut = FinalResult.FINAL_FAILURE_TIMEOUT;
 
 476                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
 
 477                 notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
 
 478                 notification.message = "Control Loop timed out";
 
 479                 notification.history.addAll(this.controlLoopHistory);
 
 483         public boolean isControlLoopTimedOut() {
 
 484                 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
 
 487         public int      getControlLoopTimeout(Integer defaultTimeout) {
 
 488                 if (this.processor != null && this.processor.getControlLoop() != null) {
 
 489                         return this.processor.getControlLoop().timeout;
 
 491                 if (defaultTimeout != null) {
 
 492                         return defaultTimeout;
 
 497         public static void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
 
 498                 if (event.closedLoopEventStatus == null || 
 
 499                                 (event.closedLoopEventStatus != ControlLoopEventStatus.ONSET &&
 
 500                                 event.closedLoopEventStatus != ControlLoopEventStatus.ABATED)) {
 
 501                         throw new ControlLoopException("Invalid value in closedLoopEventStatus");
 
 503                 if (event.closedLoopControlName == null || event.closedLoopControlName.length() < 1) {
 
 504                         throw new ControlLoopException("No control loop name");
 
 506                 if (event.requestID == null) {
 
 507                         throw new ControlLoopException("No request ID");
 
 509                 if (event.AAI == null) {
 
 510                         throw new ControlLoopException("AAI is null");
 
 512                 if (event.AAI.get("vserver.is-closed-loop-disabled") == null) {
 
 513                         throw new ControlLoopException("vserver.is-closed-loop-disabled information missing");
 
 515                 if (event.AAI.get("vserver.is-closed-loop-disabled").equalsIgnoreCase("true") ||
 
 516                                 event.AAI.get("vserver.is-closed-loop-disabled").equalsIgnoreCase("T") ||
 
 517                                 event.AAI.get("vserver.is-closed-loop-disabled").equalsIgnoreCase("yes") ||
 
 518                                 event.AAI.get("vserver.is-closed-loop-disabled").equalsIgnoreCase("Y")) {
 
 519                         throw new ControlLoopException("vserver.is-closed-loop-disabled is set to true");
 
 521                 if (event.target == null || event.target.length() < 1) {
 
 522                         throw new ControlLoopException("No target field");
 
 524                         if (! event.target.equalsIgnoreCase("VM_NAME") &&
 
 525                                 ! event.target.equalsIgnoreCase("VNF_NAME") &&
 
 526                                 ! event.target.equalsIgnoreCase("vserver.vserver-name") &&
 
 527                                 ! event.target.equalsIgnoreCase("generic-vnf.vnf-name") ) {
 
 528                                 throw new ControlLoopException("target field invalid - expecting VM_NAME or VNF_NAME");
 
 534         public boolean isActive() {
 
 540         public boolean releaseLock() {
 
 545         public String getTargetInstance(Policy policy) {
 
 546                 if (policy.target != null) {
 
 547                         if (policy.target.type != null) {
 
 548                                 switch(policy.target.type) {
 
 552                                         if (this.onset.target.equalsIgnoreCase("vserver.vserver-name")) {
 
 553                                                 return this.onset.AAI.get("vserver.vserver-name");
 
 565         public String toString() {
 
 566                 return "ControlLoopEventManager [closedLoopControlName=" + closedLoopControlName + ", requestID=" + requestID
 
 567                                 + ", processor=" + processor + ", onset=" + (onset != null ? onset.requestID : "null") + ", numOnsets=" + numOnsets + ", numAbatements="
 
 568                                 + numAbatements + ", isActivated="
 
 569                                 + isActivated + ", currentOperation=" + currentOperation + ", targetLock=" + targetLock + "]";