5d80ea5f44dccf81312ed417aa3ecd64a354774b
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 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.step;
22
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.BiConsumer;
30 import java.util.function.Consumer;
31 import lombok.Getter;
32 import lombok.Setter;
33 import org.apache.commons.lang3.StringUtils;
34 import org.onap.aai.domain.yang.CloudRegion;
35 import org.onap.aai.domain.yang.GenericVnf;
36 import org.onap.aai.domain.yang.ModelVer;
37 import org.onap.aai.domain.yang.ServiceInstance;
38 import org.onap.aai.domain.yang.Tenant;
39 import org.onap.policy.aai.AaiCqResponse;
40 import org.onap.policy.common.utils.coder.StandardCoderObject;
41 import org.onap.policy.controlloop.VirtualControlLoopEvent;
42 import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
43 import org.onap.policy.controlloop.actor.aai.AaiGetTenantOperation;
44 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
45 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
46 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
47 import org.onap.policy.controlloop.eventmanager.Step;
48 import org.onap.policy.controlloop.eventmanager.StepContext;
49 import org.onap.policy.drools.apps.controller.usecases.UsecasesConstants;
50
51 /**
52  * Steps specific to the usecases controller. The {@link #setProperties()} method is used
53  * to load the various properties into the operation, extracting enrichment data where
54  * appropriate, and extracting other data from the step's context. For each property,
55  * there is a getXxx() method for extracting the value and a loadXxx() method for loading
56  * the extracted value into the operation. In addition, the
57  * {@link #success(OperationOutcome)} method is responsible for extracting responses from
58  * an operation outcome and recording the data in the step's context for use by subsequent
59  * steps.
60  */
61 public class Step2 extends Step {
62     public static final String TARGET_MODEL_VERSION_ID = "modelVersionId";
63     public static final String TARGET_MODEL_CUSTOMIZATION_ID = "modelCustomizationId";
64     public static final String TARGET_MODEL_INVARIANT_ID = "modelInvariantId";
65     public static final String TARGET_RESOURCE_ID = "resourceID";
66     public static final String TARGET_INFO_MSG = "Target Entity IDs";
67     public static final String ENRICHMENT_PREFIX = "enrichment/";
68     public static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
69     public static final String RESOURCE_LINK = "resource-link";
70     public static final String RESULT_DATA = "result-data";
71
72     private static final Map<String, BiConsumer<Step2, String>> PROPERTY_LOADER;
73     private static final Map<String, Consumer<Step2>> PROPERTY_SAVER;
74
75     static {
76         /*
77          * Populate map for PROPERTY_LOADER.
78          */
79         Map<String, BiConsumer<Step2, String>> map = new HashMap<>();
80
81         map.put(OperationProperties.AAI_DEFAULT_CLOUD_REGION, Step2::loadCloudRegion);
82         map.put(OperationProperties.AAI_DEFAULT_TENANT, Step2::loadTenant);
83         map.put(OperationProperties.AAI_PNF, Step2::loadPnf);
84         map.put(OperationProperties.AAI_RESOURCE_VNF, Step2::loadResourceVnf);
85         map.put(OperationProperties.AAI_SERVICE, Step2::loadService);
86         map.put(OperationProperties.AAI_SERVICE_MODEL, Step2::loadServiceModel);
87         map.put(OperationProperties.AAI_TARGET_ENTITY, Step2::loadTargetEntity);
88         map.put(OperationProperties.AAI_VNF, Step2::loadVnf);
89         map.put(OperationProperties.AAI_VNF_MODEL, Step2::loadVnfModel);
90         map.put(OperationProperties.AAI_VSERVER_LINK, Step2::loadVserverLink);
91         map.put(OperationProperties.DATA_VF_COUNT, Step2::loadVfCount);
92         map.put(OperationProperties.EVENT_ADDITIONAL_PARAMS, Step2::loadAdditionalEventParams);
93         map.put(OperationProperties.EVENT_PAYLOAD, Step2::loadEventPayload);
94         map.put(OperationProperties.OPT_CDS_GRPC_AAI_PROPERTIES, Step2::loadOptCdsGrpcAaiProperties);
95
96         map.put(UsecasesConstants.AAI_DEFAULT_GENERIC_VNF, Step2::loadDefaultGenericVnf);
97
98         PROPERTY_LOADER = Collections.unmodifiableMap(map);
99
100
101         /*
102          * Populate map for PROPERTY_SAVER.
103          */
104         Map<String, Consumer<Step2>> map2 = new HashMap<>();
105
106         map2.put(OperationProperties.DATA_VF_COUNT, Step2::storeVfCount);
107
108         PROPERTY_SAVER = Collections.unmodifiableMap(map2);
109     }
110
111
112     protected final StepContext stepContext;
113     protected final VirtualControlLoopEvent event;
114
115     /**
116      * {@code True} if the associated preprocessing steps have been loaded, {@code false}
117      * otherwise.
118      */
119     @Getter
120     @Setter
121     private boolean preprocessed;
122
123     /**
124      * Actions to take to store the Operation's properties back into the context.
125      */
126     private List<Consumer<Step2>> postProcessors = new LinkedList<>();
127
128
129     /**
130      * Constructs the object. This is used when constructing the step for the policy's
131      * actual operation.
132      *
133      * @param stepContext the step's context
134      * @param params operation parameters
135      * @param event the event being processed
136      */
137     public Step2(StepContext stepContext, ControlLoopOperationParams params, VirtualControlLoopEvent event) {
138         super(params, new AtomicReference<>());
139         this.stepContext = stepContext;
140         this.event = event;
141     }
142
143     /**
144      * Constructs the object using information from another step. This is used when
145      * constructing a preprocessing step.
146      *
147      * @param otherStep step whose information should be used
148      * @param actor actor name
149      * @param operation operation name
150      */
151     public Step2(Step2 otherStep, String actor, String operation) {
152         super(otherStep, actor, operation);
153         this.stepContext = otherStep.stepContext;
154         this.event = otherStep.event;
155     }
156
157     /**
158      * Determines if starting this step indicates acceptance of the event. The default
159      * method simply invokes {@link #isPolicyStep()}.
160      *
161      * @return {@code true} if this step accepts the event, {@code false} if it is still
162      *         indeterminate
163      */
164     public boolean acceptsEvent() {
165         return isPolicyStep();
166     }
167
168     /**
169      * Indicates that the step succeeded with the given outcome. Invoked by the rules. The
170      * default method invokes the post processors.
171      *
172      * @param outcome operation's outcome
173      */
174     public void success(OperationOutcome outcome) {
175         for (Consumer<Step2> proc : postProcessors) {
176             proc.accept(this);
177         }
178     }
179
180     /**
181      * Gets the names of the properties required by the operation. The default method just
182      * delegates to the operation to identify the properties.
183      *
184      * @return the names of the properties required by the operation
185      */
186     public List<String> getPropertyNames() {
187         return getOperation().getPropertyNames();
188     }
189
190     /**
191      * Sets the operation's properties. This is invoked <i>after</i> any preprocessor
192      * steps have been performed. It also adds items to {@link #postProcessors}.
193      */
194     public void setProperties() {
195         postProcessors.clear();
196
197         for (String propName : getPropertyNames()) {
198             // identify the saver, if any
199             Consumer<Step2> saver = PROPERTY_SAVER.get(propName);
200             if (saver != null) {
201                 postProcessors.add(saver);
202             }
203
204
205             // load data
206             if (propName.startsWith(ENRICHMENT_PREFIX)) {
207                 loadEnrichment(propName);
208                 continue;
209             }
210
211             BiConsumer<Step2, String> loader = PROPERTY_LOADER.get(propName);
212             if (loader == null) {
213                 throw new IllegalArgumentException("unknown property " + propName + " needed by " + getActorName() + "."
214                                 + getOperationName());
215             }
216
217             loader.accept(this, propName);
218         }
219     }
220
221     protected void loadCloudRegion(String propName) {
222         getOperation().setProperty(propName, getCloudRegion());
223     }
224
225     protected void loadTenant(String propName) {
226         getOperation().setProperty(propName, getTenant());
227     }
228
229     protected void loadPnf(String propName) {
230         getOperation().setProperty(propName, getPnf());
231     }
232
233     protected void loadResourceVnf(String propName) {
234         getOperation().setProperty(propName, getResourceVnf());
235     }
236
237     protected void loadService(String propName) {
238         getOperation().setProperty(propName, getService());
239     }
240
241     protected void loadServiceModel(String propName) {
242         getOperation().setProperty(propName, getServiceModel());
243     }
244
245     protected void loadTargetEntity(String propName) {
246         getOperation().setProperty(propName, getTargetEntity());
247     }
248
249     protected void loadVnf(String propName) {
250         getOperation().setProperty(propName, getVnf());
251     }
252
253     protected void loadVnfModel(String propName) {
254         getOperation().setProperty(propName, getVnfModel());
255     }
256
257     protected void loadVserverLink(String propName) {
258         getOperation().setProperty(propName, getVserverLink());
259     }
260
261     protected void loadVfCount(String propName) {
262         getOperation().setProperty(propName, getVfCount());
263     }
264
265     protected void loadEnrichment(String propName) {
266         getOperation().setProperty(propName, getEnrichment(propName));
267     }
268
269     protected void loadAdditionalEventParams(String propName) {
270         getOperation().setProperty(propName, getAdditionalEventParams());
271     }
272
273     protected void loadEventPayload(String propName) {
274         getOperation().setProperty(propName, getEventPayload());
275     }
276
277     protected void loadOptCdsGrpcAaiProperties(String propName) {
278         // do nothing
279     }
280
281     protected void loadDefaultGenericVnf(String propName) {
282         getOperation().setProperty(propName, getDefaultGenericVnf());
283     }
284
285     protected CloudRegion getCloudRegion() {
286         AaiCqResponse aaicq = getCustomQueryData();
287         return aaicq.getDefaultCloudRegion();
288     }
289
290     protected Tenant getTenant() {
291         AaiCqResponse aaicq = getCustomQueryData();
292         return aaicq.getDefaultTenant();
293     }
294
295     protected StandardCoderObject getPnf() {
296         return stepContext.getProperty(AaiGetPnfOperation.getKey(getTargetEntity()));
297     }
298
299     protected GenericVnf getResourceVnf() {
300         verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
301
302         String resourceId = params.getTargetEntityIds().get(TARGET_RESOURCE_ID);
303
304         verifyNotNull("Target resource ID", resourceId);
305
306         AaiCqResponse aaicq = getCustomQueryData();
307         return aaicq.getGenericVnfByModelInvariantId(resourceId);
308     }
309
310     protected ServiceInstance getService() {
311         AaiCqResponse aaicq = getCustomQueryData();
312         return aaicq.getServiceInstance();
313     }
314
315     protected ModelVer getServiceModel() {
316         AaiCqResponse aaicq = getCustomQueryData();
317         ServiceInstance service = aaicq.getServiceInstance();
318         return aaicq.getModelVerByVersionId(service.getModelVersionId());
319     }
320
321     /**
322      * The default method assumes there is only one target entity and that it's stored
323      * within the step's context.
324      */
325     protected String getTargetEntity() {
326         return stepContext.getProperty(OperationProperties.AAI_TARGET_ENTITY);
327     }
328
329     protected GenericVnf getVnf() {
330         verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
331
332         String modelInvariantId = params.getTargetEntityIds().get(TARGET_MODEL_INVARIANT_ID);
333
334         verifyNotNull(TARGET_MODEL_INVARIANT_ID, modelInvariantId);
335
336         AaiCqResponse aaicq = getCustomQueryData();
337         return aaicq.getGenericVnfByVfModuleModelInvariantId(modelInvariantId);
338     }
339
340     protected ModelVer getVnfModel() {
341         GenericVnf vnf = getVnf();
342         AaiCqResponse aaicq = getCustomQueryData();
343         return aaicq.getModelVerByVersionId(vnf.getModelVersionId());
344     }
345
346     protected String getVserverLink() {
347         String vserver = event.getAai().get(VSERVER_VSERVER_NAME);
348         if (StringUtils.isBlank(vserver)) {
349             throw new IllegalArgumentException("missing " + VSERVER_VSERVER_NAME + " in enrichment data");
350         }
351
352         StandardCoderObject tenant = stepContext.getProperty(AaiGetTenantOperation.getKey(vserver));
353         verifyNotNull("tenant data", tenant);
354
355         String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
356         verifyNotNull("tenant data resource-link", resourceLink);
357
358         return stripPrefix(resourceLink, 3);
359     }
360
361     protected Integer getVfCount() {
362         if (stepContext.contains(OperationProperties.DATA_VF_COUNT)) {
363             return stepContext.getProperty(OperationProperties.DATA_VF_COUNT);
364         }
365
366         verifyNotNull(TARGET_INFO_MSG, params.getTargetEntityIds());
367
368         String modelCustomizationId = params.getTargetEntityIds().get(TARGET_MODEL_CUSTOMIZATION_ID);
369         String modelInvariantId = params.getTargetEntityIds().get(TARGET_MODEL_INVARIANT_ID);
370         String modelVersionId = params.getTargetEntityIds().get(TARGET_MODEL_VERSION_ID);
371
372         verifyNotNull("target modelCustomizationId", modelCustomizationId);
373         verifyNotNull("target modelInvariantId", modelInvariantId);
374         verifyNotNull("target modelVersionId", modelVersionId);
375
376         AaiCqResponse aaicq = getCustomQueryData();
377         return aaicq.getVfModuleCount(modelCustomizationId, modelInvariantId, modelVersionId);
378     }
379
380     protected String getEnrichment(String propName) {
381         String enrichmentKey = propName.substring(ENRICHMENT_PREFIX.length());
382         String value = event.getAai().get(enrichmentKey);
383         verifyNotNull(propName, value);
384
385         return value;
386     }
387
388     protected Map<String, String> getAdditionalEventParams() {
389         return event.getAdditionalEventParams();
390     }
391
392     protected String getEventPayload() {
393         return event.getPayload();
394     }
395
396     protected GenericVnf getDefaultGenericVnf() {
397         AaiCqResponse aaicq = getCustomQueryData();
398         return aaicq.getDefaultGenericVnf();
399     }
400
401     protected AaiCqResponse getCustomQueryData() {
402         AaiCqResponse aaicq = stepContext.getProperty(AaiCqResponse.CONTEXT_KEY);
403         verifyNotNull("custom query data", aaicq);
404
405         return aaicq;
406     }
407
408     protected void storeVfCount() {
409         if (!getOperation().containsProperty(OperationProperties.DATA_VF_COUNT)) {
410             return;
411         }
412
413         int vfcount = getOperation().getProperty(OperationProperties.DATA_VF_COUNT);
414         stepContext.setProperty(OperationProperties.DATA_VF_COUNT, vfcount);
415     }
416
417     protected void verifyNotNull(String propName, Object value) {
418         if (value == null) {
419             throw new IllegalArgumentException(
420                             "missing " + propName + " for " + getActorName() + "." + getOperationName());
421         }
422     }
423
424     protected static String stripPrefix(String resourceLink, int ncomponents) {
425         int previdx = -1;
426         for (int nslashes = 0; nslashes < ncomponents; ++nslashes) {
427             int idx = resourceLink.indexOf('/', previdx + 1);
428             if (idx < 0) {
429                 break;
430             }
431
432             previdx = idx;
433         }
434
435         return resourceLink.substring(Math.max(0, previdx));
436     }
437 }