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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.controlloop.actor.so;
 
  23 import com.google.common.collect.ImmutableList;
 
  24 import com.google.common.collect.ImmutableMap;
 
  26 import java.util.Collections;
 
  27 import java.util.HashMap;
 
  28 import java.util.List;
 
  30 import java.util.UUID;
 
  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;
 
  61 public class SOActorServiceProvider implements Actor {
 
  62     private static final Logger logger = LoggerFactory.getLogger(SOActorServiceProvider.class);
 
  64     // Strings for SO Actor
 
  65     private static final String SO_ACTOR = "SO";
 
  67     // Strings for targets
 
  68     private static final String TARGET_VFC = "VFC";
 
  70     // Strings for recipes
 
  71     private static final String RECIPE_VF_MODULE_CREATE = "VF Module Create";
 
  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();
 
  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;
 
  83     public String actor() {
 
  88     public List<String> recipes() {
 
  89         return ImmutableList.copyOf(recipes);
 
  93     public List<String> recipeTargets(String recipe) {
 
  94         return ImmutableList.copyOf(targets.getOrDefault(recipe, Collections.emptyList()));
 
  98     public List<String> recipePayloads(String recipe) {
 
  99         return Collections.emptyList();
 
 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.
 
 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
 
 110      * @return a SO request conforming to the lcm API using the DMAAP wrapper
 
 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";
 
 118         if (!SO_ACTOR.equals(policy.getActor()) || !RECIPE_VF_MODULE_CREATE.equals(policy.getRecipe())) {
 
 119             // for future extension
 
 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
 
 130         AaiNqInventoryResponseItem vnfItem;
 
 131         AaiNqInventoryResponseItem vnfServiceItem;
 
 132         AaiNqInventoryResponseItem tenantItem;
 
 134         // Extract the items we're interested in from the response
 
 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),
 
 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);
 
 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);
 
 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);
 
 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.");
 
 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);
 
 183         // cloudConfiguration
 
 185         request.getRequestDetails().getCloudConfiguration().setTenantId(tenantItem.getTenant().getTenantId());
 
 186         request.getRequestDetails().getCloudConfiguration().setLcpCloudRegionId(
 
 187                 tenantItem.getItems().getInventoryResponseItems().get(0).getCloudRegion().getCloudRegionId());
 
 192         AaiNqInventoryResponseItem vfModuleItem = vnfItem.getItems().getInventoryResponseItems().get(nonBaseIndex);
 
 194         request.getRequestDetails().getModelInfo().setModelType("vfModule");
 
 195         request.getRequestDetails().getModelInfo()
 
 196                 .setModelInvariantId(vfModuleItem.getVfModule().getModelInvariantId());
 
 197         request.getRequestDetails().getModelInfo().setModelVersionId(vfModuleItem.getVfModule().getModelVersionId());
 
 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());
 
 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);
 
 223             request.getRequestDetails().getRequestInfo().setInstanceName(vnfItem.getItems().getInventoryResponseItems()
 
 224                     .get(baseIndex).getVfModule().getVfModuleName().replace("Vfmodule", "vDNS"));
 
 226         request.getRequestDetails().getRequestInfo().setSource("POLICY");
 
 227         request.getRequestDetails().getRequestInfo().setSuppressRollback(false);
 
 228         request.getRequestDetails().getRequestInfo().setRequestorId("policy");
 
 231         // relatedInstanceList
 
 233         SORelatedInstanceListElement relatedInstanceListElement1 = new SORelatedInstanceListElement();
 
 234         SORelatedInstanceListElement relatedInstanceListElement2 = new SORelatedInstanceListElement();
 
 235         relatedInstanceListElement1.setRelatedInstance(new SORelatedInstance());
 
 236         relatedInstanceListElement2.setRelatedInstance(new SORelatedInstance());
 
 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());
 
 255         relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getGenericVnf().getVnfId());
 
 256         relatedInstanceListElement2.getRelatedInstance().setModelInfo(new SOModelInfo());
 
 257         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelType("vnf");
 
 258         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 259                 .setModelInvariantId(vnfItem.getGenericVnf().getModelInvariantId());
 
 260         for (AaiNqExtraProperty prop : vnfItem.getExtraProperties().getExtraProperty()) {
 
 261             if (prop.getPropertyName().equals(modelNamePropertyKey)) {
 
 262                 relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
 
 263             } else if (prop.getPropertyName().equals(modelVersionPropertyKey)) {
 
 264                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 265                         .setModelVersion(prop.getPropertyValue());
 
 266             } else if (prop.getPropertyName().equals(modelVersionIdPropertyKey)) {
 
 267                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 268                         .setModelVersionId(prop.getPropertyValue());
 
 271         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelCustomizationName(vnfItem
 
 272                 .getGenericVnf().getVnfType().substring(vnfItem.getGenericVnf().getVnfType().lastIndexOf('/') + 1));
 
 274         // Insert the Service Item and VNF Item
 
 275         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1);
 
 276         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2);
 
 278         // Save the instance IDs for the VNF and service to static fields
 
 279         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(),
 
 280                 vnfServiceItem.getServiceInstance().getServiceInstanceId());
 
 282         if (logger.isDebugEnabled()) {
 
 283             logger.debug("SO request sent: {}", Serialization.gsonPretty.toJson(request));
 
 290      * This method is needed to get the serviceInstanceId and vnfInstanceId which is used in the
 
 293      * @param requestId the request Id
 
 294      * @param wm the working memory
 
 295      * @param request the request
 
 297     public static void sendRequest(String requestId, WorkingMemory wm, Object request) {
 
 298         SOManager soManager = new SOManager();
 
 299         soManager.asyncSORestCall(requestId, wm, lastServiceItemServiceInstanceId, lastVNFItemVnfId,
 
 300                 (SORequest) request);
 
 304      * Constructs and sends an AAI vserver Named Query.
 
 306      * @param onset the virtial control loop event
 
 307      * @returns the response to the AAI Named Query
 
 309     private AaiNqResponseWrapper performAaiNamedQueryRequest(VirtualControlLoopEvent onset) {
 
 311         // create AAI named-query request with UUID started with ""
 
 312         AaiNqRequest aaiNqRequest = new AaiNqRequest();
 
 313         AaiNqQueryParameters aaiNqQueryParam = new AaiNqQueryParameters();
 
 314         AaiNqNamedQuery aaiNqNamedQuery = new AaiNqNamedQuery();
 
 315         final AaiNqInstanceFilters aaiNqInstanceFilter = new AaiNqInstanceFilters();
 
 318         // UUID.fromString($params.getAaiNamedQueryUUID()) TO DO: AaiNamedQueryUUID
 
 319         aaiNqNamedQuery.setNamedQueryUuid(UUID.fromString("4ff56a54-9e3f-46b7-a337-07a1d3c6b469"));
 
 320         aaiNqQueryParam.setNamedQuery(aaiNqNamedQuery);
 
 321         aaiNqRequest.setQueryParameters(aaiNqQueryParam);
 
 325         Map<String, Map<String, String>> aaiNqInstanceFilterMap = new HashMap<>();
 
 326         Map<String, String> aaiNqInstanceFilterMapItem = new HashMap<>();
 
 327         // TO DO: get vserver.vname from dcae onset.AAI.get("vserver.vserver-name")
 
 328         aaiNqInstanceFilterMapItem.put("vserver-name", onset.getAai().get("vserver.vserver-name"));
 
 329         aaiNqInstanceFilterMap.put("vserver", aaiNqInstanceFilterMapItem);
 
 330         aaiNqInstanceFilter.getInstanceFilter().add(aaiNqInstanceFilterMap);
 
 331         aaiNqRequest.setInstanceFilters(aaiNqInstanceFilter);
 
 333         if (logger.isDebugEnabled()) {
 
 334             logger.debug("AAI Request sent: {}", Serialization.gsonPretty.toJson(aaiNqRequest));
 
 337         AaiNqResponse aaiNqResponse = new AaiManager(new RESTManager()).postQuery(getPeManagerEnvProperty("aai.url"),
 
 338                 getPeManagerEnvProperty("aai.username"), getPeManagerEnvProperty("aai.password"), aaiNqRequest,
 
 339                 onset.getRequestId());
 
 341         // Check AAI response
 
 342         if (aaiNqResponse == null) {
 
 343             logger.warn("No response received from AAI for request {}", aaiNqRequest);
 
 347         // Create AAINQResponseWrapper
 
 348         AaiNqResponseWrapper aaiNqResponseWrapper = new AaiNqResponseWrapper(onset.getRequestId(), aaiNqResponse);
 
 350         if (logger.isDebugEnabled()) {
 
 351             logger.debug("AAI Named Query Response: ");
 
 352             logger.debug(Serialization.gsonPretty.toJson(aaiNqResponseWrapper.getAaiNqResponse()));
 
 355         return aaiNqResponseWrapper;
 
 359      * Find the base index or non base index in a list of inventory response items.
 
 361      * @param inventoryResponseItems the list of inventory response items
 
 362      * @param baseIndexFlag true if we are searching for the base index, false if we are searching
 
 363      *        for the non base index
 
 364      * @return the base or non base index or -1 if the index was not found
 
 366     private int findIndex(List<AaiNqInventoryResponseItem> inventoryResponseItems, boolean baseIndexFlag) {
 
 367         for (AaiNqInventoryResponseItem invenoryResponseItem : inventoryResponseItems) {
 
 368             if (invenoryResponseItem.getVfModule() != null
 
 369                     && baseIndexFlag == invenoryResponseItem.getVfModule().getIsBaseVfModule()) {
 
 370                 return inventoryResponseItems.indexOf(invenoryResponseItem);
 
 378      * Find the number of non base modules present in API response object.
 
 380      * @param inventoryResponseItems the list of inventory response items
 
 381      * @return number of non base index modules
 
 384     private int findNonBaseModules(List<AaiNqInventoryResponseItem> inventoryResponseItems) {
 
 385         int nonBaseModuleCount = 0;
 
 386         for (AaiNqInventoryResponseItem invenoryResponseItem : inventoryResponseItems) {
 
 387             if (invenoryResponseItem.getVfModule() != null
 
 388                     && (!invenoryResponseItem.getVfModule().getIsBaseVfModule())) {
 
 389                 nonBaseModuleCount++;
 
 392         return nonBaseModuleCount;
 
 396      * This method is called to remember the last service instance ID and VNF Item VNF ID. Note
 
 397      * these fields are static, beware for multithreaded deployments
 
 399      * @param vnfInstanceId update the last VNF instance ID to this value
 
 400      * @param serviceInstanceId update the last service instance ID to this value
 
 402     private static void preserveInstanceIds(final String vnfInstanceId, final String serviceInstanceId) {
 
 403         lastVNFItemVnfId = vnfInstanceId;
 
 404         lastServiceItemServiceInstanceId = serviceInstanceId;
 
 408      * This method reads and validates environmental properties coming from the policy engine. Null
 
 409      * properties cause an {@link IllegalArgumentException} runtime exception to be thrown
 
 411      * @param string the name of the parameter to retrieve
 
 412      * @return the property value
 
 414     private static String getPeManagerEnvProperty(String enginePropertyName) {
 
 415         String enginePropertyValue = PolicyEngine.manager.getEnvironmentProperty(enginePropertyName);
 
 416         if (enginePropertyValue == null) {
 
 417             throw new IllegalArgumentException("The value of policy engine manager environment property \""
 
 418                     + enginePropertyName + "\" may not be null");
 
 420         return enginePropertyValue;