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;
 
  25 import com.google.gson.reflect.TypeToken;
 
  26 import java.lang.reflect.Type;
 
  27 import java.util.Collections;
 
  28 import java.util.List;
 
  30 import org.drools.core.WorkingMemory;
 
  31 import org.onap.policy.aai.AaiNqExtraProperty;
 
  32 import org.onap.policy.aai.AaiNqInventoryResponseItem;
 
  33 import org.onap.policy.aai.AaiNqResponseWrapper;
 
  34 import org.onap.policy.controlloop.ControlLoopOperation;
 
  35 import org.onap.policy.controlloop.VirtualControlLoopEvent;
 
  36 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
 
  37 import org.onap.policy.controlloop.policy.Policy;
 
  38 import org.onap.policy.so.SOCloudConfiguration;
 
  39 import org.onap.policy.so.SOManager;
 
  40 import org.onap.policy.so.SOModelInfo;
 
  41 import org.onap.policy.so.SORelatedInstance;
 
  42 import org.onap.policy.so.SORelatedInstanceListElement;
 
  43 import org.onap.policy.so.SORequest;
 
  44 import org.onap.policy.so.SORequestDetails;
 
  45 import org.onap.policy.so.SORequestInfo;
 
  46 import org.onap.policy.so.SORequestParameters;
 
  47 import org.onap.policy.so.SoOperationType;
 
  48 import org.onap.policy.so.util.Serialization;
 
  49 import org.slf4j.Logger;
 
  50 import org.slf4j.LoggerFactory;
 
  52 public class SOActorServiceProvider implements Actor {
 
  53     private static final Logger logger = LoggerFactory.getLogger(SOActorServiceProvider.class);
 
  55     // Strings for SO Actor
 
  56     private static final String SO_ACTOR = "SO";
 
  58     // Strings for targets
 
  59     private static final String TARGET_VFC = "VFC";
 
  61     // Strings for recipes
 
  62     private static final String RECIPE_VF_MODULE_CREATE = "VF Module Create";
 
  63     private static final String RECIPE_VF_MODULE_DELETE = "VF Module Delete";
 
  65     private static final ImmutableList<String> recipes = ImmutableList.of(RECIPE_VF_MODULE_CREATE,
 
  66             RECIPE_VF_MODULE_DELETE);
 
  67     private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>()
 
  68                     .put(RECIPE_VF_MODULE_CREATE, ImmutableList.of(TARGET_VFC))
 
  69                     .put(RECIPE_VF_MODULE_DELETE, ImmutableList.of(TARGET_VFC)).build();
 
  71     // name of request parameters within policy payload
 
  72     public static final String REQ_PARAM_NM = "requestParameters";
 
  74     // name of configuration parameters within policy payload
 
  75     public static final String CONFIG_PARAM_NM = "configurationParameters";
 
  77     private static final String MODEL_NAME_PROPERTY_KEY = "model-ver.model-name";
 
  78     private static final String MODEL_VERSION_PROPERTY_KEY = "model-ver.model-version";
 
  79     private static final String MODEL_VERSION_ID_PROPERTY_KEY = "model-ver.model-version-id";
 
  81     // used to decode configuration parameters via gson
 
  82     private static final Type CONFIG_TYPE = new TypeToken<List<Map<String, String>>>() {}.getType();
 
  84     // Static variables required to hold the IDs of the last service item, VNF item and VF Module.
 
  86     // a multithreaded deployment this WILL break
 
  87     private static String lastVNFItemVnfId;
 
  88     private static String lastServiceItemServiceInstanceId;
 
  89     private static String lastVfModuleItemVfModuleInstanceId;
 
  92     public String actor() {
 
  97     public List<String> recipes() {
 
  98         return ImmutableList.copyOf(recipes);
 
 102     public List<String> recipeTargets(String recipe) {
 
 103         return ImmutableList.copyOf(targets.getOrDefault(recipe, Collections.emptyList()));
 
 107     public List<String> recipePayloads(String recipe) {
 
 108         return Collections.emptyList();
 
 112      * Constructs a SO request conforming to the lcm API. The actual request is
 
 113      * constructed and then placed in a wrapper object used to send through DMAAP.
 
 115      * @param onset the event that is reporting the alert for policy to perform an action
 
 116      * @param operation the control loop operation specifying the actor, operation,
 
 118      * @param policy the policy the was specified from the yaml generated by CLAMP or
 
 119      *        through the Policy GUI/API
 
 120      * @param aaiResponseWrapper wrapper for AAI vserver named-query response
 
 121      * @return a SO request conforming to the lcm API using the DMAAP wrapper
 
 123     public SORequest constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, Policy policy,
 
 124                     AaiNqResponseWrapper aaiResponseWrapper) {
 
 125         if (!SO_ACTOR.equals(policy.getActor()) || !recipes().contains(policy.getRecipe())) {
 
 129         // A&AI named query should have been performed by now. If not, return null
 
 130         if (aaiResponseWrapper == null) {
 
 134         AaiNqInventoryResponseItem vnfItem;
 
 135         AaiNqInventoryResponseItem vnfServiceItem;
 
 136         AaiNqInventoryResponseItem tenantItem;
 
 138         // Extract the items we're interested in from the response
 
 140             vnfItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
 
 141                             .getInventoryResponseItems().get(0);
 
 142         } catch (Exception e) {
 
 143             logger.error("VNF Item not found in AAI response {}", Serialization.gsonPretty.toJson(aaiResponseWrapper),
 
 149             vnfServiceItem = vnfItem.getItems().getInventoryResponseItems().get(0);
 
 150         } catch (Exception e) {
 
 151             logger.error("VNF Service Item not found in AAI response {}",
 
 152                             Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
 
 157             tenantItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
 
 158                             .getInventoryResponseItems().get(1);
 
 159         } catch (Exception e) {
 
 160             logger.error("Tenant Item not found in AAI response {}",
 
 161                             Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
 
 165         // Find the index for base vf module and non-base vf module
 
 166         AaiNqInventoryResponseItem baseItem = findVfModule(aaiResponseWrapper, true);
 
 167         AaiNqInventoryResponseItem vfModuleItem = findVfModule(aaiResponseWrapper, false);
 
 169         // Report the error if either base vf module or non-base vf module is not found
 
 170         if (baseItem == null || vfModuleItem == null) {
 
 171             logger.error("Either base or non-base vf module is not found from AAI response.");
 
 175         // Construct SO Request for a policy's recipe
 
 176         if (RECIPE_VF_MODULE_CREATE.equals(policy.getRecipe())) {
 
 177             return constructCreateRequest(aaiResponseWrapper, policy, tenantItem, vnfItem, vnfServiceItem,
 
 179         } else if (RECIPE_VF_MODULE_DELETE.equals(policy.getRecipe())) {
 
 180             return constructDeleteRequest(tenantItem, vnfItem, vnfServiceItem, vfModuleItem);
 
 187      * Construct SO request to create vf-module
 
 189      * @param aaiResponseWrapper the AAI response containing the VF modules
 
 190      * @param policy             the policy
 
 191      * @param tenantItem         tenant item from A&AI named-query response
 
 192      * @param vnfItem            vnf item from A&AI named-query response
 
 193      * @param vnfServiceItem     vnf service item from A&AI named-query response
 
 194      * @param vfModuleItem       vf module item from A&AI named-query response
 
 195      * @return SO create vf-module request
 
 197     private SORequest constructCreateRequest(AaiNqResponseWrapper aaiResponseWrapper, Policy policy,
 
 198                                              AaiNqInventoryResponseItem tenantItem, AaiNqInventoryResponseItem vnfItem,
 
 199                                              AaiNqInventoryResponseItem vnfServiceItem,
 
 200                                              AaiNqInventoryResponseItem vfModuleItem) {
 
 201         SORequest request = new SORequest();
 
 202         request.setOperationType(SoOperationType.SCALE_OUT);
 
 205         // Do NOT send So the requestId, they do not support this field
 
 207         request.setRequestDetails(new SORequestDetails());
 
 208         request.getRequestDetails().setRequestParameters(new SORequestParameters());
 
 209         request.getRequestDetails().getRequestParameters().setUserParams(null);
 
 211         // cloudConfiguration
 
 212         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
 
 214         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
 
 215         request.getRequestDetails().getModelInfo().setModelVersionId(vfModuleItem.getVfModule().getModelVersionId());
 
 218         request.getRequestDetails().setRequestInfo(constructRequestInfo());
 
 219         String vfModuleName = aaiResponseWrapper.genVfModuleName();
 
 220         request.getRequestDetails().getRequestInfo().setInstanceName(vfModuleName);
 
 222         // relatedInstanceList
 
 223         SORelatedInstanceListElement relatedInstanceListElement1 = new SORelatedInstanceListElement();
 
 224         SORelatedInstanceListElement relatedInstanceListElement2 = new SORelatedInstanceListElement();
 
 225         relatedInstanceListElement1.setRelatedInstance(new SORelatedInstance());
 
 226         relatedInstanceListElement2.setRelatedInstance(new SORelatedInstance());
 
 229         relatedInstanceListElement1.getRelatedInstance()
 
 230                 .setInstanceId(vnfServiceItem.getServiceInstance().getServiceInstanceId());
 
 231         relatedInstanceListElement1.getRelatedInstance().setModelInfo(new SOModelInfo());
 
 232         relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelType("service");
 
 233         relatedInstanceListElement1.getRelatedInstance().getModelInfo()
 
 234                 .setModelInvariantId(vnfServiceItem.getServiceInstance().getModelInvariantId());
 
 235         for (AaiNqExtraProperty prop : vnfServiceItem.getExtraProperties().getExtraProperty()) {
 
 236             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
 
 237                 relatedInstanceListElement1.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
 
 238             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
 
 239                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
 
 240                         .setModelVersion(prop.getPropertyValue());
 
 241             } else if (prop.getPropertyName().equals(MODEL_VERSION_ID_PROPERTY_KEY)) {
 
 242                 relatedInstanceListElement1.getRelatedInstance().getModelInfo()
 
 243                         .setModelVersionId(prop.getPropertyValue());
 
 248         relatedInstanceListElement2.getRelatedInstance().setInstanceId(vnfItem.getGenericVnf().getVnfId());
 
 249         relatedInstanceListElement2.getRelatedInstance().setModelInfo(new SOModelInfo());
 
 250         relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelType("vnf");
 
 251         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 252                 .setModelInvariantId(vnfItem.getGenericVnf().getModelInvariantId());
 
 253         for (AaiNqExtraProperty prop : vnfItem.getExtraProperties().getExtraProperty()) {
 
 254             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
 
 255                 relatedInstanceListElement2.getRelatedInstance().getModelInfo().setModelName(prop.getPropertyValue());
 
 256             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
 
 257                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 258                         .setModelVersion(prop.getPropertyValue());
 
 259             } else if (prop.getPropertyName().equals(MODEL_VERSION_ID_PROPERTY_KEY)) {
 
 260                 relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 261                         .setModelVersionId(prop.getPropertyValue());
 
 264         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 265                 .setModelCustomizationName(vnfItem.getGenericVnf().getVnfType()
 
 266                         .substring(vnfItem.getGenericVnf().getVnfType().lastIndexOf('/') + 1));
 
 267         relatedInstanceListElement2.getRelatedInstance().getModelInfo()
 
 268                 .setModelCustomizationId(vnfItem.getGenericVnf().getModelCustomizationId());
 
 270         // Insert the Service Item and VNF Item
 
 271         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1);
 
 272         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2);
 
 274         // Request Parameters
 
 275         buildRequestParameters(policy, request.getRequestDetails());
 
 277         // Configuration Parameters
 
 278         buildConfigurationParameters(policy, request.getRequestDetails());
 
 279         // Save the instance IDs for the VNF and service to static fields
 
 280         // vfModuleId is not required for the create vf-module
 
 281         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
 
 282                 .getServiceInstanceId(), null);
 
 283         if (logger.isDebugEnabled()) {
 
 284             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
 
 290      * Construct SO request to delete vf-module
 
 292      * @param tenantItem         tenant item from A&AI named-query response
 
 293      * @param vnfItem            vnf item from A&AI named-query response
 
 294      * @param vnfServiceItem     vnf service item from A&AI named-query response
 
 295      * @param vfModuleItem       vf module item from A&AI named-query response
 
 296      * @return SO delete vf-module request
 
 298     private SORequest constructDeleteRequest(AaiNqInventoryResponseItem tenantItem, AaiNqInventoryResponseItem
 
 299             vnfItem, AaiNqInventoryResponseItem vnfServiceItem, AaiNqInventoryResponseItem vfModuleItem) {
 
 300         SORequest request = new SORequest();
 
 301         request.setOperationType(SoOperationType.DELETE_VF_MODULE);
 
 302         request.setRequestDetails(new SORequestDetails());
 
 303         request.getRequestDetails().setRelatedInstanceList(null);
 
 304         request.getRequestDetails().setConfigurationParameters(null);
 
 306         // cloudConfiguration
 
 307         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
 
 309         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
 
 311         request.getRequestDetails().setRequestInfo(constructRequestInfo());
 
 312         // Save the instance IDs for the VNF, service and vfModule to static fields
 
 313         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
 
 314                 .getServiceInstanceId(), vfModuleItem.getVfModule().getVfModuleId());
 
 316         if (logger.isDebugEnabled()) {
 
 317             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
 
 323      * construct requestInfo for the SO requestDetails
 
 325      * @return SO request information
 
 327     private SORequestInfo constructRequestInfo() {
 
 328         SORequestInfo soRequestInfo = new SORequestInfo();
 
 329         soRequestInfo.setSource("POLICY");
 
 330         soRequestInfo.setSuppressRollback(false);
 
 331         soRequestInfo.setRequestorId("policy");
 
 332         return soRequestInfo;
 
 336      * construct modelInfo of the vfModule for the SO requestDetails
 
 338      * @param vfModuleItem vf module item from A&AI named-query response
 
 339      * @return SO Model info for the vfModule
 
 341     private SOModelInfo constructVfModuleModelInfo(AaiNqInventoryResponseItem vfModuleItem) {
 
 342         SOModelInfo soModelInfo = new SOModelInfo();
 
 343         soModelInfo.setModelType("vfModule");
 
 344         soModelInfo.setModelInvariantId(vfModuleItem.getVfModule().getModelInvariantId());
 
 345         soModelInfo.setModelCustomizationId(vfModuleItem.getVfModule().getModelCustomizationId());
 
 347         for (AaiNqExtraProperty prop : vfModuleItem.getExtraProperties().getExtraProperty()) {
 
 348             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
 
 349                 soModelInfo.setModelName(prop.getPropertyValue());
 
 350             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
 
 351                 soModelInfo.setModelVersion(prop.getPropertyValue());
 
 358      * construct cloudConfiguration for the SO requestDetails
 
 360      * @param tenantItem tenant item from A&AI named-query response
 
 361      * @return SO cloud configuration
 
 363     private SOCloudConfiguration constructCloudConfiguration(AaiNqInventoryResponseItem tenantItem) {
 
 364         SOCloudConfiguration cloudConfiguration = new SOCloudConfiguration();
 
 365         cloudConfiguration.setTenantId(tenantItem.getTenant().getTenantId());
 
 366         cloudConfiguration.setLcpCloudRegionId(tenantItem.getItems().getInventoryResponseItems().get(0)
 
 367                 .getCloudRegion().getCloudRegionId());
 
 368         return cloudConfiguration;
 
 372      * This method is needed to get the serviceInstanceId and vnfInstanceId which is used
 
 373      * in the asyncSORestCall.
 
 375      * @param requestId the request Id
 
 376      * @param wm the working memory
 
 377      * @param request the request
 
 379     public static void sendRequest(String requestId, WorkingMemory wm, Object request) {
 
 380         SOManager soManager = new SOManager();
 
 381         soManager.asyncSORestCall(requestId, wm, lastServiceItemServiceInstanceId, lastVNFItemVnfId,
 
 382                 lastVfModuleItemVfModuleInstanceId, (SORequest) request);
 
 386      * Find the base or non base VF module item in an AAI response.
 
 387      * If there is more than one item, then the <i>last</i> item is returned
 
 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
 
 392      * @return the base or non base VF module item or null if the module was not found
 
 394     private AaiNqInventoryResponseItem findVfModule(AaiNqResponseWrapper aaiResponseWrapper, boolean baseFlag) {
 
 395         List<AaiNqInventoryResponseItem> lst = aaiResponseWrapper.getVfModuleItems(baseFlag);
 
 396         return (lst.isEmpty() ? null : lst.get(lst.size() - 1));
 
 400      * Builds the request parameters from the policy payload.
 
 402      * @param policy the policy
 
 403      * @param request request into which to stick the request parameters
 
 405     private void buildRequestParameters(Policy policy, SORequestDetails request) {
 
 406         // assume null until proven otherwise
 
 407         request.setRequestParameters(null);
 
 409         if (policy.getPayload() == null) {
 
 413         String json = policy.getPayload().get(REQ_PARAM_NM);
 
 418         request.setRequestParameters(Serialization.gsonPretty.fromJson(json, SORequestParameters.class));
 
 422      * Builds the configuration parameters from the policy payload.
 
 424      * @param policy the policy
 
 425      * @param request request into which to stick the configuration parameters
 
 427     private void buildConfigurationParameters(Policy policy, SORequestDetails request) {
 
 428         // assume null until proven otherwise
 
 429         request.setConfigurationParameters(null);
 
 431         if (policy.getPayload() == null) {
 
 435         String json = policy.getPayload().get(CONFIG_PARAM_NM);
 
 440         request.setConfigurationParameters(Serialization.gsonPretty.fromJson(json, CONFIG_TYPE));
 
 444      * This method is called to remember the last service instance ID, VNF Item VNF ID and vf module ID.
 
 445      * Note these fields are static, beware for multithreaded deployments
 
 447      * @param vnfInstanceId update the last VNF instance ID to this value
 
 448      * @param serviceInstanceId update the last service instance ID to this value
 
 449      * @param vfModuleId update the vfModule instance ID to this value
 
 451     private static void preserveInstanceIds(final String vnfInstanceId, final String serviceInstanceId,
 
 452                                             final String vfModuleId) {
 
 453         lastVNFItemVnfId = vnfInstanceId;
 
 454         lastServiceItemServiceInstanceId = serviceInstanceId;
 
 455         lastVfModuleItemVfModuleInstanceId = vfModuleId;