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