7c900249c4a98e27dc70b9df95c7c8d85b1efb9d
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * controlloop operation manager
4  * ================================================================================
5  * Copyright (C) 2017-2018 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 import java.util.List;
29 import java.util.Properties;
30
31 import javax.persistence.EntityManager;
32 import javax.persistence.Persistence;
33
34 import org.eclipse.persistence.config.PersistenceUnitProperties;
35 import org.onap.policy.aai.util.AAIException;
36 import org.onap.policy.appc.Response;
37 import org.onap.policy.appc.ResponseCode;
38 import org.onap.policy.appclcm.LCMResponseWrapper;
39 import org.onap.policy.controlloop.ControlLoopEvent;
40 import org.onap.policy.controlloop.ControlLoopException;
41 import org.onap.policy.controlloop.ControlLoopOperation;
42 import org.onap.policy.controlloop.VirtualControlLoopEvent;
43 import org.onap.policy.controlloop.actor.appc.APPCActorServiceProvider;
44 import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider;
45 import org.onap.policy.controlloop.actor.so.SOActorServiceProvider;
46 import org.onap.policy.controlloop.actor.vfc.VFCActorServiceProvider;
47 import org.onap.policy.controlloop.policy.Policy;
48 import org.onap.policy.controlloop.policy.PolicyResult;
49 import org.onap.policy.drools.system.PolicyEngine;
50 import org.onap.policy.guard.Util;
51 import org.onap.policy.so.SOResponseWrapper;
52 import org.onap.policy.vfc.VFCResponse;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 public class ControlLoopOperationManager implements Serializable {
57     private static final long serialVersionUID = -3773199283624595410L;
58     private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
59
60     private static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
61     private static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
62     private static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
63
64     @Override
65     public String toString() {
66         return "ControlLoopOperationManager [onset=" + (onset != null ? onset.getRequestID() : "null") + ", policy="
67                 + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts + ", policyResult="
68                 + policyResult + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
69                 + "]";
70     }
71
72     //
73     // These properties are not changeable, but accessible
74     // for Drools Rule statements.
75     //
76     public final ControlLoopEvent onset;
77     public final transient Policy policy;
78
79     //
80     // Properties used to track the Operation
81     //
82     private int attempts = 0;
83     private transient Operation currentOperation = null;
84     private LinkedList<Operation> operationHistory = new LinkedList<>();
85     private PolicyResult policyResult = null;
86     private ControlLoopEventManager eventManager = null;
87     private String targetEntity;
88
89     public ControlLoopEventManager getEventManager() {
90         return eventManager;
91     }
92
93     public void setEventManager(ControlLoopEventManager eventManager) {
94         this.eventManager = eventManager;
95     }
96
97     public String getTargetEntity() {
98         return this.targetEntity;
99     }
100
101     //
102     // Internal class used for tracking
103     //
104     private class Operation {
105         private ControlLoopOperation clOperation = new ControlLoopOperation();
106         private PolicyResult policyResult = null;
107         private int attempt = 0;
108
109         @Override
110         public String toString() {
111             return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + clOperation
112                     + "]";
113         }
114     }
115
116     private String guardApprovalStatus = "NONE";// "NONE", "PERMIT", "DENY"
117     private transient Object operationRequest;
118
119     public Object getOperationRequest() {
120         return operationRequest;
121     }
122
123     public String getGuardApprovalStatus() {
124         return guardApprovalStatus;
125     }
126
127     public void setGuardApprovalStatus(String guardApprovalStatus) {
128         this.guardApprovalStatus = guardApprovalStatus;
129     }
130
131     /**
132      * Get the target for a policy.
133      * 
134      * @param policy the policy
135      * @return the target
136      * @throws ControlLoopException if an error occurs
137      * @throws AAIException if an error occurs retrieving information from A&AI
138      */
139     public String getTarget(Policy policy) throws ControlLoopException, AAIException {
140         if (policy.getTarget() == null) {
141             throw new ControlLoopException("The target is null");
142         }
143
144         if (policy.getTarget().getType() == null) {
145             throw new ControlLoopException("The target type is null");
146         }
147
148         switch (policy.getTarget().getType()) {
149             case PNF:
150                 throw new ControlLoopException("PNF target is not supported");
151             case VM:
152             case VNF:
153                 VirtualControlLoopEvent virtualOnset = (VirtualControlLoopEvent) this.onset;
154                 if (this.onset.getTarget().equalsIgnoreCase(VSERVER_VSERVER_NAME)) {
155                     return virtualOnset.getAAI().get(VSERVER_VSERVER_NAME);
156                 } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_ID)) {
157                     return virtualOnset.getAAI().get(GENERIC_VNF_VNF_ID);
158                 } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_NAME)) {
159                     /*
160                      * If the onset is enriched with the vnf-id, we don't need an A&AI response
161                      */
162                     if (virtualOnset.getAAI().containsKey(GENERIC_VNF_VNF_ID)) {
163                         return virtualOnset.getAAI().get(GENERIC_VNF_VNF_ID);
164                     }
165
166                     /*
167                      * If the vnf-name was retrieved from the onset then the vnf-id must be obtained
168                      * from the event manager's A&AI GET query
169                      */
170                     String vnfId = this.eventManager.getVnfResponse().getVnfID();
171                     if (vnfId == null) {
172                         throw new AAIException("No vnf-id found");
173                     }
174                     return vnfId;
175                 }
176                 throw new ControlLoopException("Target does not match target type");
177             default:
178                 throw new ControlLoopException("The target type is not supported");
179         }
180     }
181
182     /**
183      * Construct an instance.
184      * 
185      * @param onset the onset event
186      * @param policy the policy
187      * @param em the event manager
188      * @throws ControlLoopException if an error occurs
189      * @throws AAIException if an error occurs retrieving information from A&AI
190      */
191     public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em)
192             throws ControlLoopException, AAIException {
193         this.onset = onset;
194         this.policy = policy;
195         this.guardApprovalStatus = "NONE";
196         this.eventManager = em;
197         this.targetEntity = getTarget(policy);
198
199         //
200         // Let's make a sanity check
201         //
202         switch (policy.getActor()) {
203             case "APPC":
204                 if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
205                     /*
206                      * The target vnf-id may not be the same as the source vnf-id specified in the
207                      * yaml, the target vnf-id is retrieved by a named query to A&AI.
208                      */
209                     String targetVnf = AppcLcmActorServiceProvider.vnfNamedQuery(policy.getTarget().getResourceID(),
210                             this.targetEntity);
211                     this.targetEntity = targetVnf;
212                 }
213                 break;
214             case "SO":
215                 break;
216             case "VFC":
217                 break;
218             default:
219                 throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
220         }
221     }
222
223     /**
224      * Start an operation.
225      * 
226      * @param onset the onset event
227      * @return the operation request
228      * @throws ControlLoopException if an error occurs
229      */
230     public Object startOperation(/* VirtualControlLoopEvent */ControlLoopEvent onset) throws ControlLoopException {
231         verifyOperatonCanRun();
232
233         //
234         // Setup
235         //
236         this.policyResult = null;
237         Operation operation = new Operation();
238         operation.attempt = ++this.attempts;
239         operation.clOperation.setActor(this.policy.getActor());
240         operation.clOperation.setOperation(this.policy.getRecipe());
241         operation.clOperation.setTarget(this.policy.getTarget().toString());
242         operation.clOperation.setSubRequestId(Integer.toString(operation.attempt));
243         //
244         // Now determine which actor we need to construct a request for
245         //
246         switch (policy.getActor()) {
247             case "APPC":
248                 /*
249                  * If the recipe is ModifyConfig, a legacy APPC request is constructed. Otherwise an
250                  * LCMRequest is constructed.
251                  */
252                 this.currentOperation = operation;
253                 if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
254                     this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
255                             operation.clOperation, this.policy, this.targetEntity);
256                 } else {
257                     this.operationRequest = AppcLcmActorServiceProvider.constructRequest(
258                             (VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.targetEntity);
259                 }
260                 //
261                 // Save the operation
262                 //
263
264                 return operationRequest;
265             case "SO":
266                 SOActorServiceProvider soActorSp = new SOActorServiceProvider();
267                 this.operationRequest =
268                         soActorSp.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy);
269
270                 // Save the operation
271                 this.currentOperation = operation;
272
273                 if (this.operationRequest == null) {
274                     this.policyResult = PolicyResult.FAILURE;
275                 }
276
277                 return operationRequest;
278             case "VFC":
279                 this.operationRequest = VFCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
280                         operation.clOperation, this.policy, this.eventManager.getVnfResponse());
281                 this.currentOperation = operation;
282                 if (this.operationRequest == null) {
283                     this.policyResult = PolicyResult.FAILURE;
284                 }
285                 return operationRequest;
286             default:
287                 throw new ControlLoopException("invalid actor " + policy.getActor() + " on policy");
288         }
289     }
290
291     /**
292      * Handle a response.
293      * 
294      * @param response the response
295      * @return a PolicyResult
296      */
297     public PolicyResult onResponse(Object response) {
298         //
299         // Which response is it?
300         //
301         if (response instanceof Response) {
302             //
303             // Cast APPC response and handle it
304             //
305             return onResponse((Response) response);
306         } else if (response instanceof LCMResponseWrapper) {
307             //
308             // Cast LCM response and handle it
309             //
310             return onResponse((LCMResponseWrapper) response);
311         } else if (response instanceof SOResponseWrapper) {
312             //
313             // Cast SO response and handle it
314             //
315             return onResponse((SOResponseWrapper) response);
316         } else if (response instanceof VFCResponse) {
317             //
318             // Cast VFC response and handle it
319             //
320             return onResponse((VFCResponse) response);
321         } else {
322             return null;
323         }
324     }
325
326     /**
327      * This method handles operation responses from APPC.
328      * 
329      * @param appcResponse the APPC response
330      * @return The result of the response handling
331      */
332     private PolicyResult onResponse(Response appcResponse) {
333         //
334         // Determine which subrequestID (ie. attempt)
335         //
336         Integer operationAttempt = null;
337         try {
338             operationAttempt = Integer.parseInt(appcResponse.getCommonHeader().getSubRequestID());
339         } catch (NumberFormatException e) {
340             //
341             // We cannot tell what happened if this doesn't exist
342             //
343             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
344                     PolicyResult.FAILURE_EXCEPTION);
345             return PolicyResult.FAILURE_EXCEPTION;
346         }
347         //
348         // Sanity check the response message
349         //
350         if (appcResponse.getStatus() == null) {
351             //
352             // We cannot tell what happened if this doesn't exist
353             //
354             this.completeOperation(operationAttempt,
355                     "Policy was unable to parse APP-C response status field (it was null).",
356                     PolicyResult.FAILURE_EXCEPTION);
357             return PolicyResult.FAILURE_EXCEPTION;
358         }
359         //
360         // Get the Response Code
361         //
362         ResponseCode code = ResponseCode.toResponseCode(appcResponse.getStatus().getCode());
363         if (code == null) {
364             //
365             // We are unaware of this code
366             //
367             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.",
368                     PolicyResult.FAILURE_EXCEPTION);
369             return PolicyResult.FAILURE_EXCEPTION;
370         }
371         //
372         // Ok, let's figure out what APP-C's response is
373         //
374         switch (code) {
375             case ACCEPT:
376                 //
377                 // This is good, they got our original message and
378                 // acknowledged it.
379                 //
380                 // Is there any need to track this?
381                 //
382                 return null;
383             case ERROR:
384             case REJECT:
385                 //
386                 // We'll consider these two codes as exceptions
387                 //
388                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
389                         PolicyResult.FAILURE_EXCEPTION);
390                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
391                     return null;
392                 }
393                 return PolicyResult.FAILURE_EXCEPTION;
394             case SUCCESS:
395                 //
396                 //
397                 //
398                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
399                         PolicyResult.SUCCESS);
400                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
401                     return null;
402                 }
403                 return PolicyResult.SUCCESS;
404             case FAILURE:
405                 //
406                 //
407                 //
408                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
409                         PolicyResult.FAILURE);
410                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
411                     return null;
412                 }
413                 return PolicyResult.FAILURE;
414             default:
415                 return null;
416         }
417     }
418
419     /**
420      * This method handles operation responses from LCM.
421      * 
422      * @param dmaapResponse the LCM response
423      * @return The result of the response handling
424      */
425     private PolicyResult onResponse(LCMResponseWrapper dmaapResponse) {
426         /*
427          * Parse out the operation attempt using the subrequestid
428          */
429         Integer operationAttempt = AppcLcmActorServiceProvider
430                 .parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
431         if (operationAttempt == null) {
432             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
433                     PolicyResult.FAILURE_EXCEPTION);
434         }
435
436         /*
437          * Process the APPCLCM response to see what PolicyResult should be returned
438          */
439         AbstractMap.SimpleEntry<PolicyResult, String> result =
440                 AppcLcmActorServiceProvider.processResponse(dmaapResponse);
441
442         if (result.getKey() != null) {
443             this.completeOperation(operationAttempt, result.getValue(), result.getKey());
444             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
445                 return null;
446             }
447             return result.getKey();
448         }
449         return null;
450     }
451
452     /**
453      * This method handles operation responses from SO.
454      * 
455      * @param msoResponse the SO response
456      * @return The result of the response handling
457      */
458     private PolicyResult onResponse(SOResponseWrapper msoResponse) {
459         switch (msoResponse.getSoResponse().getHttpResponseCode()) {
460             case 200:
461             case 202:
462                 //
463                 // Consider it as success
464                 //
465                 this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + " Success",
466                         PolicyResult.SUCCESS);
467                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
468                     return null;
469                 }
470                 return PolicyResult.SUCCESS;
471             default:
472                 //
473                 // Consider it as failure
474                 //
475                 this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + " Failed",
476                         PolicyResult.FAILURE);
477                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
478                     return null;
479                 }
480                 return PolicyResult.FAILURE;
481         }
482     }
483
484     /**
485      * This method handles operation responses from VFC.
486      * 
487      * @param vfcResponse the VFC response
488      * @return The result of the response handling
489      */
490     private PolicyResult onResponse(VFCResponse vfcResponse) {
491         if (vfcResponse.getResponseDescriptor().getStatus().equalsIgnoreCase("finished")) {
492             //
493             // Consider it as success
494             //
495             this.completeOperation(this.attempts, " Success", PolicyResult.SUCCESS);
496             if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
497                 return null;
498             }
499             return PolicyResult.SUCCESS;
500         } else {
501             //
502             // Consider it as failure
503             //
504             this.completeOperation(this.attempts, " Failed", PolicyResult.FAILURE);
505             if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
506                 return null;
507             }
508             // increment operation attempts for retries
509             this.attempts += 1;
510             return PolicyResult.FAILURE;
511         }
512     }
513
514     /**
515      * Get the operation timeout.
516      * 
517      * @return the timeout
518      */
519     public Integer getOperationTimeout() {
520         //
521         // Sanity check
522         //
523         if (this.policy == null) {
524             logger.debug("getOperationTimeout returning 0");
525             return 0;
526         }
527         logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
528         return this.policy.getTimeout();
529     }
530
531     /**
532      * Get the operation timeout as a String.
533      * 
534      * @param defaultTimeout the default timeout
535      * @return the timeout as a String
536      */
537     public String getOperationTimeoutString(int defaultTimeout) {
538         Integer to = this.getOperationTimeout();
539         if (to == null || to == 0) {
540             return Integer.toString(defaultTimeout) + "s";
541         }
542         return to.toString() + "s";
543     }
544
545     public PolicyResult getOperationResult() {
546         return this.policyResult;
547     }
548
549     /**
550      * Get the operation as a message.
551      * 
552      * @return the operation as a message
553      */
554     public String getOperationMessage() {
555         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
556             return this.currentOperation.clOperation.toMessage();
557         }
558
559         if (!this.operationHistory.isEmpty()) {
560             return this.operationHistory.getLast().clOperation.toMessage();
561         }
562         return null;
563     }
564
565     /**
566      * Get the operation as a message including the guard result.
567      * 
568      * @param guardResult the guard result
569      * @return the operation as a message including the guard result
570      */
571     public String getOperationMessage(String guardResult) {
572         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
573             return this.currentOperation.clOperation.toMessage() + ", Guard result: " + guardResult;
574         }
575
576         if (!this.operationHistory.isEmpty()) {
577             return this.operationHistory.getLast().clOperation.toMessage() + ", Guard result: " + guardResult;
578         }
579         return null;
580     }
581
582     /**
583      * Get the operation history.
584      * 
585      * @return the operation history
586      */
587     public String getOperationHistory() {
588         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
589             return this.currentOperation.clOperation.toHistory();
590         }
591
592         if (!this.operationHistory.isEmpty()) {
593             return this.operationHistory.getLast().clOperation.toHistory();
594         }
595         return null;
596     }
597
598     /**
599      * Get the history.
600      * 
601      * @return the list of control loop operations
602      */
603     public List<ControlLoopOperation> getHistory() {
604         LinkedList<ControlLoopOperation> history = new LinkedList<>();
605         for (Operation op : this.operationHistory) {
606             history.add(new ControlLoopOperation(op.clOperation));
607
608         }
609         return history;
610     }
611
612     /**
613      * Set the operation has timed out.
614      */
615     public void setOperationHasTimedOut() {
616         //
617         //
618         //
619         this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
620     }
621
622     /**
623      * Set the operation has been denied by guard.
624      */
625     public void setOperationHasGuardDeny() {
626         //
627         //
628         //
629         this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
630     }
631
632     public void setOperationHasException(String message) {
633         this.completeOperation(this.attempts, message, PolicyResult.FAILURE_EXCEPTION);
634     }
635
636     /**
637      * Is the operation complete.
638      * 
639      * @return <code>true</code> if the operation is complete, <code>false</code> otherwise
640      */
641     public boolean isOperationComplete() {
642         //
643         // Is there currently a result?
644         //
645         if (this.policyResult == null) {
646             //
647             // either we are in process or we
648             // haven't started
649             //
650             return false;
651         }
652         //
653         // We have some result, check if the operation failed
654         //
655         if (this.policyResult.equals(PolicyResult.FAILURE)) {
656             //
657             // Check if there were no retries specified
658             //
659             if (policy.getRetry() == null || policy.getRetry() == 0) {
660                 //
661                 // The result is the failure
662                 //
663                 return true;
664             }
665             //
666             // Check retries
667             //
668             if (this.isRetriesMaxedOut()) {
669                 //
670                 // No more attempts allowed, reset
671                 // that our actual result is failure due to retries
672                 //
673                 this.policyResult = PolicyResult.FAILURE_RETRIES;
674                 return true;
675             } else {
676                 //
677                 // There are more attempts available to try the
678                 // policy recipe.
679                 //
680                 return false;
681             }
682         }
683         //
684         // Other results mean we are done
685         //
686         return true;
687     }
688
689     public boolean isOperationRunning() {
690         return (this.currentOperation != null);
691     }
692
693     /**
694      * This method verifies that the operation manager may run an operation.
695      * 
696      * @return True if the operation can run, false otherwise
697      * @throws ControlLoopException if the operation cannot run
698      */
699     private void verifyOperatonCanRun() throws ControlLoopException {
700         //
701         // They shouldn't call us if we currently running something
702         //
703         if (this.currentOperation != null) {
704             //
705             // what do we do if we are already running an operation?
706             //
707             throw new ControlLoopException("current operation is not null (an operation is already running)");
708         }
709         //
710         // Check if we have maxed out on retries
711         //
712         if (this.policy.getRetry() == null || this.policy.getRetry() < 1) {
713             //
714             // No retries are allowed, so check have we even made
715             // one attempt to execute the operation?
716             //
717             if (this.attempts >= 1) {
718                 //
719                 // We have, let's ensure our PolicyResult is set
720                 //
721                 if (this.policyResult == null) {
722                     this.policyResult = PolicyResult.FAILURE_RETRIES;
723                 }
724                 //
725                 //
726                 //
727                 throw new ControlLoopException("current operation failed and retries are not allowed");
728             }
729         } else {
730             //
731             // Have we maxed out on retries?
732             //
733             if (this.attempts > this.policy.getRetry()) {
734                 if (this.policyResult == null) {
735                     this.policyResult = PolicyResult.FAILURE_RETRIES;
736                 }
737                 throw new ControlLoopException("current oepration has failed after " + this.attempts + " retries");
738             }
739         }
740
741         return;
742     }
743
744     private boolean isRetriesMaxedOut() {
745         if (policy.getRetry() == null || policy.getRetry() == 0) {
746             //
747             // There were NO retries specified, so declare
748             // this as completed.
749             //
750             return (this.attempts > 0);
751         }
752         return (this.attempts > policy.getRetry());
753     }
754
755     private void storeOperationInDataBase() {
756         // Only store in DB if enabled
757         boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
758         if (!guardEnabled) {
759             return;
760         }
761
762
763         // DB Properties
764         Properties props = new Properties();
765         if (PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL) != null
766                 && PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER) != null
767                 && PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS) != null) {
768             props.put(Util.ECLIPSE_LINK_KEY_URL, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL));
769             props.put(Util.ECLIPSE_LINK_KEY_USER, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER));
770             props.put(Util.ECLIPSE_LINK_KEY_PASS, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS));
771             props.put(PersistenceUnitProperties.CLASSLOADER, ControlLoopOperationManager.class.getClassLoader());
772         }
773
774
775         String opsHistPu = System.getProperty("OperationsHistoryPU");
776         if (opsHistPu == null || !opsHistPu.equals("TestOperationsHistoryPU")) {
777             opsHistPu = "OperationsHistoryPU";
778         } else {
779             props.clear();
780         }
781         EntityManager em;
782         try {
783             em = Persistence.createEntityManagerFactory(opsHistPu, props).createEntityManager();
784         } catch (Exception e) {
785             logger.error("storeOperationInDataBase threw: ", e);
786             return;
787         }
788
789         OperationsHistoryDbEntry newEntry = new OperationsHistoryDbEntry();
790
791         newEntry.setClosedLoopName(this.onset.getClosedLoopControlName());
792         newEntry.setRequestId(this.onset.getRequestID().toString());
793         newEntry.setActor(this.currentOperation.clOperation.getActor());
794         newEntry.setOperation(this.currentOperation.clOperation.getOperation());
795         newEntry.setTarget(this.targetEntity);
796         newEntry.setStarttime(Timestamp.from(this.currentOperation.clOperation.getStart()));
797         newEntry.setSubrequestId(this.currentOperation.clOperation.getSubRequestId());
798         newEntry.setEndtime(new Timestamp(this.currentOperation.clOperation.getEnd().toEpochMilli()));
799         newEntry.setMessage(this.currentOperation.clOperation.getMessage());
800         newEntry.setOutcome(this.currentOperation.clOperation.getOutcome());
801
802         em.getTransaction().begin();
803         em.persist(newEntry);
804         em.getTransaction().commit();
805
806         em.close();
807     }
808
809     private void completeOperation(Integer attempt, String message, PolicyResult result) {
810         if (attempt == null) {
811             logger.debug("attempt cannot be null (i.e. subRequestID)");
812             return;
813         }
814         if (this.currentOperation != null) {
815             if (this.currentOperation.attempt == attempt.intValue()) {
816                 this.currentOperation.clOperation.setEnd(Instant.now());
817                 this.currentOperation.clOperation.setMessage(message);
818                 this.currentOperation.clOperation.setOutcome(result.toString());
819                 this.currentOperation.policyResult = result;
820                 //
821                 // Save it in history
822                 //
823                 this.operationHistory.add(this.currentOperation);
824                 this.storeOperationInDataBase();
825                 //
826                 // Set our last result
827                 //
828                 this.policyResult = result;
829                 //
830                 // Clear the current operation field
831                 //
832                 this.currentOperation = null;
833                 return;
834             }
835             logger.debug("not current");
836         }
837         for (Operation op : this.operationHistory) {
838             if (op.attempt == attempt.intValue()) {
839                 op.clOperation.setEnd(Instant.now());
840                 op.clOperation.setMessage(message);
841                 op.clOperation.setOutcome(result.toString());
842                 op.policyResult = result;
843                 return;
844             }
845         }
846         logger.debug("Could not find associated operation");
847
848     }
849
850 }