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 + "]";