Fix topic lower case for kafka compability
[policy/drools-applications.git] / controlloop / common / controller-usecases / src / main / java / org / onap / policy / drools / apps / controller / usecases / UsecasesEventManager.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2024 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.drools.apps.controller.usecases;
23
24 import static org.onap.policy.controlloop.ControlLoopTargetType.PNF;
25 import static org.onap.policy.controlloop.ControlLoopTargetType.VM;
26 import static org.onap.policy.controlloop.ControlLoopTargetType.VNF;
27 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED;
28 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.GENERIC_VNF_PROV_STATUS;
29 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.GENERIC_VNF_VNF_ID;
30 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.GENERIC_VNF_VNF_NAME;
31 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.PNF_IS_IN_MAINT;
32 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.PNF_NAME;
33 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.PROV_STATUS_ACTIVE;
34 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.VM_NAME;
35 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.VNF_NAME;
36 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.VSERVER_IS_CLOSED_LOOP_DISABLED;
37 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.VSERVER_PROV_STATUS;
38 import static org.onap.policy.drools.apps.controller.usecases.UsecasesConstants.VSERVER_VSERVER_NAME;
39
40 import java.io.Serial;
41 import java.util.Deque;
42 import java.util.Map;
43 import java.util.Set;
44 import java.util.stream.Collectors;
45 import java.util.stream.Stream;
46 import org.drools.core.WorkingMemory;
47 import org.onap.policy.controlloop.ControlLoopException;
48 import org.onap.policy.controlloop.ControlLoopResponse;
49 import org.onap.policy.controlloop.VirtualControlLoopEvent;
50 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
51 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
52 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
53 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
54 import org.onap.policy.controlloop.eventmanager.ActorConstants;
55 import org.onap.policy.controlloop.eventmanager.ClEventManagerWithEvent;
56 import org.onap.policy.controlloop.eventmanager.EventManagerServices;
57 import org.onap.policy.controlloop.eventmanager.StepContext;
58 import org.onap.policy.drools.apps.controller.usecases.step.AaiCqStep2;
59 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetPnfStep2;
60 import org.onap.policy.drools.apps.controller.usecases.step.AaiGetTenantStep2;
61 import org.onap.policy.drools.apps.controller.usecases.step.GetTargetEntityStep2;
62 import org.onap.policy.drools.apps.controller.usecases.step.GuardStep2;
63 import org.onap.policy.drools.apps.controller.usecases.step.LockStep2;
64 import org.onap.policy.drools.apps.controller.usecases.step.Step2;
65 import org.onap.policy.sdnr.PciMessage;
66
67 /**
68  * Manager for a single control loop event. Once this has been created, the event can be
69  * retracted from working memory. Processing progresses through each policy, which
70  * involves at least one step. As a step is processed, additional preprocessor steps may
71  * be pushed onto the queue (e.g., locks, A&AI queries, guards).
72  */
73 public class UsecasesEventManager extends ClEventManagerWithEvent<Step2> implements StepContext {
74
75     @Serial
76     private static final long serialVersionUID = -1216568161322872641L;
77
78     /**
79      * If there's a failure from one of these actors, then the TOSCA processing should be
80      * aborted.
81      */
82     private static final Set<String> ABORT_ACTORS = Set.of(ActorConstants.CL_TIMEOUT_ACTOR, ActorConstants.LOCK_ACTOR);
83
84     private static final Set<String> VALID_TARGETS = Stream
85                     .of(VM_NAME, VNF_NAME, VSERVER_VSERVER_NAME, GENERIC_VNF_VNF_ID, GENERIC_VNF_VNF_NAME, PNF_NAME)
86                     .map(String::toLowerCase).collect(Collectors.toSet());
87
88     private static final Set<String> TRUE_VALUES = Set.of("true", "t", "yes", "y");
89
90     /**
91      * Names of Operation properties for which A&AI PNF query is needed.
92      */
93     private static final Set<String> PNF_PROPERTIES = Set.of(OperationProperties.AAI_PNF);
94
95     /**
96      * Names of Operation properties for which A&AI Tenant query is needed.
97      */
98     private static final Set<String> TENANT_PROPERTIES = Set.of(OperationProperties.AAI_VSERVER_LINK);
99
100     /**
101      * Names of Operation properties for which A&AI custom query is needed.
102      */
103     private static final Set<String> CQ_PROPERTIES = Set.of(OperationProperties.AAI_DEFAULT_CLOUD_REGION,
104                     OperationProperties.AAI_VNF, OperationProperties.AAI_SERVICE_MODEL,
105                     OperationProperties.AAI_VNF_MODEL, OperationProperties.AAI_SERVICE,
106                     OperationProperties.AAI_RESOURCE_VNF, UsecasesConstants.AAI_DEFAULT_GENERIC_VNF);
107
108
109     /**
110      * Constructs the object.
111      *
112      * @param services services the manager should use when processing the event
113      * @param params control loop parameters
114      * @param event event to be managed by this object
115      * @param workMem working memory to update if this changes
116      * @throws ControlLoopException if the event is invalid or if a YAML processor cannot
117      *         be created
118      */
119     public UsecasesEventManager(EventManagerServices services, ControlLoopParams params, VirtualControlLoopEvent event,
120                     WorkingMemory workMem) throws ControlLoopException {
121
122         super(services, params, event, workMem);
123
124         if (isClosedLoopDisabled(event)) {
125             throw new IllegalStateException("is-closed-loop-disabled is set to true on VServer or VNF");
126         }
127
128         if (isProvStatusInactive(event)) {
129             throw new IllegalStateException("prov-status is not ACTIVE on VServer or VNF");
130         }
131     }
132
133     /*
134      * This is needed to satisfy drools, thus disabling sonar.
135      */
136     @Override
137     public Deque<Step2> getSteps() {    // NOSONAR
138         return super.getSteps();
139     }
140
141     @Override
142     public void loadPreprocessorSteps() {
143         super.loadPreprocessorSteps();
144
145         final Deque<Step2> steps = getSteps();
146         final Step2 step = getSteps().peek();
147
148         // determine if any A&AI queries are needed
149         var needCq = false;
150         var needPnf = false;
151         var needTenant = false;
152         var needTargetEntity = false;
153
154         for (String propName : step.getPropertyNames()) {
155             needCq = needCq || CQ_PROPERTIES.contains(propName);
156             needPnf = needPnf || PNF_PROPERTIES.contains(propName);
157             needTenant = needTenant || TENANT_PROPERTIES.contains(propName);
158             needTargetEntity = needTargetEntity || OperationProperties.AAI_TARGET_ENTITY.equals(propName);
159         }
160
161         /*
162          * The Policy's actual operation requires additional, implicit steps, such as
163          * locking and guards.
164          */
165         final boolean needPolicySteps = step.isPolicyStep();
166
167
168         /*
169          * NOTE: need to push steps onto the queue in the OPPOSITE order in which they
170          * must be performed.
171          */
172
173
174         // GUARD must be pushed first
175         if (needPolicySteps) {
176             steps.push(new GuardStep2(step, getClosedLoopControlName()));
177         }
178
179         // A&AI queries
180         if (needCq) {
181             steps.push(new AaiCqStep2(step));
182         }
183
184         if (needPnf) {
185             steps.push(new AaiGetPnfStep2(step));
186         }
187
188         if (needTenant) {
189             steps.push(new AaiGetTenantStep2(step));
190         }
191
192         // LOCK must be pushed after the queries
193         if (needPolicySteps) {
194             steps.push(new LockStep2(step));
195         }
196
197         // GET-TARGET-ENTITY should be pushed last
198         if (needTargetEntity) {
199             steps.push(new GetTargetEntityStep2(step));
200         }
201     }
202
203     @Override
204     public boolean isAbort(OperationOutcome outcome) {
205         return (super.isAbort(outcome) && ABORT_ACTORS.contains(outcome.getActor()));
206     }
207
208     /**
209      * Stores an operation outcome in the DB.
210      *
211      * @param outcome operation outcome to store
212      */
213     public void storeInDataBase(OperationOutcome2 outcome) {
214         storeInDataBase(outcome, getProperty(OperationProperties.AAI_TARGET_ENTITY));
215     }
216
217     @Override
218     public ControlLoopResponse makeControlLoopResponse(OperationOutcome outcome) {
219         var clRsp = super.makeControlLoopResponse(outcome);
220
221         Object obj = outcome.getResponse();
222         if (!(obj instanceof PciMessage)) {
223             return clRsp;
224         }
225
226         PciMessage msg = (PciMessage) obj;
227         if (msg.getBody() != null && msg.getBody().getOutput() != null) {
228             clRsp.setPayload(msg.getBody().getOutput().getPayload());
229         }
230
231         return clRsp;
232     }
233
234     @Override
235     protected void checkEventSyntax(VirtualControlLoopEvent event) throws ControlLoopException {
236         super.checkEventSyntax(event);
237         validateAaiData(event);
238     }
239
240     @Override
241     protected void validateTarget(VirtualControlLoopEvent event) throws ControlLoopException {
242         super.validateTarget(event);
243
244         if (!VALID_TARGETS.contains(event.getTarget().toLowerCase())) {
245             throw new ControlLoopException("target field invalid");
246         }
247     }
248
249     private void validateAaiData(VirtualControlLoopEvent event) throws ControlLoopException {
250         Map<String, String> eventAai = event.getAai();
251         if (eventAai == null) {
252             throw new ControlLoopException("AAI is null");
253         }
254         if (event.getTargetType() == null) {
255             throw new ControlLoopException("The Target type is null");
256         }
257         switch (event.getTargetType()) {
258             case VM, VNF:
259                 validateAaiVmVnfData(eventAai);
260                 return;
261             case PNF:
262                 validateAaiPnfData(eventAai);
263                 return;
264             default:
265                 throw new ControlLoopException("The target type is not supported");
266         }
267     }
268
269     private void validateAaiVmVnfData(Map<String, String> eventAai) throws ControlLoopException {
270         if (eventAai.get(GENERIC_VNF_VNF_ID) == null && eventAai.get(VSERVER_VSERVER_NAME) == null
271                         && eventAai.get(GENERIC_VNF_VNF_NAME) == null) {
272             throw new ControlLoopException(
273                             "generic-vnf.vnf-id or generic-vnf.vnf-name or vserver.vserver-name information missing");
274         }
275     }
276
277     private void validateAaiPnfData(Map<String, String> eventAai) throws ControlLoopException {
278         if (eventAai.get(PNF_NAME) == null) {
279             throw new ControlLoopException("AAI PNF object key pnf-name is missing");
280         }
281     }
282
283     /**
284      * Is closed loop disabled for an event.
285      *
286      * @param event the event
287      * @return <code>true</code> if the control loop is disabled, <code>false</code>
288      *         otherwise
289      */
290     private static boolean isClosedLoopDisabled(VirtualControlLoopEvent event) {
291         Map<String, String> aai = event.getAai();
292         return (isAaiTrue(aai.get(VSERVER_IS_CLOSED_LOOP_DISABLED))
293                         || isAaiTrue(aai.get(GENERIC_VNF_IS_CLOSED_LOOP_DISABLED))
294                         || isAaiTrue(aai.get(PNF_IS_IN_MAINT)));
295     }
296
297     /**
298      * Does provisioning status, for an event, have a value other than ACTIVE.
299      *
300      * @param event the event
301      * @return {@code true} if the provisioning status is neither ACTIVE nor {@code null},
302      *         {@code false} otherwise
303      */
304     private static boolean isProvStatusInactive(VirtualControlLoopEvent event) {
305         Map<String, String> aai = event.getAai();
306         return !(PROV_STATUS_ACTIVE.equalsIgnoreCase(aai.getOrDefault(VSERVER_PROV_STATUS, PROV_STATUS_ACTIVE))
307                         && PROV_STATUS_ACTIVE.equalsIgnoreCase(
308                                         aai.getOrDefault(GENERIC_VNF_PROV_STATUS, PROV_STATUS_ACTIVE)));
309     }
310
311     /**
312      * Determines the boolean value represented by the given AAI field value.
313      *
314      * @param aaiValue value to be examined
315      * @return the boolean value represented by the field value, or {@code false} if the
316      *         value is {@code null}
317      */
318     private static boolean isAaiTrue(String aaiValue) {
319         return (aaiValue != null && TRUE_VALUES.contains(aaiValue.toLowerCase()));
320     }
321
322     @Override
323     protected void loadPolicyStep(ControlLoopOperationParams params) {
324         getSteps().add(new Step2(this, params, getEvent()));
325     }
326 }