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