move actors code in drools-applications to policy/models
[policy/models.git] / models-interactions / model-actors / actor.so / src / main / java / org / onap / policy / controlloop / actor / so / SoActorServiceProvider.java
1 /*
2  * ============LICENSE_START=======================================================
3  * SOActorServiceProvider
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019 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.controlloop.actor.so;
23
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.gson.reflect.TypeToken;
27 import java.lang.reflect.Type;
28 import java.util.Collections;
29 import java.util.List;
30 import java.util.Map;
31 import org.drools.core.WorkingMemory;
32 import org.onap.policy.aai.AaiNqExtraProperty;
33 import org.onap.policy.aai.AaiNqInventoryResponseItem;
34 import org.onap.policy.aai.AaiNqResponseWrapper;
35 import org.onap.policy.controlloop.ControlLoopOperation;
36 import org.onap.policy.controlloop.VirtualControlLoopEvent;
37 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
38 import org.onap.policy.controlloop.policy.Policy;
39 import org.onap.policy.so.SoCloudConfiguration;
40 import org.onap.policy.so.SoManager;
41 import org.onap.policy.so.SoModelInfo;
42 import org.onap.policy.so.SoOperationType;
43 import org.onap.policy.so.SoRelatedInstance;
44 import org.onap.policy.so.SoRelatedInstanceListElement;
45 import org.onap.policy.so.SoRequest;
46 import org.onap.policy.so.SoRequestDetails;
47 import org.onap.policy.so.SoRequestInfo;
48 import org.onap.policy.so.SoRequestParameters;
49 import org.onap.policy.so.util.Serialization;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class SoActorServiceProvider implements Actor {
54     private static final Logger logger = LoggerFactory.getLogger(SoActorServiceProvider.class);
55
56     // Strings for SO Actor
57     private static final String SO_ACTOR = "SO";
58
59     // Strings for targets
60     private static final String TARGET_VFC = "VFC";
61
62     // Strings for recipes
63     private static final String RECIPE_VF_MODULE_CREATE = "VF Module Create";
64     private static final String RECIPE_VF_MODULE_DELETE = "VF Module Delete";
65
66     private static final ImmutableList<String> recipes = ImmutableList.of(RECIPE_VF_MODULE_CREATE,
67             RECIPE_VF_MODULE_DELETE);
68     private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>()
69                     .put(RECIPE_VF_MODULE_CREATE, ImmutableList.of(TARGET_VFC))
70                     .put(RECIPE_VF_MODULE_DELETE, ImmutableList.of(TARGET_VFC)).build();
71
72     // name of request parameters within policy payload
73     public static final String REQ_PARAM_NM = "requestParameters";
74
75     // name of configuration parameters within policy payload
76     public static final String CONFIG_PARAM_NM = "configurationParameters";
77
78     private static final String MODEL_NAME_PROPERTY_KEY = "model-ver.model-name";
79     private static final String MODEL_VERSION_PROPERTY_KEY = "model-ver.model-version";
80     private static final String MODEL_VERSION_ID_PROPERTY_KEY = "model-ver.model-version-id";
81
82     // used to decode configuration parameters via gson
83     private static final Type CONFIG_TYPE = new TypeToken<List<Map<String, String>>>() {}.getType();
84
85     // Static variables required to hold the IDs of the last service item, VNF item and VF Module.
86     // Note that in
87     // a multithreaded deployment this WILL break
88     private static String lastVNFItemVnfId;
89     private static String lastServiceItemServiceInstanceId;
90     private static String lastVfModuleItemVfModuleInstanceId;
91
92     @Override
93     public String actor() {
94         return SO_ACTOR;
95     }
96
97     @Override
98     public List<String> recipes() {
99         return ImmutableList.copyOf(recipes);
100     }
101
102     @Override
103     public List<String> recipeTargets(String recipe) {
104         return ImmutableList.copyOf(targets.getOrDefault(recipe, Collections.emptyList()));
105     }
106
107     @Override
108     public List<String> recipePayloads(String recipe) {
109         return Collections.emptyList();
110     }
111
112     /**
113      * Constructs a SO request conforming to the lcm API. The actual request is
114      * constructed and then placed in a wrapper object used to send through DMAAP.
115      *
116      * @param onset the event that is reporting the alert for policy to perform an action
117      * @param operation the control loop operation specifying the actor, operation,
118      *        target, etc.
119      * @param policy the policy the was specified from the yaml generated by CLAMP or
120      *        through the Policy GUI/API
121      * @param aaiResponseWrapper wrapper for AAI vserver named-query response
122      * @return a SO request conforming to the lcm API using the DMAAP wrapper
123      */
124     public SoRequest constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, Policy policy,
125                     AaiNqResponseWrapper aaiResponseWrapper) {
126         if (!SO_ACTOR.equals(policy.getActor()) || !recipes().contains(policy.getRecipe())) {
127             return null;
128         }
129
130         // A&AI named query should have been performed by now. If not, return null
131         if (aaiResponseWrapper == null) {
132             return null;
133         }
134
135         AaiNqInventoryResponseItem vnfItem;
136         AaiNqInventoryResponseItem vnfServiceItem;
137         AaiNqInventoryResponseItem tenantItem;
138
139         // Extract the items we're interested in from the response
140         try {
141             vnfItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
142                             .getInventoryResponseItems().get(0);
143         } catch (Exception e) {
144             logger.error("VNF Item not found in AAI response {}", Serialization.gsonPretty.toJson(aaiResponseWrapper),
145                             e);
146             return null;
147         }
148
149         try {
150             vnfServiceItem = vnfItem.getItems().getInventoryResponseItems().get(0);
151         } catch (Exception e) {
152             logger.error("VNF Service Item not found in AAI response {}",
153                             Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
154             return null;
155         }
156
157         try {
158             tenantItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
159                             .getInventoryResponseItems().get(1);
160         } catch (Exception e) {
161             logger.error("Tenant Item not found in AAI response {}",
162                             Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
163             return null;
164         }
165
166         // Find the index for base vf module and non-base vf module
167         AaiNqInventoryResponseItem baseItem = findVfModule(aaiResponseWrapper, true);
168         AaiNqInventoryResponseItem vfModuleItem = findVfModule(aaiResponseWrapper, false);
169
170         // Report the error if either base vf module or non-base vf module is not found
171         if (baseItem == null || vfModuleItem == null) {
172             logger.error("Either base or non-base vf module is not found from AAI response.");
173             return null;
174         }
175
176         // Construct SO Request for a policy's recipe
177         if (RECIPE_VF_MODULE_CREATE.equals(policy.getRecipe())) {
178             return constructCreateRequest(aaiResponseWrapper, policy, tenantItem, vnfItem, vnfServiceItem,
179                     vfModuleItem);
180         } else if (RECIPE_VF_MODULE_DELETE.equals(policy.getRecipe())) {
181             return constructDeleteRequest(tenantItem, vnfItem, vnfServiceItem, vfModuleItem);
182         } else {
183             return null;
184         }
185     }
186
187     /**
188      * Construct SO request to create vf-module.
189      *
190      * @param aaiResponseWrapper the AAI response containing the VF modules
191      * @param policy             the policy
192      * @param tenantItem         tenant item from A&AI named-query response
193      * @param vnfItem            vnf item from A&AI named-query response
194      * @param vnfServiceItem     vnf service item from A&AI named-query response
195      * @param vfModuleItem       vf module item from A&AI named-query response
196      * @return SO create vf-module request
197      */
198     private SoRequest constructCreateRequest(AaiNqResponseWrapper aaiResponseWrapper, Policy policy,
199                                              AaiNqInventoryResponseItem tenantItem, AaiNqInventoryResponseItem vnfItem,
200                                              AaiNqInventoryResponseItem vnfServiceItem,
201                                              AaiNqInventoryResponseItem vfModuleItem) {
202         SoRequest request = new SoRequest();
203         request.setOperationType(SoOperationType.SCALE_OUT);
204         //
205         //
206         // Do NOT send So the requestId, they do not support this field
207         //
208         request.setRequestDetails(new SoRequestDetails());
209         request.getRequestDetails().setRequestParameters(new SoRequestParameters());
210         request.getRequestDetails().getRequestParameters().setUserParams(null);
211
212         // cloudConfiguration
213         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
214         // modelInfo
215         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
216         request.getRequestDetails().getModelInfo().setModelVersionId(vfModuleItem.getVfModule().getModelVersionId());
217
218         // requestInfo
219         request.getRequestDetails().setRequestInfo(constructRequestInfo());
220         String vfModuleName = aaiResponseWrapper.genVfModuleName();
221         request.getRequestDetails().getRequestInfo().setInstanceName(vfModuleName);
222
223         // relatedInstanceList
224         SoRelatedInstanceListElement relatedInstanceListElement1 = new SoRelatedInstanceListElement();
225         SoRelatedInstanceListElement relatedInstanceListElement2 = new SoRelatedInstanceListElement();
226         relatedInstanceListElement1.setRelatedInstance(new SoRelatedInstance());
227         relatedInstanceListElement2.setRelatedInstance(new SoRelatedInstance());
228
229         // Service Item
230         relatedInstanceListElement1.getRelatedInstance()
231                 .setInstanceId(vnfServiceItem.getServiceInstance().getServiceInstanceId());
232         relatedInstanceListElement1.getRelatedInstance().setModelInfo(new SoModelInfo());
233         relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelType("service");
234         relatedInstanceListElement1.getRelatedInstance().getModelInfo()
235                 .setModelInvariantId(vnfServiceItem.getServiceInstance().getModelInvariantId());
236         for (AaiNqExtraProperty prop : vnfServiceItem.getExtraProperties().getExtraProperty()) {
237             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
238                 relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
239             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
240                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
241                         .setModelVersion(prop.getPropertyValue());
242             } else if (prop.getPropertyName().equals(MODEL_VERSION_ID_PROPERTY_KEY)) {
243                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
244                         .setModelVersionId(prop.getPropertyValue());
245             }
246         }
247
248         // VNF Item
249         relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getGenericVnf().getVnfId());
250         relatedInstanceListElement2.getRelatedInstance().setModelInfo(new SoModelInfo());
251         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelType("vnf");
252         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
253                 .setModelInvariantId(vnfItem.getGenericVnf().getModelInvariantId());
254         for (AaiNqExtraProperty prop : vnfItem.getExtraProperties().getExtraProperty()) {
255             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
256                 relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
257             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
258                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
259                         .setModelVersion(prop.getPropertyValue());
260             } else if (prop.getPropertyName().equals(MODEL_VERSION_ID_PROPERTY_KEY)) {
261                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
262                         .setModelVersionId(prop.getPropertyValue());
263             }
264         }
265         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
266                 .setModelCustomizationName(vnfItem.getGenericVnf().getVnfType()
267                         .substring(vnfItem.getGenericVnf().getVnfType().lastIndexOf('/') + 1));
268         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
269                 .setModelCustomizationId(vnfItem.getGenericVnf().getModelCustomizationId());
270
271         // Insert the Service Item and VNF Item
272         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1);
273         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2);
274
275         // Request Parameters
276         buildRequestParameters(policy, request.getRequestDetails());
277
278         // Configuration Parameters
279         buildConfigurationParameters(policy, request.getRequestDetails());
280         // Save the instance IDs for the VNF and service to static fields
281         // vfModuleId is not required for the create vf-module
282         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
283                 .getServiceInstanceId(), null);
284         if (logger.isDebugEnabled()) {
285             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
286         }
287         return request;
288     }
289
290     /**
291      * Construct SO request to delete vf-module.
292      *
293      * @param tenantItem         tenant item from A&AI named-query response
294      * @param vnfItem            vnf item from A&AI named-query response
295      * @param vnfServiceItem     vnf service item from A&AI named-query response
296      * @param vfModuleItem       vf module item from A&AI named-query response
297      * @return SO delete vf-module request
298      */
299     private SoRequest constructDeleteRequest(AaiNqInventoryResponseItem tenantItem, AaiNqInventoryResponseItem
300             vnfItem, AaiNqInventoryResponseItem vnfServiceItem, AaiNqInventoryResponseItem vfModuleItem) {
301         SoRequest request = new SoRequest();
302         request.setOperationType(SoOperationType.DELETE_VF_MODULE);
303         request.setRequestDetails(new SoRequestDetails());
304         request.getRequestDetails().setRelatedInstanceList(null);
305         request.getRequestDetails().setConfigurationParameters(null);
306
307         // cloudConfiguration
308         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
309         // modelInfo
310         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
311         // requestInfo
312         request.getRequestDetails().setRequestInfo(constructRequestInfo());
313         // Save the instance IDs for the VNF, service and vfModule to static fields
314         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
315                 .getServiceInstanceId(), vfModuleItem.getVfModule().getVfModuleId());
316
317         if (logger.isDebugEnabled()) {
318             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
319         }
320         return request;
321     }
322
323     /**
324      * Construct requestInfo for the SO requestDetails.
325      *
326      * @return SO request information
327      */
328     private SoRequestInfo constructRequestInfo() {
329         SoRequestInfo soRequestInfo = new SoRequestInfo();
330         soRequestInfo.setSource("POLICY");
331         soRequestInfo.setSuppressRollback(false);
332         soRequestInfo.setRequestorId("policy");
333         return soRequestInfo;
334     }
335
336     /**
337      * Construct modelInfo of the vfModule for the SO requestDetails.
338      *
339      * @param vfModuleItem vf module item from A&AI named-query response
340      * @return SO Model info for the vfModule
341      */
342     private SoModelInfo constructVfModuleModelInfo(AaiNqInventoryResponseItem vfModuleItem) {
343         SoModelInfo soModelInfo = new SoModelInfo();
344         soModelInfo.setModelType("vfModule");
345         soModelInfo.setModelInvariantId(vfModuleItem.getVfModule().getModelInvariantId());
346         soModelInfo.setModelCustomizationId(vfModuleItem.getVfModule().getModelCustomizationId());
347
348         for (AaiNqExtraProperty prop : vfModuleItem.getExtraProperties().getExtraProperty()) {
349             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
350                 soModelInfo.setModelName(prop.getPropertyValue());
351             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
352                 soModelInfo.setModelVersion(prop.getPropertyValue());
353             }
354         }
355         return soModelInfo;
356     }
357
358     /**
359      * Construct cloudConfiguration for the SO requestDetails.
360      *
361      * @param tenantItem tenant item from A&AI named-query response
362      * @return SO cloud configuration
363      */
364     private SoCloudConfiguration constructCloudConfiguration(AaiNqInventoryResponseItem tenantItem) {
365         SoCloudConfiguration cloudConfiguration = new SoCloudConfiguration();
366         cloudConfiguration.setTenantId(tenantItem.getTenant().getTenantId());
367         cloudConfiguration.setLcpCloudRegionId(tenantItem.getItems().getInventoryResponseItems().get(0)
368                 .getCloudRegion().getCloudRegionId());
369         return cloudConfiguration;
370     }
371
372     /**
373      * This method is needed to get the serviceInstanceId and vnfInstanceId which is used
374      * in the asyncSORestCall.
375      *
376      * @param requestId the request Id
377      * @param wm the working memory
378      * @param request the request
379      */
380     public static void sendRequest(String requestId, WorkingMemory wm, Object request) {
381         SoManager soManager = new SoManager();
382         soManager.asyncSoRestCall(requestId, wm, lastServiceItemServiceInstanceId, lastVNFItemVnfId,
383                 lastVfModuleItemVfModuleInstanceId, (SoRequest) request);
384     }
385
386     /**
387      * Find the base or non base VF module item in an AAI response.
388      * If there is more than one item, then the <i>last</i> item is returned
389      *
390      * @param aaiResponseWrapper the AAI response containing the VF modules
391      * @param baseFlag true if we are searching for the base, false if we are searching
392      *        for the non base
393      * @return the base or non base VF module item or null if the module was not found
394      */
395     private AaiNqInventoryResponseItem findVfModule(AaiNqResponseWrapper aaiResponseWrapper, boolean baseFlag) {
396         List<AaiNqInventoryResponseItem> lst = aaiResponseWrapper.getVfModuleItems(baseFlag);
397         return (lst.isEmpty() ? null : lst.get(lst.size() - 1));
398     }
399
400     /**
401      * Builds the request parameters from the policy payload.
402      *
403      * @param policy the policy
404      * @param request request into which to stick the request parameters
405      */
406     private void buildRequestParameters(Policy policy, SoRequestDetails request) {
407         // assume null until proven otherwise
408         request.setRequestParameters(null);
409         
410         if (policy.getPayload() == null) {
411             return;
412         }
413
414         String json = policy.getPayload().get(REQ_PARAM_NM);
415         if (json == null) {
416             return;
417         }
418
419         request.setRequestParameters(Serialization.gsonPretty.fromJson(json, SoRequestParameters.class));
420     }
421
422     /**
423      * Builds the configuration parameters from the policy payload.
424      *
425      * @param policy the policy
426      * @param request request into which to stick the configuration parameters
427      */
428     private void buildConfigurationParameters(Policy policy, SoRequestDetails request) {
429         // assume null until proven otherwise
430         request.setConfigurationParameters(null);
431         
432         if (policy.getPayload() == null) {
433             return;
434         }
435
436         String json = policy.getPayload().get(CONFIG_PARAM_NM);
437         if (json == null) {
438             return;
439         }
440
441         request.setConfigurationParameters(Serialization.gsonPretty.fromJson(json, CONFIG_TYPE));
442     }
443
444     /**
445      * This method is called to remember the last service instance ID, VNF Item VNF ID and vf module ID.
446      * Note these fields are static, beware for multithreaded deployments
447      *
448      * @param vnfInstanceId update the last VNF instance ID to this value
449      * @param serviceInstanceId update the last service instance ID to this value
450      * @param vfModuleId update the vfModule instance ID to this value
451      */
452     private static void preserveInstanceIds(final String vnfInstanceId, final String serviceInstanceId,
453                                             final String vfModuleId) {
454         lastVNFItemVnfId = vnfInstanceId;
455         lastServiceItemServiceInstanceId = serviceInstanceId;
456         lastVfModuleItemVfModuleInstanceId = vfModuleId;
457     }
458 }