d1d2cefd20d62e1976249862c4a703bbb6c1682d
[policy/drools-applications.git] /
1 /*-
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.onap.policy.controlloop.eventmanager;
22
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;
30
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;
36
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;
46
47 public class ControlLoopEventManager implements LockCallback, Serializable {
48         
49         /**
50          * 
51          */
52         private static final long serialVersionUID = -1216568161322872641L;
53         public final String closedLoopControlName;
54         public final UUID requestID;
55         
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;
63
64         private boolean isActivated = false;
65         private LinkedList<ControlLoopOperation> controlLoopHistory = new LinkedList<ControlLoopOperation>();
66         private ControlLoopOperationManager currentOperation = null;
67         private TargetLock targetLock = null;
68         
69         private static Collection<String> requiredAAIKeys = new ArrayList<String>();
70         static {
71                 requiredAAIKeys.add("AICVServerSelfLink");
72                 requiredAAIKeys.add("AICIdentity");
73                 requiredAAIKeys.add("is_closed_loop_disabled");
74                 requiredAAIKeys.add("VM_NAME");
75         }
76
77         public ControlLoopEventManager(String closedLoopControlName, UUID requestID) {
78                 this.closedLoopControlName = closedLoopControlName;
79                 this.requestID = requestID;
80         }
81         
82         public String getControlLoopResult() {
83                 return controlLoopResult;
84         }
85         
86         public void setControlLoopResult(String controlLoopResult) {
87                 this.controlLoopResult = controlLoopResult;
88         }
89         
90         public Integer getNumOnsets() {
91                 return numOnsets;
92         }
93
94         public void setNumOnsets(Integer numOnsets) {
95                 this.numOnsets = numOnsets;
96         }
97
98         public Integer getNumAbatements() {
99                 return numAbatements;
100         }
101
102         public void setNumAbatements(Integer numAbatements) {
103                 this.numAbatements = numAbatements;
104         }
105
106         public boolean isActivated() {
107                 return isActivated;
108         }
109
110         public void setActivated(boolean isActivated) {
111                 this.isActivated = isActivated;
112         }
113         
114         public VirtualControlLoopEvent  getOnsetEvent() {
115                 return this.onset;
116         }
117         
118         public VirtualControlLoopEvent getAbatementEvent() {
119                 return this.abatement;
120         }
121         
122         public ControlLoopProcessor getProcessor() {
123                 return this.processor;
124         }
125
126         public VirtualControlLoopNotification   activate(VirtualControlLoopEvent event) {
127                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
128                 try {
129                         //
130                         // This method should ONLY be called ONCE
131                         //
132                         if (this.isActivated) {
133                                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
134                         }
135                         //
136                         // Syntax check the event
137                         //
138                         checkEventSyntax(event);
139                         //
140                         // At this point we are good to go with this event
141                         //
142                         this.onset = event;
143                         this.numOnsets = 1;
144                         //
145                         notification.notification = ControlLoopNotificationType.ACTIVE;
146                         //
147                         // Set ourselves as active
148                         //
149                         this.isActivated = true;
150                 } catch (ControlLoopException e) {
151                         notification.notification = ControlLoopNotificationType.REJECTED;
152                         notification.message = e.getMessage();
153                 }
154                 return notification;
155         }
156         
157         
158         
159         public VirtualControlLoopNotification   activate(String yamlSpecification, VirtualControlLoopEvent event) {
160                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(event);
161                 try {
162                         //
163                         // This method should ONLY be called ONCE
164                         //
165                         if (this.isActivated) {
166                                 throw new ControlLoopException("ControlLoopEventManager has already been activated.");
167                         }
168                         //
169                         // Syntax check the event
170                         //
171                         checkEventSyntax(event);
172         
173                         //
174                         // Check the YAML
175                         //
176                         if (yamlSpecification == null || yamlSpecification.length() < 1) {
177                                 throw new ControlLoopException("yaml specification is null or 0 length");
178                         }
179                         String decodedYaml = null;
180                         try {
181                                 decodedYaml = URLDecoder.decode(yamlSpecification, "UTF-8");
182                                 if (decodedYaml != null && decodedYaml.length() > 0) {
183                                         yamlSpecification = decodedYaml;
184                                 }
185                         } catch (UnsupportedEncodingException e) {
186                         }
187                         //
188                         // Parse the YAML specification
189                         //
190                         this.processor = new ControlLoopProcessor(yamlSpecification);
191                         
192                         //
193                         // At this point we are good to go with this event
194                         //
195                         this.onset = event;
196                         this.numOnsets = 1;
197                         //
198                         //
199                         //
200                         notification.notification = ControlLoopNotificationType.ACTIVE;
201                         //
202                         // Set ourselves as active
203                         //
204                         this.isActivated = true;
205                 } catch (ControlLoopException e) {
206                         notification.notification = ControlLoopNotificationType.REJECTED;
207                         notification.message = e.getMessage();
208                 }
209                 return notification;
210         }
211         
212         public VirtualControlLoopNotification   isControlLoopFinal() throws ControlLoopException {
213                 //
214                 // Check if they activated us
215                 //
216                 if (this.isActivated == false) {
217                         throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
218                 }
219                 //
220                 // Make sure we are expecting this call.
221                 //
222                 if (this.onset == null) {
223                         throw new ControlLoopException("No onset event for ControlLoopEventManager.");
224                 }
225                 //
226                 // Ok, start creating the notification
227                 //
228                 VirtualControlLoopNotification notification = new VirtualControlLoopNotification(this.onset);
229                 //
230                 // Check if the overall control loop has timed out
231                 //
232                 if (this.isControlLoopTimedOut()) {
233                         //
234                         // Yes we have timed out
235                         //
236                         notification.notification = ControlLoopNotificationType.FINAL_FAILURE;
237                         notification.message = "Control Loop timed out";
238                         notification.history.addAll(this.controlLoopHistory);
239                         return notification;                    
240                 }
241                 //
242                 // Check if the current policy is Final
243                 //
244                 FinalResult result = this.processor.checkIsCurrentPolicyFinal();
245                 if (result == null) {
246                         //
247                         // we are not at a final result
248                         //
249                         return null;
250                 }
251         
252                 switch (result) {
253                 case FINAL_FAILURE:
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;
259                         break;
260                 case FINAL_OPENLOOP:
261                         notification.notification = ControlLoopNotificationType.FINAL_OPENLOOP;
262                         break;
263                 case FINAL_SUCCESS:
264                         notification.notification = ControlLoopNotificationType.FINAL_SUCCESS;
265                         break;
266                 default:
267                         return null;
268                 }
269                 //
270                 // Be sure to add all the history
271                 //
272                 notification.history.addAll(this.controlLoopHistory);
273                 return notification;
274         }
275                 
276         public ControlLoopOperationManager      processControlLoop() throws ControlLoopException {
277                 //
278                 // Check if they activated us
279                 //
280                 if (this.isActivated == false) {
281                         throw new ControlLoopException("ControlLoopEventManager MUST be activated first.");
282                 }
283                 //
284                 // Make sure we are expecting this call.
285                 //
286                 if (this.onset == null) {
287                         throw new ControlLoopException("No onset event for ControlLoopEventManager.");
288                 }
289                 //
290                 // Is there a current operation?
291                 //
292                 if (this.currentOperation != null) {
293                         //
294                         // Throw an exception, or simply return the current operation?
295                         //
296                         throw new ControlLoopException("Already working an Operation, do not call this method.");
297                 }
298                 //
299                 // Ensure we are not FINAL
300                 //
301                 VirtualControlLoopNotification notification = this.isControlLoopFinal();
302                 if (notification != null) {
303                         //
304                         // This is weird, we require them to call the isControlLoopFinal() method first
305                         //
306                         // We should really abstract this and avoid throwing an exception, because it really
307                         // isn't an exception.
308                         //
309                         throw new ControlLoopException("Control Loop is in FINAL state, do not call this method.");
310                 }
311                 //
312                 // Not final so get the policy that needs to be worked on.
313                 //
314                 Policy policy = this.processor.getCurrentPolicy();
315                 if (policy == null) {
316                         throw new ControlLoopException("ControlLoopEventManager: processor came upon null Policy.");
317                 }
318                 //
319                 // And setup an operation
320                 //
321                 this.currentOperation = new ControlLoopOperationManager(this.onset, policy, this);
322                 //
323                 // Return it
324                 //
325                 return this.currentOperation;
326         }
327         
328         public void finishOperation(ControlLoopOperationManager operation) throws ControlLoopException {
329                 //
330                 // Verify we have a current operation
331                 //
332                 if (this.currentOperation != null) {
333                         //
334                         // Validate they are finishing the current operation
335                         // PLD - this is simply comparing the policy. Do we want to equals the whole object?
336                         //
337                         if (this.currentOperation.policy.equals(operation.policy)) {
338                                 System.out.println("Finishing " + this.currentOperation.policy.getRecipe() + " result is " + this.currentOperation.getOperationResult());
339                                 //
340                                 // Save history
341                                 //
342                                 this.controlLoopHistory.addAll(this.currentOperation.getHistory());
343                                 //
344                                 // Move to the next Policy
345                                 //
346                                 this.processor.nextPolicyForResult(this.currentOperation.getOperationResult());
347                                 //
348                                 // Just null this out
349                                 //
350                                 this.currentOperation = null;
351                                 //
352                                 // TODO: Release our lock
353                                 //
354                                 return;
355                         }
356                         System.out.println("Cannot finish current operation " + this.currentOperation.policy + " does not match given operation " + operation.policy);
357                         return;
358                 }
359                 throw new ControlLoopException("No operation to finish.");
360         }
361         
362         public synchronized LockResult<GuardResult, TargetLock> lockCurrentOperation() throws ControlLoopException {
363                 //
364                 // Sanity check
365                 //
366                 if (this.currentOperation == null) {
367                         throw new ControlLoopException("Do not have a current operation.");
368                 }
369                 //
370                 // Have we acquired it already?
371                 //
372                 if (this.targetLock != null) {
373                         //
374                         // TODO: Make sure the current lock is for the same target.
375                         // Currently, it should be. But in the future it may not.
376                         //
377                         return new LockResult<GuardResult, TargetLock>(GuardResult.LOCK_ACQUIRED, this.targetLock);
378                 } else {
379                         //
380                         // Ask the Guard
381                         //
382                         LockResult<GuardResult, TargetLock> lockResult = PolicyGuard.lockTarget(
383                                                                                                                                                 this.currentOperation.policy.getTarget().getType(), 
384                                                                                                                                                 this.getTargetInstance(this.currentOperation.policy),
385                                                                                                                                                 this.onset.requestID,
386                                                                                                                                                 this);
387                         //
388                         // Was it acquired?
389                         //
390                         if (lockResult.getA().equals(GuardResult.LOCK_ACQUIRED)) {
391                                 //
392                                 // Yes, let's save it
393                                 //
394                                 this.targetLock = lockResult.getB();
395                         }
396                         return lockResult;
397                 }
398         }
399         
400         public synchronized TargetLock unlockCurrentOperation() {
401                 if (this.targetLock == null) {
402                         return null;
403                 }
404                 if (PolicyGuard.unlockTarget(this.targetLock) == true) {
405                         TargetLock returnLock = this.targetLock;
406                         this.targetLock = null;
407                         return returnLock;
408                 }
409                 return null;
410         }
411         
412         public enum NEW_EVENT_STATUS {
413                 FIRST_ONSET,
414                 SUBSEQUENT_ONSET,
415                 FIRST_ABATEMENT,
416                 SUBSEQUENT_ABATEMENT,
417                 SYNTAX_ERROR
418                 ;
419         }
420                 
421         public NEW_EVENT_STATUS onNewEvent(VirtualControlLoopEvent event) {
422                 try {
423                         ControlLoopEventManager.checkEventSyntax(event);
424                         if (event.closedLoopEventStatus == ControlLoopEventStatus.ONSET) {
425                                 //
426                                 // Check if this is our original ONSET
427                                 //
428                                 if (event.equals(this.onset)) {
429                                         //
430                                         // DO NOT retract it
431                                         //
432                                         return NEW_EVENT_STATUS.FIRST_ONSET;
433                                 }
434                                 //
435                                 // Log that we got an onset
436                                 //
437                                 this.numOnsets++;
438                                 return NEW_EVENT_STATUS.SUBSEQUENT_ONSET;
439                         } else if (event.closedLoopEventStatus == ControlLoopEventStatus.ABATED) {
440                                 //
441                                 // Have we already got an abatement?
442                                 //
443                                 if (this.abatement == null) {
444                                         //
445                                         // Save this
446                                         //
447                                         this.abatement = event;
448                                         //
449                                         // Keep track that we received another
450                                         //
451                                         this.numAbatements++;
452                                         //
453                                         //
454                                         //
455                                         return NEW_EVENT_STATUS.FIRST_ABATEMENT;
456                                 } else {
457                                         //
458                                         // Keep track that we received another
459                                         //
460                                         this.numAbatements++;
461                                         //
462                                         //
463                                         //
464                                         return NEW_EVENT_STATUS.SUBSEQUENT_ABATEMENT;
465                                 }
466                         } else {
467                                 return NEW_EVENT_STATUS.SYNTAX_ERROR;
468                         }
469                 } catch (ControlLoopException e) {
470                         return NEW_EVENT_STATUS.SYNTAX_ERROR;
471                 }
472         }
473         
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);
480                 return notification;                    
481         }
482         
483         public boolean isControlLoopTimedOut() {
484                 return (this.controlLoopTimedOut == FinalResult.FINAL_FAILURE_TIMEOUT);
485         }
486         
487         public int      getControlLoopTimeout(Integer defaultTimeout) {
488                 if (this.processor != null && this.processor.getControlLoop() != null) {
489                         return this.processor.getControlLoop().getTimeout();
490                 }
491                 if (defaultTimeout != null) {
492                         return defaultTimeout;
493                 }
494                 return 0;
495         }
496         
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");
502                 }
503                 if (event.closedLoopControlName == null || event.closedLoopControlName.length() < 1) {
504                         throw new ControlLoopException("No control loop name");
505                 }
506                 if (event.requestID == null) {
507                         throw new ControlLoopException("No request ID");
508                 }
509                 if (event.AAI == null) {
510                         throw new ControlLoopException("AAI is null");
511                 }
512                 if (event.AAI.get("vserver.is-closed-loop-disabled") == null) {
513                         throw new ControlLoopException("vserver.is-closed-loop-disabled information missing");
514                 }
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");
520                 }
521                 if (event.target == null || event.target.length() < 1) {
522                         throw new ControlLoopException("No target field");
523                 } else {
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");
529                         }
530                 }
531         }
532
533         @Override
534         public boolean isActive() {
535                 // TODO
536                 return true;
537         }
538
539         @Override
540         public boolean releaseLock() {
541                 // TODO
542                 return false;
543         }
544
545         public String getTargetInstance(Policy policy) {
546                 if (policy.getTarget() != null) {
547                         if (policy.getTarget().getType() != null) {
548                                 switch(policy.getTarget().getType()) {
549                                 case PNF:
550                                         break;
551                                 case VM:
552                                         if (this.onset.target.equalsIgnoreCase("vserver.vserver-name")) {
553                                                 return this.onset.AAI.get("vserver.vserver-name");
554                                         }
555                                         break;
556                                 default:
557                                         break;
558                                 }
559                         }
560                 }
561                 return null;
562         }
563
564         @Override
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 + "]";
570         }
571         
572 }