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