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