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