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