49b4e9885cd4b21388d25ff70681b91ef262c9bd
[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 java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.UUID;
28 import org.drools.core.WorkingMemory;
29 import org.onap.policy.aai.AaiManager;
30 import org.onap.policy.aai.AaiNqExtraProperty;
31 import org.onap.policy.aai.AaiNqInstanceFilters;
32 import org.onap.policy.aai.AaiNqInventoryResponseItem;
33 import org.onap.policy.aai.AaiNqNamedQuery;
34 import org.onap.policy.aai.AaiNqQueryParameters;
35 import org.onap.policy.aai.AaiNqRequest;
36 import org.onap.policy.aai.AaiNqResponse;
37 import org.onap.policy.aai.AaiNqResponseWrapper;
38 import org.onap.policy.controlloop.ControlLoopOperation;
39 import org.onap.policy.controlloop.VirtualControlLoopEvent;
40 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
41 import org.onap.policy.controlloop.policy.Policy;
42 import org.onap.policy.drools.system.PolicyEngine;
43 import org.onap.policy.rest.RESTManager;
44 import org.onap.policy.so.SOCloudConfiguration;
45 import org.onap.policy.so.SOManager;
46 import org.onap.policy.so.SOModelInfo;
47 import org.onap.policy.so.SORelatedInstance;
48 import org.onap.policy.so.SORelatedInstanceListElement;
49 import org.onap.policy.so.SORequest;
50 import org.onap.policy.so.SORequestDetails;
51 import org.onap.policy.so.SORequestInfo;
52 import org.onap.policy.so.SORequestParameters;
53 import org.onap.policy.so.util.Serialization;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56 import com.google.common.collect.ImmutableList;
57 import com.google.common.collect.ImmutableMap;
58
59 public class SOActorServiceProvider implements Actor {
60     private static final Logger logger = LoggerFactory.getLogger(SOActorServiceProvider.class);
61
62     // Strings for SO Actor
63     private static final String SO_ACTOR = "SO";
64
65     // Strings for targets
66     private static final String TARGET_VFC = "VFC";
67
68     // Strings for recipes
69     private static final String RECIPE_VF_MODULE_CREATE = "VF Module Create";
70
71     private static final ImmutableList<String> recipes = ImmutableList.of(RECIPE_VF_MODULE_CREATE);
72     private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>()
73             .put(RECIPE_VF_MODULE_CREATE, ImmutableList.of(TARGET_VFC)).build();
74
75     // Static variables required to hold the IDs of the last service item and VNF item. Note that in
76     // a multithreaded deployment this WILL break
77     private static String lastVNFItemVnfId;
78     private static String lastServiceItemServiceInstanceId;
79
80     @Override
81     public String actor() {
82         return SO_ACTOR;
83     }
84
85     @Override
86     public List<String> recipes() {
87         return ImmutableList.copyOf(recipes);
88     }
89
90     @Override
91     public List<String> recipeTargets(String recipe) {
92         return ImmutableList.copyOf(targets.getOrDefault(recipe, Collections.emptyList()));
93     }
94
95     @Override
96     public List<String> recipePayloads(String recipe) {
97         return Collections.emptyList();
98     }
99
100     /**
101      * Constructs a SO request conforming to the lcm API. The actual request is constructed and then
102      * placed in a wrapper object used to send through DMAAP.
103      * 
104      * @param onset the event that is reporting the alert for policy to perform an action
105      * @param operation the control loop operation specifying the actor, operation, target, etc.
106      * @param policy the policy the was specified from the yaml generated by CLAMP or through the
107      *        Policy GUI/API
108      * @return a SO request conforming to the lcm API using the DMAAP wrapper
109      */
110     public SORequest constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, Policy policy) {
111         String modelNamePropertyKey = "model-ver.model-name";
112         String modelVersionPropertyKey = "model-ver.model-version";
113         String modelVersionIdPropertyKey = "model-ver.model-version-id";
114
115
116         if (!SO_ACTOR.equals(policy.getActor()) || !RECIPE_VF_MODULE_CREATE.equals(policy.getRecipe())) {
117             // for future extension
118             return null;
119         }
120
121         // Perform named query request and handle response
122         AaiNqResponseWrapper aaiResponseWrapper = performAaiNamedQueryRequest(onset);
123         if (aaiResponseWrapper == null) {
124             // Tracing and error handling handied in the "performAaiNamedQueryRequest()" method
125             return null;
126         }
127
128         AaiNqInventoryResponseItem vnfItem;
129         AaiNqInventoryResponseItem vnfServiceItem;
130         AaiNqInventoryResponseItem tenantItem;
131
132         // Extract the items we're interested in from the response
133         try {
134             vnfItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
135                     .getInventoryResponseItems().get(0);
136         } catch (Exception e) {
137             logger.error("VNF Item not found in AAI response {}", Serialization.gsonPretty.toJson(aaiResponseWrapper),
138                     e);
139             return null;
140         }
141
142         try {
143             vnfServiceItem = vnfItem.getItems().getInventoryResponseItems().get(0);
144         } catch (Exception e) {
145             logger.error("VNF Service Item not found in AAI response {}",
146                     Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
147             return null;
148         }
149
150         try {
151             tenantItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
152                     .getInventoryResponseItems().get(1);
153         } catch (Exception e) {
154             logger.error("Tenant Item not found in AAI response {}",
155                     Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
156             return null;
157         }
158
159         // Find the index for base vf module and non-base vf module
160         int baseIndex = findIndex(vnfItem.getItems().getInventoryResponseItems(), true);
161         int nonBaseIndex = findIndex(vnfItem.getItems().getInventoryResponseItems(), false);
162
163         // Report the error if either base vf module or non-base vf module is not found
164         if (baseIndex == -1 || nonBaseIndex == -1) {
165             logger.error("Either base or non-base vf module is not found from AAI response.");
166             return null;
167         }
168
169
170         // Construct SO Request
171         SORequest request = new SORequest();
172         //
173         // Do NOT send So the requestId, they do not support this field
174         //
175         request.setRequestDetails(new SORequestDetails());
176         request.getRequestDetails().setModelInfo(new SOModelInfo());
177         request.getRequestDetails().setCloudConfiguration(new SOCloudConfiguration());
178         request.getRequestDetails().setRequestInfo(new SORequestInfo());
179         request.getRequestDetails().setRequestParameters(new SORequestParameters());
180         request.getRequestDetails().getRequestParameters().setUserParams(null);
181
182         //
183         // cloudConfiguration
184         //
185         request.getRequestDetails().getCloudConfiguration().setTenantId(tenantItem.getTenant().getTenantId());
186         request.getRequestDetails().getCloudConfiguration().setLcpCloudRegionId(
187                 tenantItem.getItems().getInventoryResponseItems().get(0).getCloudRegion().getCloudRegionId());
188
189         //
190         // modelInfo
191         //
192         AaiNqInventoryResponseItem vfModuleItem = vnfItem.getItems().getInventoryResponseItems().get(nonBaseIndex);
193
194         request.getRequestDetails().getModelInfo().setModelType("vfModule");
195         request.getRequestDetails().getModelInfo()
196                 .setModelInvariantId(vfModuleItem.getVfModule().getModelInvariantId());
197         request.getRequestDetails().getModelInfo().setModelVersionId(vfModuleItem.getVfModule().getModelVersionId());
198
199         for (AaiNqExtraProperty prop : vfModuleItem.getExtraProperties().getExtraProperty()) {
200             if (prop.getPropertyName().equals(modelNamePropertyKey)) {
201                 request.getRequestDetails().getModelInfo().setModelName(prop.getPropertyValue());
202             } else if (prop.getPropertyName().equals(modelVersionPropertyKey)) {
203                 request.getRequestDetails().getModelInfo().setModelVersion(prop.getPropertyValue());
204             }
205         }
206
207         //
208         // requestInfo
209         //
210         request.getRequestDetails().getRequestInfo().setInstanceName(vnfItem.getItems().getInventoryResponseItems()
211             .get(baseIndex).getVfModule().getVfModuleName().replace("Vfmodule", "vDNS"));
212         request.getRequestDetails().getRequestInfo().setSource("POLICY");
213         request.getRequestDetails().getRequestInfo().setSuppressRollback(false);
214         request.getRequestDetails().getRequestInfo().setRequestorId("policy");
215
216         //
217         // relatedInstanceList
218         //
219         SORelatedInstanceListElement relatedInstanceListElement1 = new SORelatedInstanceListElement();
220         SORelatedInstanceListElement relatedInstanceListElement2 = new SORelatedInstanceListElement();
221         relatedInstanceListElement1.setRelatedInstance(new SORelatedInstance());
222         relatedInstanceListElement2.setRelatedInstance(new SORelatedInstance());
223
224         // Service Item
225         relatedInstanceListElement1.getRelatedInstance()
226                 .setInstanceId(vnfServiceItem.getServiceInstance().getServiceInstanceId());
227         relatedInstanceListElement1.getRelatedInstance().setModelInfo(new SOModelInfo());
228         relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelType("service");
229         relatedInstanceListElement1.getRelatedInstance().getModelInfo()
230                 .setModelInvariantId(vnfServiceItem.getServiceInstance().getModelInvariantId());
231         for (AaiNqExtraProperty prop : vnfServiceItem.getExtraProperties().getExtraProperty()) {
232             if (prop.getPropertyName().equals(modelNamePropertyKey)) {
233                 relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
234             } else if (prop.getPropertyName().equals(modelVersionPropertyKey)) {
235                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
236                         .setModelVersion(prop.getPropertyValue());
237             } else if (prop.getPropertyName().equals(modelVersionIdPropertyKey)) {
238               relatedInstanceListElement1.getRelatedInstance().getModelInfo()
239                       .setModelVersionId(prop.getPropertyValue());
240             }
241         }
242
243         // VNF Item
244         relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getGenericVnf().getVnfId());
245         relatedInstanceListElement2.getRelatedInstance().setModelInfo(new SOModelInfo());
246         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelType("vnf");
247         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
248                 .setModelInvariantId(vnfItem.getGenericVnf().getModelInvariantId());
249         for (AaiNqExtraProperty prop : vnfItem.getExtraProperties().getExtraProperty()) {
250             if (prop.getPropertyName().equals(modelNamePropertyKey)) {
251                 relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
252             } else if (prop.getPropertyName().equals(modelVersionPropertyKey)) {
253                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
254                         .setModelVersion(prop.getPropertyValue());
255             } else if (prop.getPropertyName().equals(modelVersionIdPropertyKey)) {
256                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
257                         .setModelVersionId(prop.getPropertyValue());
258             }
259         }
260         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelCustomizationName(vnfItem
261                 .getGenericVnf().getVnfType().substring(vnfItem.getGenericVnf().getVnfType().lastIndexOf('/') + 1));
262
263         // Insert the Service Item and VNF Item
264         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1);
265         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2);
266
267         // Save the instance IDs for the VNF and service to static fields
268         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(),
269                 vnfServiceItem.getServiceInstance().getServiceInstanceId());
270
271         if (logger.isDebugEnabled()) {
272             logger.debug("SO request sent: {}", Serialization.gsonPretty.toJson(request));
273         }
274
275         return request;
276     }
277
278     /**
279      * This method is needed to get the serviceInstanceId and vnfInstanceId which is used in the
280      * asyncSORestCall.
281      * 
282      * @param requestId the request Id
283      * @param wm the working memory
284      * @param request the request
285      */
286     public static void sendRequest(String requestId, WorkingMemory wm, Object request) {
287         SOManager soManager = new SOManager();
288         soManager.asyncSORestCall(requestId, wm, lastServiceItemServiceInstanceId, lastVNFItemVnfId,
289                 (SORequest) request);
290     }
291
292     /**
293      * Constructs and sends an AAI vserver Named Query.
294      * 
295      * @param onset the virtial control loop event
296      * @returns the response to the AAI Named Query
297      */
298     private AaiNqResponseWrapper performAaiNamedQueryRequest(VirtualControlLoopEvent onset) {
299
300         // create AAI named-query request with UUID started with ""
301         AaiNqRequest aaiNqRequest = new AaiNqRequest();
302         AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
303         AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
304         final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
305
306         // queryParameters
307         // UUID.fromString($params.getAaiNamedQueryUUID()) TO DO: AaiNamedQueryUUID
308         aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
309         aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
310         aaiNqRequest.setQueryParameters(aaiNqQueryParam);
311         //
312         // instanceFilters
313         //
314         Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
315         Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
316         // TO DO: get vserver.vname from dcae onset.AAI.get("vserver.vserver-name")
317         aaiNqInstanceFilterMapItem.put("vserver-name", onset.getAai().get("vserver.vserver-name"));
318         aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
319         aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
320         aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
321
322         if (logger.isDebugEnabled()) {
323             logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
324         }
325
326         AaiNqResponse aaiNqResponse = new AaiManager(new RESTManager()).postQuery(getPeManagerEnvProperty("aai.url"),
327                 getPeManagerEnvProperty("aai.username"), getPeManagerEnvProperty("aai.password"), aaiNqRequest,
328                 onset.getRequestId());
329
330         // Check AAI response
331         if (aaiNqResponse == null) {
332             logger.warn("No response received from AAI for request {}", aaiNqRequest);
333             return null;
334         }
335
336         // Create AAINQResponseWrapper
337         AaiNqResponseWrapper aaiNqResponseWrapper = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
338
339         if (logger.isDebugEnabled()) {
340             logger.debug("AAI Named Query Response: ");
341             logger.debug(Serialization.gsonPretty.toJson(aaiNqResponseWrapper.getAaiNqResponse()));
342         }
343
344         return aaiNqResponseWrapper;
345     }
346
347     /**
348      * Find the base index or non base index in a list of inventory response items.
349      * 
350      * @param inventoryResponseItems the list of inventory response items
351      * @param baseIndexFlag true if we are searching for the base index, false if we are searching
352      *        for the non base index
353      * @return the base or non base index or -1 if the index was not found
354      */
355     private int findIndex(List<AaiNqInventoryResponseItem> inventoryResponseItems, boolean baseIndexFlag) {
356         for (AaiNqInventoryResponseItem invenoryResponseItem : inventoryResponseItems) {
357             if (invenoryResponseItem.getVfModule() != null
358                     && baseIndexFlag == invenoryResponseItem.getVfModule().getIsBaseVfModule()) {
359                 return inventoryResponseItems.indexOf(invenoryResponseItem);
360             }
361         }
362
363         return -1;
364     }
365
366     /**
367      * Find the number of non base modules present in API response object.
368      * 
369      * @param inventoryResponseItems the list of inventory response items
370      * @return number of non base index modules
371      */
372
373     @SuppressWarnings("unused")
374     private int findNonBaseModules(List<AaiNqInventoryResponseItem> inventoryResponseItems) {
375         int nonBaseModuleCount = 0;
376         for (AaiNqInventoryResponseItem invenoryResponseItem : inventoryResponseItems) {
377             if (invenoryResponseItem.getVfModule() != null
378                     && (!invenoryResponseItem.getVfModule().getIsBaseVfModule())) {
379                 nonBaseModuleCount++;
380             }
381         }
382         return nonBaseModuleCount;
383     }
384
385     /**
386      * This method is called to remember the last service instance ID and VNF Item VNF ID. Note
387      * these fields are static, beware for multithreaded deployments
388      * 
389      * @param vnfInstanceId update the last VNF instance ID to this value
390      * @param serviceInstanceId update the last service instance ID to this value
391      */
392     private static void preserveInstanceIds(final String vnfInstanceId, final String serviceInstanceId) {
393         lastVNFItemVnfId = vnfInstanceId;
394         lastServiceItemServiceInstanceId = serviceInstanceId;
395     }
396
397     /**
398      * This method reads and validates environmental properties coming from the policy engine. Null
399      * properties cause an {@link IllegalArgumentException} runtime exception to be thrown
400      * 
401      * @param string the name of the parameter to retrieve
402      * @return the property value
403      */
404     private static String getPeManagerEnvProperty(String enginePropertyName) {
405         String enginePropertyValue = PolicyEngine.manager.getEnvironmentProperty(enginePropertyName);
406         if (enginePropertyValue == null) {
407             throw new IllegalArgumentException("The value of policy engine manager environment property \""
408                     + enginePropertyName + "\" may not be null");
409         }
410         return enginePropertyValue;
411     }
412 }