Merge "Clearing sonar critical for missing serialization"
[policy/drools-applications.git] / controlloop / common / eventmanager / src / main / java / org / onap / policy / controlloop / eventmanager / ControlLoopOperationManager.java
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.AbstractMap;
27 import java.util.LinkedList;
28
29 import javax.persistence.EntityManager;
30 import javax.persistence.Persistence;
31
32 import org.onap.policy.appc.Response;
33 import org.onap.policy.appc.ResponseCode;
34 import org.onap.policy.appclcm.LCMResponseWrapper;
35 import org.onap.policy.controlloop.ControlLoopEvent;
36 import org.onap.policy.controlloop.ControlLoopException;
37 import org.onap.policy.controlloop.ControlLoopOperation;
38 import org.onap.policy.controlloop.VirtualControlLoopEvent;
39 import org.onap.policy.controlloop.actor.appc.APPCActorServiceProvider;
40 import org.onap.policy.controlloop.actor.vfc.VFCActorServiceProvider;
41 import org.onap.policy.controlloop.policy.Policy;
42 import org.onap.policy.controlloop.policy.PolicyResult;
43 import org.onap.policy.controlloop.actor.mso.MSOActorServiceProvider;
44 import org.onap.policy.mso.SOResponse;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider;
48
49 public class ControlLoopOperationManager implements Serializable {
50
51         /**
52          *
53          */
54         private static final long serialVersionUID = -3773199283624595410L;
55         private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
56
57         @Override
58         public String toString() {
59                 return "ControlLoopOperationManager [onset=" + (onset != null ? onset.requestID : "null") + ", policy="
60                                 + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts
61                                 + ", policyResult=" + policyResult
62                                 + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
63                                 + "]";
64         }
65
66         //
67         // These properties are not changeable, but accessible
68         // for Drools Rule statements.
69         //
70         //public final ATTControlLoopEvent onset;
71         public final ControlLoopEvent onset;
72         public final Policy policy;
73
74         //
75         // Properties used to track the Operation
76         //
77         private int attempts = 0;
78         private Operation currentOperation = null;
79         private LinkedList<Operation> operationHistory = new LinkedList<Operation>();
80         private PolicyResult policyResult = null;
81         private ControlLoopEventManager eventManager = null;
82
83         public ControlLoopEventManager getEventManager() {
84                 return eventManager;
85         }
86
87         public void setEventManager(ControlLoopEventManager eventManager) {
88                 this.eventManager = eventManager;
89         }
90
91
92         //
93         // Internal class used for tracking
94         //
95         private class Operation {
96                 public ControlLoopOperation operation = new ControlLoopOperation();
97                 public PolicyResult policyResult = null;
98                 public int attempt = 0;
99
100                 @Override
101                 public String toString() {
102                         return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + operation
103                                         + "]";
104                 }
105         }
106
107         private String guardApprovalStatus = "NONE";//"NONE", "PERMIT", "DENY"
108         private Object operationRequest;
109
110         public Object getOperationRequest() {
111                 return operationRequest;
112         }
113
114         public String getGuardApprovalStatus() {
115                 return guardApprovalStatus;
116         }
117         public void setGuardApprovalStatus(String guardApprovalStatus) {
118                 this.guardApprovalStatus = guardApprovalStatus;
119         }
120
121
122         public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em) throws ControlLoopException {
123                 this.onset = onset;
124                 this.policy = policy;
125                 this.guardApprovalStatus = "NONE";
126                 this.eventManager = em;
127
128                 //
129                 // Let's make a sanity check
130                 //
131                 switch (policy.getActor()) {
132                 case "APPC":
133                         break;
134                 case "SO":
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                     /*
200                      * If the recipe is ModifyConfig, a legacy APPC
201                      * request is constructed. Otherwise an LCMRequest
202                      * is constructed.
203                      */
204                     if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
205
206                     this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent)onset, operation.operation, this.policy);
207                     }
208                     else {
209                         this.operationRequest = AppcLcmActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.operation, this.policy);
210                     }
211                         //
212                         // Save the operation
213                         //
214                         this.currentOperation = operation;
215                         return operationRequest;
216                 case "SO":
217                         MSOActorServiceProvider SOAsp = new MSOActorServiceProvider();
218                         this.operationRequest = SOAsp.constructRequest((VirtualControlLoopEvent)onset, operation.operation, this.policy);
219                         
220                         // Save the operation
221                         this.currentOperation = operation;
222                         
223                         return operationRequest;
224                 case "VFC":
225                         this.operationRequest = VFCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.operation, this.policy);
226                         this.currentOperation = operation;
227                         return operationRequest;
228
229                 }
230                 return null;
231         }
232
233         public PolicyResult     onResponse(Object response) {
234                 //
235                 // Which response is it?
236                 //
237                 if (response instanceof Response) {
238                         //
239                         // Cast it
240                         //
241                         Response appcResponse = (Response) response;
242                         //
243                         // Determine which subrequestID (ie. attempt)
244                         //
245                         Integer operationAttempt = null;
246                         try {
247                                 operationAttempt = Integer.parseInt(appcResponse.CommonHeader.SubRequestID);
248                         } catch (NumberFormatException e) {
249                                 //
250                                 // We cannot tell what happened if this doesn't exist
251                                 //
252                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
253                                 return PolicyResult.FAILURE_EXCEPTION;
254                         }
255                         //
256                         // Sanity check the response message
257                         //
258                         if (appcResponse.Status == null) {
259                                 //
260                                 // We cannot tell what happened if this doesn't exist
261                                 //
262                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status field (it was null).", PolicyResult.FAILURE_EXCEPTION);
263                                 return PolicyResult.FAILURE_EXCEPTION;
264                         }
265                         //
266                         // Get the Response Code
267                         //
268                         ResponseCode code = ResponseCode.toResponseCode(appcResponse.Status.Code);
269                         if (code == null) {
270                                 //
271                                 // We are unaware of this code
272                                 //
273                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.", PolicyResult.FAILURE_EXCEPTION);
274                                 return PolicyResult.FAILURE_EXCEPTION;
275                         }
276                         //
277                         // Ok, let's figure out what APP-C's response is
278                         //
279                         switch (code) {
280                         case ACCEPT:
281                                 //
282                                 // This is good, they got our original message and
283                                 // acknowledged it.
284                                 //
285                                 // Is there any need to track this?
286                                 //
287                                 return null;
288                         case ERROR:
289                         case REJECT:
290                                 //
291                                 // We'll consider these two codes as exceptions
292                                 //
293                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.FAILURE_EXCEPTION);
294                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
295                                         return null;
296                                 }
297                                 return PolicyResult.FAILURE_EXCEPTION;
298                         case SUCCESS:
299                                 //
300                                 //
301                                 //
302                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.SUCCESS);
303                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
304                                         return null;
305                                 }
306                                 return PolicyResult.SUCCESS;
307                         case FAILURE:
308                                 //
309                                 //
310                                 //
311                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.FAILURE);
312                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
313                                         return null;
314                                 }
315                                 return PolicyResult.FAILURE;
316                         }
317                 }
318                 else if (response instanceof LCMResponseWrapper) {
319
320                     LCMResponseWrapper dmaapResponse = (LCMResponseWrapper) response;
321
322                     /*
323                      * Parse out the operation attempt using the subrequestid
324                      */
325                     Integer operationAttempt = AppcLcmActorServiceProvider.parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
326                     if (operationAttempt == null) {
327                         this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
328                     }
329
330                     /*
331                      * Process the APPCLCM response to see what PolicyResult
332                      * should be returned
333                      */
334                     AbstractMap.SimpleEntry<PolicyResult, String> result = AppcLcmActorServiceProvider.processResponse(dmaapResponse);
335
336                     if (result.getKey() != null) {
337                     this.completeOperation(operationAttempt, result.getValue(), result.getKey());
338                     if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
339                     return null;
340                 }
341                     return result.getKey();
342                     }
343                     return null;
344                 } else if (response instanceof SOResponse) {
345                         SOResponse msoResponse = (SOResponse) response;
346                         switch (msoResponse.httpResponseCode) {
347                         case 200:
348                         case 202:
349                                 //
350                                 // Consider it as success
351                                 //
352                                 this.completeOperation(new Integer(1), msoResponse.httpResponseCode + " Success", PolicyResult.SUCCESS);
353                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
354                                         return null;
355                                 }
356                                 return PolicyResult.SUCCESS;
357                         default:
358                                 //
359                                 // Consider it as failure
360                                 //
361                                 this.completeOperation(new Integer(1), msoResponse.httpResponseCode + " Failed", PolicyResult.FAILURE);
362                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
363                                         return null;
364                                 }
365                                 return PolicyResult.FAILURE;
366                         }
367                         
368                 }
369                 
370                 return null;
371         }
372
373         public Integer  getOperationTimeout() {
374                 //
375                 // Sanity check
376                 //
377                 if (this.policy == null) {
378                         logger.debug("getOperationTimeout returning 0");
379                         return 0;
380                 }
381                 logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
382                 return this.policy.getTimeout();
383         }
384
385         public String   getOperationTimeoutString(int defaultTimeout) {
386                 Integer to = this.getOperationTimeout();
387                 if (to == null || to == 0) {
388                         return Integer.toString(defaultTimeout) + "s";
389                 }
390                 return to.toString() + "s";
391         }
392
393         public PolicyResult     getOperationResult() {
394                 return this.policyResult;
395         }
396
397         public String   getOperationMessage() {
398                 if (this.currentOperation != null && this.currentOperation.operation != null) {
399                         return this.currentOperation.operation.toMessage();
400                 }
401                 if (this.operationHistory != null && this.operationHistory.size() > 0) {
402                         return this.operationHistory.getLast().operation.toMessage();
403                 }
404                 return null;
405         }
406
407         public String   getOperationMessage(String guardResult) {
408                 if (this.currentOperation != null && this.currentOperation.operation != null) {
409                         return this.currentOperation.operation.toMessage()+ ", Guard result: " + guardResult;
410                 }
411                 if (this.operationHistory != null && this.operationHistory.size() > 0) {
412                         return this.operationHistory.getLast().operation.toMessage() + ", Guard result: " + guardResult;
413                 }
414                 return null;
415         }
416
417         public String   getOperationHistory() {
418                 if (this.currentOperation != null && this.currentOperation.operation != null) {
419                         return this.currentOperation.operation.toHistory();
420                 }
421                 if (this.operationHistory != null && this.operationHistory.size() > 0) {
422                         return this.operationHistory.getLast().operation.toHistory();
423                 }
424                 return null;
425         }
426
427         public LinkedList<ControlLoopOperation> getHistory() {
428                 LinkedList<ControlLoopOperation> history = new LinkedList<ControlLoopOperation>();
429                 for (Operation op : this.operationHistory) {
430                         history.add(new ControlLoopOperation(op.operation));
431
432                 }
433                 return history;
434         }
435
436         public void             setOperationHasTimedOut() {
437                 //
438                 //
439                 //
440                 this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
441         }
442
443         public void             setOperationHasGuardDeny() {
444                 //
445                 //
446                 //
447                 this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
448         }
449
450         public boolean  isOperationComplete() {
451                 //
452                 // Is there currently a result?
453                 //
454                 if (this.policyResult == null) {
455                         //
456                         // either we are in process or we
457                         // haven't started
458                         //
459                         return false;
460                 }
461                 //
462                 // We have some result, check if the operation failed
463                 //
464                 if (this.policyResult.equals(PolicyResult.FAILURE)) {
465                         //
466                         // Check if there were no retries specified
467                         //
468                         if (policy.getRetry() == null || policy.getRetry() == 0) {
469                                 //
470                                 // The result is the failure
471                                 //
472                                 return true;
473                         }
474                         //
475                         // Check retries
476                         //
477                         if (this.isRetriesMaxedOut()) {
478                                 //
479                                 // No more attempts allowed, reset
480                                 // that our actual result is failure due to retries
481                                 //
482                                 this.policyResult = PolicyResult.FAILURE_RETRIES;
483                                 return true;
484                         } else {
485                                 //
486                                 // There are more attempts available to try the
487                                 // policy recipe.
488                                 //
489                                 return false;
490                         }
491                 }
492                 //
493                 // Other results mean we are done
494                 //
495                 return true;
496         }
497
498         public boolean  isOperationRunning() {
499                 return (this.currentOperation != null);
500         }
501
502         private boolean isRetriesMaxedOut() {
503                 if (policy.getRetry() == null || policy.getRetry() == 0) {
504                         //
505                         // There were NO retries specified, so declare
506                         // this as completed.
507                         //
508                         return (this.attempts > 0);
509                 }
510                 return (this.attempts > policy.getRetry());
511         }
512
513         private void    storeOperationInDataBase(){
514
515                 String OpsHistPU = System.getProperty("OperationsHistoryPU");
516                 if(OpsHistPU == null || !OpsHistPU.equals("TestOperationsHistoryPU")){
517                         OpsHistPU = "OperationsHistoryPU";
518                 }
519                 EntityManager em;
520                 try{
521                         em = Persistence.createEntityManagerFactory(OpsHistPU).createEntityManager();
522                 }catch(Exception e){
523                         logger.error("storeOperationInDataBase threw: ", e);
524                         return;
525                 }
526
527                 OperationsHistoryDbEntry newEntry = new OperationsHistoryDbEntry();
528
529                 newEntry.closedLoopName = this.onset.closedLoopControlName;
530                 newEntry.requestId = this.onset.requestID.toString();
531                 newEntry.actor = this.currentOperation.operation.actor;
532                 newEntry.operation = this.currentOperation.operation.operation;
533                 newEntry.target = this.eventManager.getTargetInstance(this.policy);
534                 newEntry.starttime = Timestamp.from(this.currentOperation.operation.start);
535                 newEntry.subrequestId = this.currentOperation.operation.subRequestId;
536                 newEntry.endtime = new Timestamp(this.currentOperation.operation.end.toEpochMilli());
537                 newEntry.message = this.currentOperation.operation.message;
538                 newEntry.outcome = this.currentOperation.operation.outcome;
539
540                 em.getTransaction().begin();
541                 em.persist(newEntry);
542                 em.getTransaction().commit();
543
544                 em.close();
545
546         }
547
548
549
550         private void    completeOperation(Integer attempt, String message, PolicyResult result) {
551                 if (attempt == null) {
552                         logger.debug("attempt cannot be null (i.e. subRequestID)");
553                         return;
554                 }
555                 if (this.currentOperation != null) {
556                         if (this.currentOperation.attempt == attempt.intValue()) {
557                                 this.currentOperation.operation.end = Instant.now();
558                                 this.currentOperation.operation.message = message;
559                                 this.currentOperation.operation.outcome = result.toString();
560                                 this.currentOperation.policyResult = result;
561                                 //
562                                 // Save it in history
563                                 //
564                                 this.operationHistory.add(this.currentOperation);
565                                 this.storeOperationInDataBase();
566                                 //
567                                 // Set our last result
568                                 //
569                                 this.policyResult = result;
570                                 //
571                                 // Clear the current operation field
572                                 //
573                                 this.currentOperation = null;
574                                 return;
575                         }
576                         logger.debug("not current");
577                 }
578                 for (Operation op : this.operationHistory) {
579                         if (op.attempt == attempt.intValue()) {
580                                 op.operation.end = Instant.now();
581                                 op.operation.message = message;
582                                 op.operation.outcome = result.toString();
583                                 op.policyResult = result;
584                                 return;
585                         }
586                 }
587                 logger.debug("Could not find associated operation");
588
589         }
590
591 }