09f69fb0b9c7eeef831c7f3a61eb149bc9589cec
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * controlloop operation 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.sql.Timestamp;
25 import java.time.Instant;
26 import java.util.LinkedList;
27
28 import javax.persistence.EntityManager;
29 import javax.persistence.Persistence;
30
31 import org.onap.policy.appc.Response;
32 import org.onap.policy.appc.ResponseCode;
33 import org.onap.policy.controlloop.ControlLoopEvent;
34 import org.onap.policy.controlloop.ControlLoopOperation;
35 import org.onap.policy.controlloop.VirtualControlLoopEvent;
36 import org.onap.policy.controlloop.ControlLoopException;
37 import org.onap.policy.controlloop.policy.Policy;
38 import org.onap.policy.controlloop.policy.PolicyResult;
39 import org.onap.policy.controlloop.actor.appc.APPCActorServiceProvider;
40 import org.onap.policy.controlloop.actor.vfc.VFCActorServiceProvider;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45 public class ControlLoopOperationManager implements Serializable {
46         
47         /**
48          * 
49          */
50         private static final long serialVersionUID = -3773199283624595410L;
51         private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
52
53         @Override
54         public String toString() {
55                 return "ControlLoopOperationManager [onset=" + (onset != null ? onset.requestID : "null") + ", policy=" 
56                                 + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts
57                                 + ", policyResult=" + policyResult 
58                                 + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
59                                 + "]";
60         }
61
62         //
63         // These properties are not changeable, but accessible
64         // for Drools Rule statements.
65         //
66         //public final ATTControlLoopEvent onset;
67         public final ControlLoopEvent onset;
68         public final Policy policy;
69
70         //
71         // Properties used to track the Operation
72         //
73         private int attempts = 0;
74         private Operation currentOperation = null;
75         private LinkedList<Operation> operationHistory = new LinkedList<Operation>();
76         private PolicyResult policyResult = null;
77         private ControlLoopEventManager eventManager = null;
78
79         public ControlLoopEventManager getEventManager() {
80                 return eventManager;
81         }
82
83         public void setEventManager(ControlLoopEventManager eventManager) {
84                 this.eventManager = eventManager;
85         }
86
87
88         //
89         // Internal class used for tracking
90         //
91         private class Operation {
92                 public ControlLoopOperation operation = new ControlLoopOperation();
93                 public PolicyResult policyResult = null;
94                 public int attempt = 0;
95                 
96                 @Override
97                 public String toString() {
98                         return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + operation
99                                         + "]";
100                 }
101         }
102         
103         private String guardApprovalStatus = "NONE";//"NONE", "PERMIT", "DENY"
104         private Object operationRequest;
105         
106         public Object getOperationRequest() {
107                 return operationRequest;
108         }
109
110         public String getGuardApprovalStatus() {
111                 return guardApprovalStatus;
112         }
113         public void setGuardApprovalStatus(String guardApprovalStatus) {
114                 this.guardApprovalStatus = guardApprovalStatus;
115         }
116         
117         
118         public ControlLoopOperationManager(/*ATTControlLoopEvent*/ControlLoopEvent onset, Policy policy, ControlLoopEventManager em) throws ControlLoopException {
119                 this.onset = onset;
120                 this.policy = policy;
121                 this.guardApprovalStatus = "NONE";
122                 this.eventManager = em;
123                 
124                 //
125                 // Let's make a sanity check
126                 //
127                 switch (policy.getActor()) {
128                 case "APPC":
129                         break;
130                 case "AOTS":
131                         break;
132                 case "MSO":
133                         break;
134                 case "SDNO":
135                         break;
136                 case "VFC":
137                         break;
138                 default:
139                         throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
140                 }
141         }
142         
143         public Object startOperation(/*VirtualControlLoopEvent*/ControlLoopEvent onset) {
144                 //
145                 // They shouldn't call us if we currently running something
146                 //
147                 if (this.currentOperation != null) {
148                         //
149                         // what do we do if we are already running an operation?
150                         //
151                         return null;
152                 }
153                 //
154                 // Check if we have maxed out on retries
155                 //
156                 if (this.policy.getRetry() == null || this.policy.getRetry() < 1) {
157                         //
158                         // No retries are allowed, so check have we even made
159                         // one attempt to execute the operation?
160                         //
161                         if (this.attempts >= 1) {
162                                 //
163                                 // We have, let's ensure our PolicyResult is set
164                                 //
165                                 if (this.policyResult == null) {
166                                         this.policyResult = PolicyResult.FAILURE_RETRIES;
167                                 }
168                                 //
169                                 //
170                                 //
171                                 return null;
172                         }
173                 } else {
174                         //
175                         // Have we maxed out on retries?
176                         //
177                         if (this.attempts > this.policy.getRetry()) {
178                                 if (this.policyResult == null) {
179                                         this.policyResult = PolicyResult.FAILURE_RETRIES;
180                                 }
181                                 return null;
182                         }
183                 }
184                 //
185                 // Setup
186                 //
187                 this.policyResult = null;
188                 Operation operation = new Operation();
189                 operation.attempt = ++this.attempts;
190                 operation.operation.actor = this.policy.getActor().toString();
191                 operation.operation.operation = this.policy.getRecipe();
192                 operation.operation.target = this.policy.getTarget().toString();
193                 operation.operation.subRequestId = Integer.toString(operation.attempt);
194                 //
195                 // Now determine which actor we need to construct a request for
196                 //
197                 switch (policy.getActor()) {
198                 case "APPC":
199                         //Request request = APPCActorServiceProvider.constructRequest(onset, operation.operation, this.policy);
200                         this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent)onset, operation.operation, this.policy);
201                         //
202                         // Save the operation
203                         //
204                         this.currentOperation = operation;
205                         //System.out.print("*************   BEFORE STORING.....");
206                         //this.storeOperationInDataBase("startOperation");
207                         //System.out.print("*************   AFTER STORING.....");
208                         //
209                         return operationRequest;
210                 case "MSO":
211                         //
212                         // We are not supporting MSO interface at the moment
213                         //
214                         logger.debug("We are not supporting MSO actor in the latest release.");
215                         return null;
216                 case "VFC":
217                         this.operationRequest = VFCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.operation, this.policy);
218                         this.currentOperation = operation;
219                         return operationRequest;
220
221                 }
222                 return null;
223         }
224         
225         public PolicyResult     onResponse(Object response) {
226                 //
227                 // Which response is it?
228                 //
229                 if (response instanceof Response) {
230                         //
231                         // Cast it
232                         //
233                         Response appcResponse = (Response) response;
234                         //
235                         // Determine which subrequestID (ie. attempt)
236                         //
237                         Integer operationAttempt = null;
238                         try {
239                                 operationAttempt = Integer.parseInt(appcResponse.CommonHeader.SubRequestID);
240                         } catch (NumberFormatException e) {
241                                 //
242                                 // We cannot tell what happened if this doesn't exist
243                                 //
244                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
245                                 return PolicyResult.FAILURE_EXCEPTION;
246                         }
247                         //
248                         // Sanity check the response message
249                         //
250                         if (appcResponse.Status == null) {
251                                 //
252                                 // We cannot tell what happened if this doesn't exist
253                                 //
254                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status field (it was null).", PolicyResult.FAILURE_EXCEPTION);
255                                 return PolicyResult.FAILURE_EXCEPTION;
256                         }
257                         //
258                         // Get the Response Code
259                         //
260                         ResponseCode code = ResponseCode.toResponseCode(appcResponse.Status.Code);
261                         if (code == null) {
262                                 //
263                                 // We are unaware of this code
264                                 //
265                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.", PolicyResult.FAILURE_EXCEPTION);
266                                 return PolicyResult.FAILURE_EXCEPTION;
267                         }
268                         //
269                         // Ok, let's figure out what APP-C's response is
270                         //
271                         switch (code) {
272                         case ACCEPT:
273                                 //
274                                 // This is good, they got our original message and
275                                 // acknowledged it.
276                                 //
277                                 // Is there any need to track this?
278                                 //
279                                 return null;
280                         case ERROR:
281                         case REJECT:
282                                 //
283                                 // We'll consider these two codes as exceptions
284                                 //
285                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.FAILURE_EXCEPTION);
286                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
287                                         return null;
288                                 }
289                                 return PolicyResult.FAILURE_EXCEPTION;
290                         case SUCCESS:
291                                 //
292                                 //
293                                 //
294                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.SUCCESS);
295                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
296                                         return null;
297                                 }
298                                 return PolicyResult.SUCCESS;
299                         case FAILURE:
300                                 //
301                                 //
302                                 //
303                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.FAILURE);
304                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
305                                         return null;
306                                 }
307                                 return PolicyResult.FAILURE;
308                         }
309                 } 
310                 return null;
311         }
312         
313         public Integer  getOperationTimeout() {
314                 //
315                 // Sanity check
316                 //
317                 if (this.policy == null) {
318                         logger.debug("getOperationTimeout returning 0");
319                         return 0;
320                 }
321                 logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
322                 return this.policy.getTimeout();
323         }
324         
325         public String   getOperationTimeoutString(int defaultTimeout) {
326                 Integer to = this.getOperationTimeout();
327                 if (to == null || to == 0) {
328                         return Integer.toString(defaultTimeout) + "s";
329                 }
330                 return to.toString() + "s";
331         }
332         
333         public PolicyResult     getOperationResult() {
334                 return this.policyResult;
335         }
336         
337         public String   getOperationMessage() {
338                 if (this.currentOperation != null && this.currentOperation.operation != null) {
339                         return this.currentOperation.operation.toMessage();
340                 }
341                 if (this.operationHistory != null && this.operationHistory.size() > 0) {
342                         return this.operationHistory.getLast().operation.toMessage();
343                 }
344                 return null;
345         }
346         
347         public String   getOperationMessage(String guardResult) {
348                 if (this.currentOperation != null && this.currentOperation.operation != null) {
349                         return this.currentOperation.operation.toMessage()+ ", Guard result: " + guardResult;
350                 }
351                 if (this.operationHistory != null && this.operationHistory.size() > 0) {
352                         return this.operationHistory.getLast().operation.toMessage() + ", Guard result: " + guardResult;
353                 }
354                 return null;
355         }
356         
357         public String   getOperationHistory() {
358                 if (this.currentOperation != null && this.currentOperation.operation != null) {
359                         return this.currentOperation.operation.toHistory();
360                 }
361                 if (this.operationHistory != null && this.operationHistory.size() > 0) {
362                         return this.operationHistory.getLast().operation.toHistory();
363                 }
364                 return null;
365         }
366         
367         public LinkedList<ControlLoopOperation> getHistory() {
368                 LinkedList<ControlLoopOperation> history = new LinkedList<ControlLoopOperation>();
369                 for (Operation op : this.operationHistory) {
370                         history.add(new ControlLoopOperation(op.operation));
371                         
372                 }
373                 return history;
374         }
375         
376         public void             setOperationHasTimedOut() {
377                 //
378                 //
379                 //
380                 this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
381         }
382         
383         public void             setOperationHasGuardDeny() {
384                 //
385                 //
386                 //
387                 this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
388         }
389
390         public boolean  isOperationComplete() {
391                 //
392                 // Is there currently a result?
393                 //
394                 if (this.policyResult == null) {
395                         //
396                         // either we are in process or we
397                         // haven't started
398                         //
399                         return false;
400                 }
401                 //
402                 // We have some result, check if the operation failed
403                 //
404                 if (this.policyResult.equals(PolicyResult.FAILURE)) {
405                         //
406                         // Check if there were no retries specified
407                         //
408                         if (policy.getRetry() == null || policy.getRetry() == 0) {
409                                 //
410                                 // The result is the failure
411                                 //
412                                 return true;
413                         }
414                         //
415                         // Check retries
416                         //
417                         if (this.isRetriesMaxedOut()) {
418                                 //
419                                 // No more attempts allowed, reset
420                                 // that our actual result is failure due to retries
421                                 //
422                                 this.policyResult = PolicyResult.FAILURE_RETRIES;
423                                 return true;
424                         } else {
425                                 //
426                                 // There are more attempts available to try the
427                                 // policy recipe.
428                                 //
429                                 return false;
430                         }
431                 }
432                 //
433                 // Other results mean we are done
434                 //
435                 return true;
436         }
437         
438         public boolean  isOperationRunning() {
439                 return (this.currentOperation != null);
440         }
441         
442         private boolean isRetriesMaxedOut() {
443                 if (policy.getRetry() == null || policy.getRetry() == 0) {
444                         //
445                         // There were NO retries specified, so declare
446                         // this as completed.
447                         //
448                         return (this.attempts > 0);
449                 }
450                 return (this.attempts > policy.getRetry());
451         }
452         
453         private void    storeOperationInDataBase(){
454                 
455                 EntityManager em;
456                 try{
457                         em = Persistence.createEntityManagerFactory("OperationsHistoryPU").createEntityManager();//emf.createEntityManager();           
458                 }catch(Exception e){
459                         logger.error("storeOperationInDataBase threw: ", e);
460                         return; 
461                 }
462                         
463                 OperationsHistoryDbEntry newEntry = new OperationsHistoryDbEntry(); 
464                         
465                 newEntry.closedLoopName = this.onset.closedLoopControlName;
466                 newEntry.requestId = this.onset.requestID.toString();
467                 newEntry.actor = this.currentOperation.operation.actor;
468                 newEntry.operation = this.currentOperation.operation.operation;
469                 newEntry.target = this.eventManager.getTargetInstance(this.policy);
470                 newEntry.starttime = Timestamp.from(this.currentOperation.operation.start);
471                 newEntry.subrequestId = this.currentOperation.operation.subRequestId;
472                 newEntry.endtime = new Timestamp(this.currentOperation.operation.end.toEpochMilli());
473                 newEntry.message = this.currentOperation.operation.message;
474                 newEntry.outcome = this.currentOperation.operation.outcome;
475                         
476                 em.getTransaction().begin();
477                 em.persist(newEntry);
478                 em.getTransaction().commit();
479                         
480                 em.close();
481
482         }
483
484         
485         
486         private void    completeOperation(Integer attempt, String message, PolicyResult result) {
487                 if (attempt == null) {
488                         logger.debug("attempt cannot be null (i.e. subRequestID)");
489                         return;
490                 }
491                 if (this.currentOperation != null) {
492                         if (this.currentOperation.attempt == attempt.intValue()) {
493                                 this.currentOperation.operation.end = Instant.now();
494                                 this.currentOperation.operation.message = message;
495                                 this.currentOperation.operation.outcome = result.toString();
496                                 this.currentOperation.policyResult = result;
497                                 //
498                                 // Save it in history
499                                 //
500                                 this.operationHistory.add(this.currentOperation);
501                                 this.storeOperationInDataBase();
502                                 //
503                                 // Set our last result
504                                 //
505                                 this.policyResult = result;
506                                 //
507                                 // Clear the current operation field
508                                 //
509                                 this.currentOperation = null;
510                                 return;
511                         }
512                         logger.debug("not current");
513                 }
514                 for (Operation op : this.operationHistory) {
515                         if (op.attempt == attempt.intValue()) {
516                                 op.operation.end = Instant.now();
517                                 op.operation.message = message;
518                                 op.operation.outcome = result.toString();
519                                 op.policyResult = result;
520                                 return;
521                         }
522                 }
523                 logger.debug("Could not find associated operation");
524                 
525         }
526         
527 }