ce49dda4607613d13a3fcb4817db7973ffebe484
[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         } else if (RECIPE_VF_MODULE_DELETE.equals(policy.getRecipe())) {
171             return constructDeleteRequest(aaiResponseWrapper, tenantItem, vnfItem, vnfServiceItem);
172         } else {
173             return null;
174         }
175     }
176
177     /**
178      * Construct SO request to create vf-module
179      *
180      * @param aaiResponseWrapper the AAI response containing the VF modules
181      * @param policy             the policy
182      * @param tenantItem         tenant item from A&AI named-query response
183      * @param vnfItem            vnf item from A&AI named-query response
184      * @param vnfServiceItem     vnf service item from A&AI named-query response
185      * @return SO create vf-module request
186      */
187     private SORequest constructCreateRequest(AaiNqResponseWrapper aaiResponseWrapper, Policy policy, AaiNqInventoryResponseItem
188             tenantItem, AaiNqInventoryResponseItem vnfItem, AaiNqInventoryResponseItem vnfServiceItem) {
189         AaiNqInventoryResponseItem vfModuleItem = findVfModule(aaiResponseWrapper, false);
190         SORequest request = new SORequest();
191         request.setOperationType(SoOperationType.SCALE_OUT);
192         //
193         //
194         // Do NOT send So the requestId, they do not support this field
195         //
196         request.setRequestDetails(new SORequestDetails());
197         request.getRequestDetails().setRequestParameters(new SORequestParameters());
198         request.getRequestDetails().getRequestParameters().setUserParams(null);
199
200         // cloudConfiguration
201         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
202         // modelInfo
203         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
204         request.getRequestDetails().getModelInfo().setModelVersionId(vfModuleItem.getVfModule().getModelVersionId());
205
206         // requestInfo
207         request.getRequestDetails().setRequestInfo(constructRequestInfo());
208         String vfModuleName = aaiResponseWrapper.genVfModuleName();
209         request.getRequestDetails().getRequestInfo().setInstanceName(vfModuleName);
210
211         // relatedInstanceList
212         SORelatedInstanceListElement relatedInstanceListElement0 = new SORelatedInstanceListElement();
213         SORelatedInstanceListElement relatedInstanceListElement1 = new SORelatedInstanceListElement();
214         SORelatedInstanceListElement relatedInstanceListElement2 = new SORelatedInstanceListElement();
215         relatedInstanceListElement1.setRelatedInstance(new SORelatedInstance());
216         relatedInstanceListElement2.setRelatedInstance(new SORelatedInstance());
217
218         // Volume Group Item
219         relatedInstanceListElement0.setRelatedInstance(new SORelatedInstance());
220         relatedInstanceListElement0.getRelatedInstance().setInstanceId(UUID.randomUUID().toString());
221         relatedInstanceListElement0.getRelatedInstance().setInstanceName(vfModuleName + "_vol");
222         relatedInstanceListElement0.getRelatedInstance().setModelInfo(new SOModelInfo());
223         relatedInstanceListElement0.getRelatedInstance().getModelInfo().setModelType("volumeGroup");
224
225         // Service Item
226         relatedInstanceListElement1.getRelatedInstance()
227                 .setInstanceId(vnfServiceItem.getServiceInstance().getServiceInstanceId());
228         relatedInstanceListElement1.getRelatedInstance().setModelInfo(new SOModelInfo());
229         relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelType("service");
230         relatedInstanceListElement1.getRelatedInstance().getModelInfo()
231                 .setModelInvariantId(vnfServiceItem.getServiceInstance().getModelInvariantId());
232         for (AaiNqExtraProperty prop : vnfServiceItem.getExtraProperties().getExtraProperty()) {
233             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
234                 relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
235             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
236                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
237                         .setModelVersion(prop.getPropertyValue());
238             } else if (prop.getPropertyName().equals(MODEL_VERSION_ID_PROPERTY_KEY)) {
239                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
240                         .setModelVersionId(prop.getPropertyValue());
241             }
242         }
243
244         // VNF Item
245         relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getGenericVnf().getVnfId());
246         relatedInstanceListElement2.getRelatedInstance().setModelInfo(new SOModelInfo());
247         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelType("vnf");
248         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
249                 .setModelInvariantId(vnfItem.getGenericVnf().getModelInvariantId());
250         for (AaiNqExtraProperty prop : vnfItem.getExtraProperties().getExtraProperty()) {
251             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
252                 relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
253             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
254                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
255                         .setModelVersion(prop.getPropertyValue());
256             } else if (prop.getPropertyName().equals(MODEL_VERSION_ID_PROPERTY_KEY)) {
257                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
258                         .setModelVersionId(prop.getPropertyValue());
259             }
260         }
261         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
262                 .setModelCustomizationName(vnfItem.getGenericVnf().getVnfType()
263                         .substring(vnfItem.getGenericVnf().getVnfType().lastIndexOf('/') + 1));
264         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
265                 .setModelCustomizationId(vnfItem.getGenericVnf().getModelCustomizationId());
266
267         // Insert the Service Item and VNF Item
268         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement0);
269         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1);
270         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2);
271
272         // Request Parameters
273         request.getRequestDetails().setRequestParameters(buildRequestParameters(policy));
274
275         // Configuration Parameters
276         request.getRequestDetails().setConfigurationParameters(buildConfigurationParameters(policy));
277         // Save the instance IDs for the VNF and service to static fields
278         // vfModuleId is not required for the create vf-module
279         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
280                 .getServiceInstanceId(), null);
281         if (logger.isDebugEnabled()) {
282             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
283         }
284         return request;
285     }
286
287     /**
288      * Construct SO request to delete vf-module
289      *
290      * @param aaiResponseWrapper the AAI response containing the VF modules
291      * @param tenantItem         tenant item from A&AI named-query response
292      * @param vnfItem            vnf item from A&AI named-query response
293      * @param vnfServiceItem     vnf service item from A&AI named-query response
294      * @return SO delete vf-module request
295      */
296     private SORequest constructDeleteRequest(AaiNqResponseWrapper aaiResponseWrapper, AaiNqInventoryResponseItem
297             tenantItem, AaiNqInventoryResponseItem vnfItem, AaiNqInventoryResponseItem vnfServiceItem) {
298         // find the last non-base vf-module to delete
299         AaiNqInventoryResponseItem vfModuleItem = findVfModuleToDelete(aaiResponseWrapper);
300
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      *
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 == null || lst.isEmpty() ? null : lst.get(0));
397     }
398
399     /**
400      * Find the VF module item to delete from AAI response.
401      *
402      * @param aaiResponseWrapper the AAI response containing the VF modules
403      * @return VF module item to delete or null if the non-base vfModule was not found
404      */
405     private AaiNqInventoryResponseItem findVfModuleToDelete(AaiNqResponseWrapper aaiResponseWrapper) {
406         List<AaiNqInventoryResponseItem> lst = aaiResponseWrapper.getVfModuleItems(false);
407         return (lst == null || lst.isEmpty() ? null : lst.get(lst.size() - 1));
408     }
409
410
411     /**
412      * Builds the request parameters from the policy payload.
413      *
414      * @param policy the policy
415      * @return the request parameters, or {@code null} if the payload is {@code null}
416      */
417     private SORequestParameters buildRequestParameters(Policy policy) {
418         if (policy.getPayload() == null) {
419             return null;
420         }
421
422         String json = policy.getPayload().get(REQ_PARAM_NM);
423         if (json == null) {
424             return null;
425         }
426
427         return Serialization.gsonPretty.fromJson(json, SORequestParameters.class);
428     }
429
430     /**
431      * Builds the configuration parameters from the policy payload.
432      *
433      * @param policy the policy
434      * @return the configuration parameters, or {@code null} if the payload is
435      *         {@code null}
436      */
437     private List<Map<String, String>> buildConfigurationParameters(Policy policy) {
438         if (policy.getPayload() == null) {
439             return null;
440         }
441
442         String json = policy.getPayload().get(CONFIG_PARAM_NM);
443         if (json == null) {
444             return null;
445         }
446
447         return Serialization.gsonPretty.fromJson(json, CONFIG_TYPE);
448     }
449
450     /**
451      * This method is called to remember the last service instance ID, VNF Item VNF ID and vf module ID.
452      * Note these fields are static, beware for multithreaded deployments
453      *
454      * @param vnfInstanceId update the last VNF instance ID to this value
455      * @param serviceInstanceId update the last service instance ID to this value
456      * @param vfModuleId update the vfModule instance ID to this value
457      */
458     private static void preserveInstanceIds(final String vnfInstanceId, final String serviceInstanceId, final String vfModuleId) {
459         lastVNFItemVnfId = vnfInstanceId;
460         lastServiceItemServiceInstanceId = serviceInstanceId;
461         lastVfModuleItemVfModuleInstanceId = vfModuleId;
462     }
463 }