62bd0c1e9bd9ce0294331b3aa989743f36ba5222
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * controlloop operation manager
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved.
7  * Modifications Copyright (C) 2019 Tech Mahindra
8  * Modifications Copyright (C) 2019 Bell Canada.
9  * ================================================================================
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.policy.controlloop.eventmanager;
25
26 import java.io.Serializable;
27 import java.sql.Timestamp;
28 import java.time.Instant;
29 import java.util.AbstractMap;
30 import java.util.HashMap;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.NoSuchElementException;
35 import java.util.Optional;
36 import java.util.Properties;
37 import javax.persistence.EntityManager;
38 import javax.persistence.Persistence;
39
40 import org.eclipse.persistence.config.PersistenceUnitProperties;
41 import org.onap.aai.domain.yang.GenericVnf;
42 import org.onap.aai.domain.yang.ServiceInstance;
43 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
44 import org.onap.policy.aai.AaiCqResponse;
45 import org.onap.policy.aai.util.AaiException;
46 import org.onap.policy.appc.Response;
47 import org.onap.policy.appc.ResponseCode;
48 import org.onap.policy.appclcm.LcmResponseWrapper;
49 import org.onap.policy.cds.CdsResponse;
50 import org.onap.policy.controlloop.ControlLoopEvent;
51 import org.onap.policy.controlloop.ControlLoopException;
52 import org.onap.policy.controlloop.ControlLoopOperation;
53 import org.onap.policy.controlloop.ControlLoopResponse;
54 import org.onap.policy.controlloop.VirtualControlLoopEvent;
55 import org.onap.policy.controlloop.actor.appc.AppcActorServiceProvider;
56 import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider;
57 import org.onap.policy.controlloop.actor.cds.CdsActorServiceProvider;
58 import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants;
59 import org.onap.policy.controlloop.actor.sdnc.SdncActorServiceProvider;
60 import org.onap.policy.controlloop.actor.sdnr.SdnrActorServiceProvider;
61 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
62 import org.onap.policy.controlloop.actor.vfc.VfcActorServiceProvider;
63 import org.onap.policy.controlloop.policy.Policy;
64 import org.onap.policy.controlloop.policy.PolicyResult;
65 import org.onap.policy.controlloop.policy.TargetType;
66 import org.onap.policy.database.operationshistory.Dbao;
67 import org.onap.policy.drools.system.PolicyEngineConstants;
68 import org.onap.policy.guard.Util;
69 import org.onap.policy.sdnc.SdncResponse;
70 import org.onap.policy.sdnr.PciResponseWrapper;
71 import org.onap.policy.so.SoResponseWrapper;
72 import org.onap.policy.vfc.VfcResponse;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76 public class ControlLoopOperationManager implements Serializable {
77     private static final String SUCCESS_MSG = " Success";
78     private static final String FAILED_MSG = " Failed";
79     private static final String AAI_CUSTOM_QUERY = "aai.customQuery";
80     private static final long serialVersionUID = -3773199283624595410L;
81     private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
82
83     private static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
84     private static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
85     private static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
86
87     private static final String AAI_SERVICE_INSTANCE_ID_KEY = "service-instance.service-instance-id";
88
89     //
90     // These properties are not changeable, but accessible
91     // for Drools Rule statements.
92     //
93     public final ControlLoopEvent onset;
94     public final Policy policy;
95
96     //
97     // Properties used to track the Operation
98     //
99     private int attempts = 0;
100     private Operation currentOperation = null;
101     private LinkedList<Operation> operationHistory = new LinkedList<>();
102     private PolicyResult policyResult = null;
103     private ControlLoopEventManager eventManager = null;
104     private String targetEntity;
105     private String guardApprovalStatus = "NONE";// "NONE", "PERMIT", "DENY"
106     private AaiCqResponse aaiCqResponse;
107     private transient Object operationRequest;
108
109     /**
110      * Construct an instance.
111      *
112      * @param onset the onset event
113      * @param policy the policy
114      * @param em the event manager
115      * @throws ControlLoopException if an error occurs
116      */
117     public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em)
118             throws ControlLoopException {
119
120         this.onset = onset;
121         this.policy = policy;
122         this.guardApprovalStatus = "NONE";
123         this.eventManager = em;
124
125         try {
126
127             if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
128                 this.aaiCqResponse = this.eventManager.getCqResponse((VirtualControlLoopEvent) onset);
129             }
130
131             this.targetEntity = getTarget(policy);
132
133             //
134             // Let's make a sanity check
135             //
136             switch (policy.getActor()) {
137                 case "APPC":
138                     initAppc(onset, policy);
139                     break;
140                 case "SO":
141                     break;
142                 case "SDNR":
143                     break;
144                 case "VFC":
145                     break;
146                 case "SDNC":
147                     break;
148                 case "CDS":
149                     break;
150                 default:
151                     throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
152             }
153
154         } catch (AaiException e) {
155             throw new ControlLoopException(e.getMessage(), e);
156         }
157     }
158
159
160     private void initAppc(ControlLoopEvent onset, Policy policy) throws AaiException {
161         if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
162             /*
163              * The target vnf-id may not be the same as the source vnf-id specified in the yaml, the target
164              * vnf-id is retrieved by a named query to A&AI.
165              */
166             if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
167                 GenericVnf genvnf =
168                         this.aaiCqResponse.getGenericVnfByModelInvariantId(policy.getTarget().getResourceID());
169                 if (genvnf == null) {
170                     logger.info("Target entity could not be found");
171                     throw new AaiException("Target vnf-id could not be found");
172                 }
173                 this.targetEntity = genvnf.getVnfId();
174
175             } else {
176                 this.targetEntity =
177                         AppcLcmActorServiceProvider.vnfNamedQuery(policy.getTarget().getResourceID(),
178                                 this.targetEntity, PolicyEngineConstants.getManager().getEnvironmentProperty("aai.url"),
179                                 PolicyEngineConstants.getManager().getEnvironmentProperty("aai.username"),
180                                 PolicyEngineConstants.getManager().getEnvironmentProperty("aai.password"));
181             }
182         }
183     }
184
185
186     public ControlLoopEventManager getEventManager() {
187         return eventManager;
188     }
189
190     public void setEventManager(ControlLoopEventManager eventManager) {
191         this.eventManager = eventManager;
192     }
193
194     public String getTargetEntity() {
195         return this.targetEntity;
196     }
197
198     @Override
199     public String toString() {
200         return "ControlLoopOperationManager [onset=" + (onset != null ? onset.getRequestId() : "null") + ", policy="
201                 + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts + ", policyResult="
202                 + policyResult + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
203                 + "]";
204     }
205
206     //
207     // Internal class used for tracking
208     //
209     private class Operation implements Serializable {
210         private static final long serialVersionUID = 1L;
211
212         private ControlLoopOperation clOperation = new ControlLoopOperation();
213         private PolicyResult policyResult = null;
214         private int attempt = 0;
215
216         @Override
217         public String toString() {
218             return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + clOperation
219                     + "]";
220         }
221     }
222
223     public Object getOperationRequest() {
224         return operationRequest;
225     }
226
227     public String getGuardApprovalStatus() {
228         return guardApprovalStatus;
229     }
230
231     public void setGuardApprovalStatus(String guardApprovalStatus) {
232         this.guardApprovalStatus = guardApprovalStatus;
233     }
234
235     /**
236      * Get the target for a policy.
237      *
238      * @param policy the policy
239      * @return the target
240      * @throws ControlLoopException if an error occurs
241      */
242     public String getTarget(Policy policy) throws ControlLoopException {
243         if (policy.getTarget() == null) {
244             throw new ControlLoopException("The target is null");
245         }
246
247         if (policy.getTarget().getType() == null) {
248             throw new ControlLoopException("The target type is null");
249         }
250
251         switch (policy.getTarget().getType()) {
252             case PNF:
253                 throw new ControlLoopException("PNF target is not supported");
254             case VM:
255             case VNF:
256                 return getVfModuleTarget();
257             case VFMODULE:
258                 return getVfModuleTarget();
259             default:
260                 throw new ControlLoopException("The target type is not supported");
261         }
262     }
263
264
265     private String getVfModuleTarget() throws ControlLoopException {
266         VirtualControlLoopEvent virtualOnsetEvent = (VirtualControlLoopEvent) this.onset;
267         if (this.onset.getTarget().equalsIgnoreCase(VSERVER_VSERVER_NAME)) {
268             return virtualOnsetEvent.getAai().get(VSERVER_VSERVER_NAME);
269         } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_ID)) {
270             return virtualOnsetEvent.getAai().get(GENERIC_VNF_VNF_ID);
271         } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_NAME)) {
272             /*
273              * If the onset is enriched with the vnf-id, we don't need an A&AI response
274              */
275             if (virtualOnsetEvent.getAai().containsKey(GENERIC_VNF_VNF_ID)) {
276                 return virtualOnsetEvent.getAai().get(GENERIC_VNF_VNF_ID);
277             }
278
279             /*
280              * If the vnf-name was retrieved from the onset then the vnf-id must be obtained from the event
281              * manager's A&AI GET query
282              */
283             try {
284                 String vnfId;
285                 if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
286                     vnfId = this.aaiCqResponse.getDefaultGenericVnf().getVnfId();
287                 } else {
288                     vnfId = this.eventManager.getVnfResponse().getVnfId();
289                 }
290                 if (vnfId == null) {
291                     throw new AaiException("No vnf-id found");
292                 }
293                 return vnfId;
294
295             } catch (AaiException e) {
296                 throw new ControlLoopException(e.getMessage(), e);
297             }
298         }
299         throw new ControlLoopException("Target does not match target type");
300     }
301
302     /**
303      * Start an operation.
304      *
305      * @param onset the onset event
306      * @return the operation request
307      * @throws ControlLoopException if an error occurs
308      */
309     public Object startOperation(/* VirtualControlLoopEvent */ControlLoopEvent onset)
310             throws ControlLoopException {
311         verifyOperatonCanRun();
312
313         //
314         // Setup
315         //
316         this.policyResult = null;
317         Operation operation = new Operation();
318         operation.attempt = ++this.attempts;
319         operation.clOperation.setActor(this.policy.getActor());
320         operation.clOperation.setOperation(this.policy.getRecipe());
321         operation.clOperation.setTarget(this.policy.getTarget().toString());
322         operation.clOperation.setSubRequestId(Integer.toString(operation.attempt));
323         //
324         // Now determine which actor we need to construct a request for
325         //
326         try {
327             switch (policy.getActor()) {
328                 case "APPC":
329                     return startAppcOperation(onset, operation);
330                 case "SO":
331                     return startSoOperation(onset, operation);
332                 case "VFC":
333                     return startVfcOperation(onset, operation);
334                 case "SDNR":
335                     return startSdnrOperation(onset, operation);
336                 case "SDNC":
337                     return startSdncOperation(onset, operation);
338                 case "CDS":
339                     return startCdsOperation(onset, operation);
340                 default:
341                     throw new ControlLoopException("invalid actor " + policy.getActor() + " on policy");
342             }
343
344         } catch (AaiException e) {
345             throw new ControlLoopException(e.getMessage(), e);
346         }
347     }
348
349
350     private Object startAppcOperation(ControlLoopEvent onset, Operation operation) {
351         /*
352          * If the recipe is ModifyConfig, a legacy APPC request is constructed. Otherwise an LCMRequest is
353          * constructed.
354          */
355         this.currentOperation = operation;
356         if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
357             this.operationRequest = AppcActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
358                     operation.clOperation, this.policy, this.targetEntity);
359         } else {
360             this.operationRequest = AppcLcmActorServiceProvider.constructRequest(
361                     (VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.targetEntity);
362         }
363         //
364         // Save the operation
365         //
366
367         return operationRequest;
368     }
369
370
371     private Object startSoOperation(ControlLoopEvent onset, Operation operation) throws AaiException {
372         SoActorServiceProvider soActorSp = new SoActorServiceProvider();
373         if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
374             this.operationRequest =
375                     soActorSp.constructRequestCq((VirtualControlLoopEvent) onset, operation.clOperation,
376                             this.policy, this.aaiCqResponse);
377         } else {
378             this.operationRequest = soActorSp.constructRequest((VirtualControlLoopEvent) onset,
379                     operation.clOperation, this.policy, eventManager.getNqVserverFromAai());
380         }
381
382         // Save the operation
383         this.currentOperation = operation;
384
385         if (this.operationRequest == null) {
386             this.policyResult = PolicyResult.FAILURE;
387         }
388
389         return operationRequest;
390     }
391
392
393     private Object startVfcOperation(ControlLoopEvent onset, Operation operation) throws AaiException {
394         if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
395             this.operationRequest = VfcActorServiceProvider.constructRequestCq((VirtualControlLoopEvent) onset,
396                     operation.clOperation, this.policy, this.aaiCqResponse);
397         } else {
398             this.operationRequest = VfcActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
399                     operation.clOperation, this.policy, this.eventManager.getVnfResponse(),
400                     PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.url"),
401                     PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.username"),
402                     PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.password"));
403         }
404         this.currentOperation = operation;
405         if (this.operationRequest == null) {
406             this.policyResult = PolicyResult.FAILURE;
407         }
408         return operationRequest;
409     }
410
411
412     private Object startSdnrOperation(ControlLoopEvent onset, Operation operation) {
413         /*
414          * If the recipe is ModifyConfig or ModifyConfigANR, a SDNR request is constructed.
415          */
416         this.currentOperation = operation;
417         this.operationRequest = SdnrActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
418                 operation.clOperation, this.policy);
419         //
420         // Save the operation
421         //
422         if (this.operationRequest == null) {
423             this.policyResult = PolicyResult.FAILURE;
424         }
425
426         return operationRequest;
427     }
428
429
430     private Object startSdncOperation(ControlLoopEvent onset, Operation operation) {
431         SdncActorServiceProvider provider = new SdncActorServiceProvider();
432         this.operationRequest =
433                 provider.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy);
434         this.currentOperation = operation;
435         if (this.operationRequest == null) {
436             this.policyResult = PolicyResult.FAILURE;
437         }
438         return operationRequest;
439     }
440
441     private Object startCdsOperation(ControlLoopEvent onset, Operation operation) throws AaiException {
442
443         CdsActorServiceProvider provider = new CdsActorServiceProvider();
444         Optional<ExecutionServiceInput> optionalRequest = provider.constructRequest(
445                 (VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.buildAaiParams());
446
447         this.currentOperation = operation;
448         if (optionalRequest.isPresent()) {
449             this.operationRequest = optionalRequest.get();
450         } else {
451             this.operationRequest = null;
452             this.policyResult = PolicyResult.FAILURE;
453         }
454
455         return this.operationRequest;
456     }
457
458     /**
459      * Build AAI parameters for CDS operation.
460      * @return a map containing vnf id key and value for the vnf to apply the action to.
461      * @throws AaiException if the vnf can not be found.
462      */
463     private Map<String, String> buildAaiParams() throws AaiException {
464
465         Map<String, String> result = new HashMap<>();
466
467         if (TargetType.VNF.equals(policy.getTarget().getType())
468                     || TargetType.VFMODULE.equals(policy.getTarget().getType())) {
469
470             if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
471
472                 ServiceInstance serviceInstance = this.aaiCqResponse.getServiceInstance();
473                 if (serviceInstance == null) {
474                     logger.info("Target entity service instance could not be found");
475                     throw new AaiException("Target service instance could not be found");
476                 }
477
478                 GenericVnf genericVnf =
479                         this.aaiCqResponse.getGenericVnfByModelInvariantId(policy.getTarget().getResourceID());
480                 if (genericVnf == null) {
481                     logger.info("Target entity generic vnf could not be found");
482                     throw new AaiException("Target generic vnf could not be found");
483                 }
484
485                 result.put(AAI_SERVICE_INSTANCE_ID_KEY, serviceInstance.getServiceInstanceId());
486                 result.put(GENERIC_VNF_VNF_ID, genericVnf.getVnfId());
487             }
488
489         }
490
491         return result;
492
493     }
494
495     /**
496      * Handle a response.
497      *
498      * @param response the response
499      * @return a PolicyResult
500      */
501     public PolicyResult onResponse(Object response) {
502         //
503         // Which response is it?
504         //
505         if (response instanceof Response) {
506             //
507             // Cast APPC response and handle it
508             //
509             return onResponse((Response) response);
510         } else if (response instanceof LcmResponseWrapper) {
511             //
512             // Cast LCM response and handle it
513             //
514             return onResponse((LcmResponseWrapper) response);
515         } else if (response instanceof PciResponseWrapper) {
516             //
517             // Cast SDNR response and handle it
518             //
519             return onResponse((PciResponseWrapper) response);
520         } else if (response instanceof SoResponseWrapper) {
521             //
522             // Cast SO response and handle it
523             //
524             return onResponse((SoResponseWrapper) response);
525         } else if (response instanceof VfcResponse) {
526             //
527             // Cast VFC response and handle it
528             //
529             return onResponse((VfcResponse) response);
530         } else if (response instanceof SdncResponse) {
531             //
532             // Cast SDNC response and handle it
533             //
534             return onResponse((SdncResponse) response);
535         } else if (response instanceof CdsResponse) {
536             //
537             // Cast CDS response and handle it
538             //
539             return onResponse((CdsResponse) response);
540         } else {
541             return null;
542         }
543     }
544
545     /**
546      * This method handles operation responses from APPC.
547      *
548      * @param appcResponse the APPC response
549      * @return The result of the response handling
550      */
551     private PolicyResult onResponse(Response appcResponse) {
552         //
553         // Determine which subrequestID (ie. attempt)
554         //
555         Integer operationAttempt = getSubRequestId(appcResponse);
556         if (operationAttempt == null) {
557             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
558                             PolicyResult.FAILURE_EXCEPTION);
559             return PolicyResult.FAILURE_EXCEPTION;
560         }
561         //
562         // Sanity check the response message
563         //
564         if (appcResponse.getStatus() == null) {
565             //
566             // We cannot tell what happened if this doesn't exist
567             //
568             this.completeOperation(operationAttempt,
569                     "Policy was unable to parse APP-C response status field (it was null).",
570                     PolicyResult.FAILURE_EXCEPTION);
571             return PolicyResult.FAILURE_EXCEPTION;
572         }
573         //
574         // Get the Response Code
575         //
576         ResponseCode code = ResponseCode.toResponseCode(appcResponse.getStatus().getCode());
577         if (code == null) {
578             //
579             // We are unaware of this code
580             //
581             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.",
582                     PolicyResult.FAILURE_EXCEPTION);
583             return PolicyResult.FAILURE_EXCEPTION;
584         }
585
586         return onResponse(appcResponse, operationAttempt, code);
587     }
588
589
590     private PolicyResult onResponse(Response appcResponse, Integer operationAttempt, ResponseCode code) {
591         //
592         // Ok, let's figure out what APP-C's response is
593         //
594         switch (code) {
595             case ACCEPT:
596                 //
597                 // This is good, they got our original message and
598                 // acknowledged it.
599                 //
600                 // Is there any need to track this?
601                 //
602                 return null;
603             case ERROR:
604             case REJECT:
605                 //
606                 // We'll consider these two codes as exceptions
607                 //
608                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
609                         PolicyResult.FAILURE_EXCEPTION);
610                 return getTimeoutResult(PolicyResult.FAILURE_EXCEPTION);
611             case SUCCESS:
612                 //
613                 //
614                 //
615                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
616                         PolicyResult.SUCCESS);
617                 return getTimeoutResult(PolicyResult.SUCCESS);
618             case FAILURE:
619                 //
620                 //
621                 //
622                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
623                         PolicyResult.FAILURE);
624                 return getTimeoutResult(PolicyResult.FAILURE);
625             default:
626                 return null;
627         }
628     }
629
630     /**
631      * This method handles operation responses from LCM.
632      *
633      * @param dmaapResponse the LCM response
634      * @return The result of the response handling
635      */
636     private PolicyResult onResponse(LcmResponseWrapper dmaapResponse) {
637         /*
638          * Parse out the operation attempt using the subrequestid
639          */
640         Integer operationAttempt = AppcLcmActorServiceProvider
641                 .parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
642         if (operationAttempt == null) {
643             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
644                     PolicyResult.FAILURE_EXCEPTION);
645             return PolicyResult.FAILURE_EXCEPTION;
646         }
647
648         /*
649          * Process the APPCLCM response to see what PolicyResult should be returned
650          */
651         AbstractMap.SimpleEntry<PolicyResult, String> result =
652                 AppcLcmActorServiceProvider.processResponse(dmaapResponse);
653
654         if (result.getKey() != null) {
655             this.completeOperation(operationAttempt, result.getValue(), result.getKey());
656             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
657                 return null;
658             }
659             return result.getKey();
660         }
661         return null;
662     }
663
664     /**
665      * This method handles operation responses from SDNR.
666      *
667      * @param dmaapResponse the SDNR response
668      * @return the result of the response handling
669      */
670     private PolicyResult onResponse(PciResponseWrapper dmaapResponse) {
671         /*
672          * Parse out the operation attempt using the subrequestid
673          */
674         Integer operationAttempt = SdnrActorServiceProvider
675                 .parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
676         if (operationAttempt == null) {
677             this.completeOperation(operationAttempt, "Policy was unable to parse SDNR SubRequestID.",
678                     PolicyResult.FAILURE_EXCEPTION);
679             return PolicyResult.FAILURE_EXCEPTION;
680         }
681
682         /*
683          * Process the SDNR response to see what PolicyResult should be returned
684          */
685         SdnrActorServiceProvider.Pair<PolicyResult, String> result =
686                 SdnrActorServiceProvider.processResponse(dmaapResponse);
687
688         if (result.getResult() != null) {
689             this.completeOperation(operationAttempt, result.getMessage(), result.getResult());
690             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
691                 return null;
692             }
693             return result.getResult();
694         }
695         return null;
696     }
697
698     /**
699      * This method handles operation responses from SO.
700      *
701      * @param msoResponse the SO response
702      * @return The result of the response handling
703      */
704     private PolicyResult onResponse(SoResponseWrapper msoResponse) {
705         switch (msoResponse.getSoResponse().getHttpResponseCode()) {
706             case 200:
707             case 202:
708                 //
709                 // Consider it as success
710                 //
711                 this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + SUCCESS_MSG,
712                         PolicyResult.SUCCESS);
713                 return getTimeoutResult(PolicyResult.SUCCESS);
714             default:
715                 //
716                 // Consider it as failure
717                 //
718                 this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + FAILED_MSG,
719                         PolicyResult.FAILURE);
720                 return getTimeoutResult(PolicyResult.FAILURE);
721         }
722     }
723
724     /**
725      * This method handles operation responses from VFC.
726      *
727      * @param vfcResponse the VFC response
728      * @return The result of the response handling
729      */
730     private PolicyResult onResponse(VfcResponse vfcResponse) {
731         if ("finished".equalsIgnoreCase(vfcResponse.getResponseDescriptor().getStatus())) {
732             //
733             // Consider it as success
734             //
735             this.completeOperation(this.attempts, SUCCESS_MSG, PolicyResult.SUCCESS);
736             return getTimeoutResult(PolicyResult.SUCCESS);
737         } else {
738             //
739             // Consider it as failure
740             //
741             this.completeOperation(this.attempts, FAILED_MSG, PolicyResult.FAILURE);
742             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
743                 return null;
744             }
745             // increment operation attempts for retries
746             this.attempts += 1;
747             return PolicyResult.FAILURE;
748         }
749     }
750
751     /**
752      * This method handles operation responses from SDNC.
753      *
754      * @param sdncResponse the VFC response
755      * @return The result of the response handling
756      */
757     private PolicyResult onResponse(SdncResponse sdncResponse) {
758         if ("200".equals(sdncResponse.getResponseOutput().getResponseCode())) {
759             //
760             // Consider it as success
761             //
762             this.completeOperation(this.attempts, SUCCESS_MSG, PolicyResult.SUCCESS);
763             return getTimeoutResult(PolicyResult.SUCCESS);
764         } else {
765             //
766             // Consider it as failure
767             //
768             this.completeOperation(this.attempts, FAILED_MSG, PolicyResult.FAILURE);
769             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
770                 return null;
771             }
772             // increment operation attempts for retries
773             this.attempts += 1;
774             return PolicyResult.FAILURE;
775         }
776     }
777
778     /**
779      * This method handles operation responses from CDS.
780      *
781      * @param response the CDS response
782      * @return The result of the response handling
783      */
784     private PolicyResult onResponse(CdsResponse response) {
785         if (response != null && CdsActorConstants.SUCCESS.equals(response.getStatus())) {
786             //
787             // Consider it as success
788             //
789             this.completeOperation(this.attempts, SUCCESS_MSG, PolicyResult.SUCCESS);
790             return getTimeoutResult(PolicyResult.SUCCESS);
791         } else {
792             //
793             // Consider it as failure
794             //
795             this.completeOperation(this.attempts, FAILED_MSG, PolicyResult.FAILURE);
796             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
797                 return null;
798             }
799             // increment operation attempts for retries
800             this.attempts += 1;
801             return PolicyResult.FAILURE;
802         }
803     }
804
805     private PolicyResult getTimeoutResult(PolicyResult result) {
806         return (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult) ? null : result);
807     }
808
809
810     private Integer getSubRequestId(Response appcResponse) {
811         try {
812             return Integer.valueOf(appcResponse.getCommonHeader().getSubRequestId());
813         } catch (NumberFormatException e) {
814             //
815             // We cannot tell what happened if this doesn't exist
816             //
817             return null;
818         }
819     }
820
821     /**
822      * Get the operation timeout.
823      *
824      * @return the timeout
825      */
826     public Integer getOperationTimeout() {
827         //
828         // Sanity check
829         //
830         if (this.policy == null) {
831             logger.debug("getOperationTimeout returning 0");
832             return 0;
833         }
834         logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
835         return this.policy.getTimeout();
836     }
837
838     /**
839      * Get the operation timeout as a String.
840      *
841      * @param defaultTimeout the default timeout
842      * @return the timeout as a String
843      */
844     public String getOperationTimeoutString(int defaultTimeout) {
845         Integer to = this.getOperationTimeout();
846         if (to == null || to == 0) {
847             return Integer.toString(defaultTimeout) + "s";
848         }
849         return to.toString() + "s";
850     }
851
852     public PolicyResult getOperationResult() {
853         return this.policyResult;
854     }
855
856     /**
857      * Get the operation as a message.
858      *
859      * @return the operation as a message
860      */
861     public String getOperationMessage() {
862         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
863             return this.currentOperation.clOperation.toMessage();
864         }
865
866         if (!this.operationHistory.isEmpty()) {
867             return this.operationHistory.getLast().clOperation.toMessage();
868         }
869         return null;
870     }
871
872     /**
873      * Get the operation as a message including the guard result.
874      *
875      * @param guardResult the guard result
876      * @return the operation as a message including the guard result
877      */
878     public String getOperationMessage(String guardResult) {
879         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
880             return this.currentOperation.clOperation.toMessage() + ", Guard result: " + guardResult;
881         }
882
883         if (!this.operationHistory.isEmpty()) {
884             return this.operationHistory.getLast().clOperation.toMessage() + ", Guard result: " + guardResult;
885         }
886         return null;
887     }
888
889     /**
890      * Get the operation history.
891      *
892      * @return the operation history
893      */
894     public String getOperationHistory() {
895         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
896             return this.currentOperation.clOperation.toHistory();
897         }
898
899         if (!this.operationHistory.isEmpty()) {
900             return this.operationHistory.getLast().clOperation.toHistory();
901         }
902         return null;
903     }
904
905     /**
906      * Get the history.
907      *
908      * @return the list of control loop operations
909      */
910     public List<ControlLoopOperation> getHistory() {
911         LinkedList<ControlLoopOperation> history = new LinkedList<>();
912         for (Operation op : this.operationHistory) {
913             history.add(new ControlLoopOperation(op.clOperation));
914
915         }
916         return history;
917     }
918
919     /**
920      * Set the operation has timed out.
921      */
922     public void setOperationHasTimedOut() {
923         //
924         //
925         //
926         this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
927     }
928
929     /**
930      * Set the operation has been denied by guard.
931      */
932     public void setOperationHasGuardDeny() {
933         //
934         //
935         //
936         this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
937     }
938
939     public void setOperationHasException(String message) {
940         this.completeOperation(this.attempts, message, PolicyResult.FAILURE_EXCEPTION);
941     }
942
943     /**
944      * Is the operation complete.
945      *
946      * @return <code>true</code> if the operation is complete, <code>false</code> otherwise
947      */
948     public boolean isOperationComplete() {
949         //
950         // Is there currently a result?
951         //
952         if (this.policyResult == null) {
953             //
954             // either we are in process or we
955             // haven't started
956             //
957             return false;
958         }
959         //
960         // We have some result, check if the operation failed
961         //
962         if (this.policyResult.equals(PolicyResult.FAILURE)) {
963             //
964             // Check if there were no retries specified
965             //
966             if (getMaxRetries() < 1) {
967                 //
968                 // The result is the failure
969                 //
970                 return true;
971             }
972             //
973             // Check retries
974             //
975             if (this.attempts > getMaxRetries()) {
976                 //
977                 // No more attempts allowed, reset
978                 // that our actual result is failure due to retries
979                 //
980                 this.policyResult = PolicyResult.FAILURE_RETRIES;
981                 return true;
982             } else {
983                 //
984                 // There are more attempts available to try the
985                 // policy recipe.
986                 //
987                 return false;
988             }
989         }
990         //
991         // Other results mean we are done
992         //
993         return true;
994     }
995
996     public boolean isOperationRunning() {
997         return (this.currentOperation != null);
998     }
999
1000     /**
1001      * This method verifies that the operation manager may run an operation.
1002      *
1003      * @return True if the operation can run, false otherwise
1004      * @throws ControlLoopException if the operation cannot run
1005      */
1006     private void verifyOperatonCanRun() throws ControlLoopException {
1007         //
1008         // They shouldn't call us if we currently running something
1009         //
1010         if (this.currentOperation != null) {
1011             //
1012             // what do we do if we are already running an operation?
1013             //
1014             throw new ControlLoopException("current operation is not null (an operation is already running)");
1015         }
1016         //
1017         // Check if we have maxed out on retries
1018         //
1019         if (getMaxRetries() < 1) {
1020             //
1021             // No retries are allowed, so check have we even made
1022             // one attempt to execute the operation?
1023             //
1024             if (this.attempts >= 1) {
1025                 //
1026                 // We have, let's ensure our PolicyResult is set
1027                 //
1028                 if (this.policyResult == null) {
1029                     this.policyResult = PolicyResult.FAILURE_RETRIES;
1030                 }
1031                 //
1032                 //
1033                 //
1034                 throw new ControlLoopException("current operation failed and retries are not allowed");
1035             }
1036         } else {
1037             //
1038             // Have we maxed out on retries?
1039             //
1040             if (this.attempts > getMaxRetries()) {
1041                 if (this.policyResult == null) {
1042                     this.policyResult = PolicyResult.FAILURE_RETRIES;
1043                 }
1044                 throw new ControlLoopException("current oepration has failed after " + this.attempts + " retries");
1045             }
1046         }
1047     }
1048
1049     /**
1050      * Gets the maximum number of retries.
1051      *
1052      * @return the maximum number of retries, or {@code 0}, if not specified
1053      */
1054     public int getMaxRetries() {
1055         return (policy.getRetry() != null ? policy.getRetry() : 0);
1056     }
1057
1058     private void storeOperationInDataBase() {
1059         // Only store in DB if enabled
1060         boolean guardEnabled = "false"
1061                         .equalsIgnoreCase(PolicyEngineConstants.getManager().getEnvironmentProperty("guard.disabled"));
1062         if (!guardEnabled) {
1063             return;
1064         }
1065
1066
1067         // DB Properties
1068         Properties props = new Properties();
1069         if (PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_URL) != null
1070                 && PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_USER) != null
1071                         && PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_PASS) != null) {
1072             props.put(Util.ECLIPSE_LINK_KEY_URL,
1073                             PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_URL));
1074             props.put(Util.ECLIPSE_LINK_KEY_USER,
1075                             PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_USER));
1076             props.put(Util.ECLIPSE_LINK_KEY_PASS,
1077                             PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_PASS));
1078             props.put(PersistenceUnitProperties.CLASSLOADER, ControlLoopOperationManager.class.getClassLoader());
1079         }
1080
1081
1082         String opsHistPu = System.getProperty("OperationsHistoryPU");
1083         if (!"OperationsHistoryPUTest".equals(opsHistPu)) {
1084             opsHistPu = "OperationsHistoryPU";
1085         } else {
1086             props.clear();
1087         }
1088         EntityManager em;
1089         try {
1090             em = Persistence.createEntityManagerFactory(opsHistPu, props).createEntityManager();
1091         } catch (Exception e) {
1092             logger.error("storeOperationInDataBase threw: ", e);
1093             return;
1094         }
1095
1096         Dbao newEntry = new Dbao();
1097
1098         newEntry.setClosedLoopName(this.onset.getClosedLoopControlName());
1099         newEntry.setRequestId(this.onset.getRequestId().toString());
1100         newEntry.setActor(this.currentOperation.clOperation.getActor());
1101         newEntry.setOperation(this.currentOperation.clOperation.getOperation());
1102         newEntry.setTarget(this.targetEntity);
1103         newEntry.setStarttime(Timestamp.from(this.currentOperation.clOperation.getStart()));
1104         newEntry.setSubrequestId(this.currentOperation.clOperation.getSubRequestId());
1105         newEntry.setEndtime(new Timestamp(this.currentOperation.clOperation.getEnd().toEpochMilli()));
1106         newEntry.setMessage(this.currentOperation.clOperation.getMessage());
1107         newEntry.setOutcome(this.currentOperation.clOperation.getOutcome());
1108
1109         em.getTransaction().begin();
1110         em.persist(newEntry);
1111         em.getTransaction().commit();
1112
1113         em.close();
1114     }
1115
1116     private void completeOperation(Integer attempt, String message, PolicyResult result) {
1117         if (attempt == null) {
1118             logger.debug("attempt cannot be null (i.e. subRequestID)");
1119             return;
1120         }
1121         if (this.currentOperation != null) {
1122             if (this.currentOperation.attempt == attempt.intValue()) {
1123                 this.currentOperation.clOperation.setEnd(Instant.now());
1124                 this.currentOperation.clOperation.setMessage(message);
1125                 this.currentOperation.clOperation.setOutcome(result.toString());
1126                 this.currentOperation.policyResult = result;
1127                 //
1128                 // Save it in history
1129                 //
1130                 this.operationHistory.add(this.currentOperation);
1131                 this.storeOperationInDataBase();
1132                 //
1133                 // Set our last result
1134                 //
1135                 this.policyResult = result;
1136                 //
1137                 // Clear the current operation field
1138                 //
1139                 this.currentOperation = null;
1140                 return;
1141             }
1142             logger.debug("not current");
1143         }
1144         for (Operation op : this.operationHistory) {
1145             if (op.attempt == attempt.intValue()) {
1146                 op.clOperation.setEnd(Instant.now());
1147                 op.clOperation.setMessage(message);
1148                 op.clOperation.setOutcome(result.toString());
1149                 op.policyResult = result;
1150                 return;
1151             }
1152         }
1153         logger.debug("Could not find associated operation");
1154     }
1155
1156
1157     /**
1158      * Commit the abatement to the history database.
1159      *
1160      * @param message the abatement message
1161      * @param outcome the abatement outcome
1162      */
1163     public void commitAbatement(String message, String outcome) {
1164         logger.info("commitAbatement: {}. {}", message, outcome);
1165
1166         if (this.currentOperation == null) {
1167             try {
1168                 this.currentOperation = this.operationHistory.getLast();
1169             } catch (NoSuchElementException e) {
1170                 logger.error("{}: commitAbatement threw an exception ", this, e);
1171                 return;
1172             }
1173         }
1174         this.currentOperation.clOperation.setEnd(Instant.now());
1175         this.currentOperation.clOperation.setMessage(message);
1176         this.currentOperation.clOperation.setOutcome(outcome);
1177         //
1178         // Store commit in DB
1179         //
1180         this.storeOperationInDataBase();
1181         //
1182         // Clear the current operation field
1183         //
1184         this.currentOperation = null;
1185     }
1186
1187     /**
1188      * Construct a ControlLoopResponse object from actor response and input event.
1189      *
1190      * @param response the response from actor
1191      * @param event the input event
1192      *
1193      * @return a ControlLoopResponse
1194      */
1195     public ControlLoopResponse getControlLoopResponse(Object response, VirtualControlLoopEvent event) {
1196         if (response instanceof PciResponseWrapper) {
1197             //
1198             // Cast SDNR response and handle it
1199             //
1200             return SdnrActorServiceProvider.getControlLoopResponse((PciResponseWrapper) response, event);
1201         } else {
1202             return null;
1203         }
1204     }
1205
1206 }