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