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