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 java.util.UUID;
 
  31 import org.drools.core.WorkingMemory;
 
  32 import org.onap.policy.aai.AaiNqExtraProperty;
 
  33 import org.onap.policy.aai.AaiNqInventoryResponseItem;
 
  34 import org.onap.policy.aai.AaiNqResponseWrapper;
 
  35 import org.onap.policy.controlloop.ControlLoopOperation;
 
  36 import org.onap.policy.controlloop.VirtualControlLoopEvent;
 
  37 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
 
  38 import org.onap.policy.controlloop.policy.Policy;
 
  39 import org.onap.policy.so.*;
 
  40 import org.onap.policy.so.util.Serialization;
 
  41 import org.slf4j.Logger;
 
  42 import org.slf4j.LoggerFactory;
 
  44 public class SOActorServiceProvider implements Actor {
 
  45     private static final Logger logger = LoggerFactory.getLogger(SOActorServiceProvider.class);
 
  47     // Strings for SO Actor
 
  48     private static final String SO_ACTOR = "SO";
 
  50     // Strings for targets
 
  51     private static final String TARGET_VFC = "VFC";
 
  53     // Strings for recipes
 
  54     private static final String RECIPE_VF_MODULE_CREATE = "VF Module Create";
 
  55     private static final String RECIPE_VF_MODULE_DELETE = "VF Module Delete";
 
  57     private static final ImmutableList<String> recipes = ImmutableList.of(RECIPE_VF_MODULE_CREATE,
 
  58             RECIPE_VF_MODULE_DELETE);
 
  59     private static final ImmutableMap<String, List<String>> targets = new ImmutableMap.Builder<String, List<String>>()
 
  60                     .put(RECIPE_VF_MODULE_CREATE, ImmutableList.of(TARGET_VFC))
 
  61                     .put(RECIPE_VF_MODULE_DELETE, ImmutableList.of(TARGET_VFC)).build();
 
  63     // name of request parameters within policy payload
 
  64     public static final String REQ_PARAM_NM = "requestParameters";
 
  66     // name of configuration parameters within policy payload
 
  67     public static final String CONFIG_PARAM_NM = "configurationParameters";
 
  69     private static final String MODEL_NAME_PROPERTY_KEY = "model-ver.model-name";
 
  70     private static final String MODEL_VERSION_PROPERTY_KEY = "model-ver.model-version";
 
  71     private static final String MODEL_VERSION_ID_PROPERTY_KEY = "model-ver.model-version-id";
 
  73     // used to decode configuration parameters via gson
 
  74     private static final Type CONFIG_TYPE = new TypeToken<List<Map<String, String>>>() {}.getType();
 
  76     // Static variables required to hold the IDs of the last service item, VNF item and VF Module.
 
  78     // a multithreaded deployment this WILL break
 
  79     private static String lastVNFItemVnfId;
 
  80     private static String lastServiceItemServiceInstanceId;
 
  81     private static String lastVfModuleItemVfModuleInstanceId;
 
  84     public String actor() {
 
  89     public List<String> recipes() {
 
  90         return ImmutableList.copyOf(recipes);
 
  94     public List<String> recipeTargets(String recipe) {
 
  95         return ImmutableList.copyOf(targets.getOrDefault(recipe, Collections.emptyList()));
 
  99     public List<String> recipePayloads(String recipe) {
 
 100         return Collections.emptyList();
 
 104      * Constructs a SO request conforming to the lcm API. The actual request is
 
 105      * constructed and then placed in a wrapper object used to send through DMAAP.
 
 107      * @param onset the event that is reporting the alert for policy to perform an action
 
 108      * @param operation the control loop operation specifying the actor, operation,
 
 110      * @param policy the policy the was specified from the yaml generated by CLAMP or
 
 111      *        through the Policy GUI/API
 
 112      * @param aaiResponseWrapper wrapper for AAI vserver named-query response
 
 113      * @return a SO request conforming to the lcm API using the DMAAP wrapper
 
 115     public SORequest constructRequest(VirtualControlLoopEvent onset, ControlLoopOperation operation, Policy policy,
 
 116                     AaiNqResponseWrapper aaiResponseWrapper) {
 
 117         if (!SO_ACTOR.equals(policy.getActor()) || !recipes().contains(policy.getRecipe())) {
 
 121         // A&AI named query should have been performed by now. If not, return null
 
 122         if (aaiResponseWrapper == null) {
 
 126         AaiNqInventoryResponseItem vnfItem;
 
 127         AaiNqInventoryResponseItem vnfServiceItem;
 
 128         AaiNqInventoryResponseItem tenantItem;
 
 130         // Extract the items we're interested in from the response
 
 132             vnfItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
 
 133                             .getInventoryResponseItems().get(0);
 
 134         } catch (Exception e) {
 
 135             logger.error("VNF Item not found in AAI response {}", Serialization.gsonPretty.toJson(aaiResponseWrapper),
 
 141             vnfServiceItem = vnfItem.getItems().getInventoryResponseItems().get(0);
 
 142         } catch (Exception e) {
 
 143             logger.error("VNF Service Item not found in AAI response {}",
 
 144                             Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
 
 149             tenantItem = aaiResponseWrapper.getAaiNqResponse().getInventoryResponseItems().get(0).getItems()
 
 150                             .getInventoryResponseItems().get(1);
 
 151         } catch (Exception e) {
 
 152             logger.error("Tenant Item not found in AAI response {}",
 
 153                             Serialization.gsonPretty.toJson(aaiResponseWrapper), e);
 
 157         // Find the index for base vf module and non-base vf module
 
 158         AaiNqInventoryResponseItem baseItem = findVfModule(aaiResponseWrapper, true);
 
 159         AaiNqInventoryResponseItem vfModuleItem = findVfModule(aaiResponseWrapper, false);
 
 161         // Report the error if either base vf module or non-base vf module is not found
 
 162         if (baseItem == null || vfModuleItem == null) {
 
 163             logger.error("Either base or non-base vf module is not found from AAI response.");
 
 167         // Construct SO Request for a policy's recipe
 
 168         if (RECIPE_VF_MODULE_CREATE.equals(policy.getRecipe())) {
 
 169             return constructCreateRequest(aaiResponseWrapper, policy, tenantItem, vnfItem, vnfServiceItem,
 
 171         } else if (RECIPE_VF_MODULE_DELETE.equals(policy.getRecipe())) {
 
 172             return constructDeleteRequest(tenantItem, vnfItem, vnfServiceItem, vfModuleItem);
 
 179      * Construct SO request to create vf-module
 
 181      * @param aaiResponseWrapper the AAI response containing the VF modules
 
 182      * @param policy             the policy
 
 183      * @param tenantItem         tenant item from A&AI named-query response
 
 184      * @param vnfItem            vnf item from A&AI named-query response
 
 185      * @param vnfServiceItem     vnf service item from A&AI named-query response
 
 186      * @param vfModuleItem       vf module item from A&AI named-query response
 
 187      * @return SO create vf-module request
 
 189     private SORequest constructCreateRequest(AaiNqResponseWrapper aaiResponseWrapper, Policy policy,
 
 190                                              AaiNqInventoryResponseItem tenantItem, AaiNqInventoryResponseItem vnfItem,
 
 191                                              AaiNqInventoryResponseItem vnfServiceItem,
 
 192                                              AaiNqInventoryResponseItem vfModuleItem) {
 
 193         SORequest request = new SORequest();
 
 194         request.setOperationType(SoOperationType.SCALE_OUT);
 
 197         // Do NOT send So the requestId, they do not support this field
 
 199         request.setRequestDetails(new SORequestDetails());
 
 200         request.getRequestDetails().setRequestParameters(new SORequestParameters());
 
 201         request.getRequestDetails().getRequestParameters().setUserParams(null);
 
 203         // cloudConfiguration
 
 204         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
 
 206         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
 
 207         request.getRequestDetails().getModelInfo().setModelVersionId(vfModuleItem.getVfModule().getModelVersionId());
 
 210         request.getRequestDetails().setRequestInfo(constructRequestInfo());
 
 211         String vfModuleName = aaiResponseWrapper.genVfModuleName();
 
 212         request.getRequestDetails().getRequestInfo().setInstanceName(vfModuleName);
 
 214         // relatedInstanceList
 
 215         SORelatedInstanceListElement relatedInstanceListElement0 = new SORelatedInstanceListElement();
 
 216         SORelatedInstanceListElement relatedInstanceListElement1 = new SORelatedInstanceListElement();
 
 217         SORelatedInstanceListElement relatedInstanceListElement2 = new SORelatedInstanceListElement();
 
 218         relatedInstanceListElement1.setRelatedInstance(new SORelatedInstance());
 
 219         relatedInstanceListElement2.setRelatedInstance(new SORelatedInstance());
 
 222         relatedInstanceListElement0.setRelatedInstance(new SORelatedInstance());
 
 223         relatedInstanceListElement0.getRelatedInstance().setInstanceId(UUID.randomUUID().toString());
 
 224         relatedInstanceListElement0.getRelatedInstance().setInstanceName(vfModuleName + "_vol");
 
 225         relatedInstanceListElement0.getRelatedInstance().setModelInfo(new SOModelInfo());
 
 226         relatedInstanceListElement0.getRelatedInstance().getModelInfo().setModelType("volumeGroup");
 
 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(relatedInstanceListElement0);
 
 272         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement1);
 
 273         request.getRequestDetails().getRelatedInstanceList().add(relatedInstanceListElement2);
 
 275         // Request Parameters
 
 276         request.getRequestDetails().setRequestParameters(buildRequestParameters(policy));
 
 278         // Configuration Parameters
 
 279         request.getRequestDetails().setConfigurationParameters(buildConfigurationParameters(policy));
 
 280         // Save the instance IDs for the VNF and service to static fields
 
 281         // vfModuleId is not required for the create vf-module
 
 282         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
 
 283                 .getServiceInstanceId(), null);
 
 284         if (logger.isDebugEnabled()) {
 
 285             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
 
 291      * Construct SO request to delete vf-module
 
 293      * @param tenantItem         tenant item from A&AI named-query response
 
 294      * @param vnfItem            vnf item from A&AI named-query response
 
 295      * @param vnfServiceItem     vnf service item from A&AI named-query response
 
 296      * @param vfModuleItem       vf module item from A&AI named-query response
 
 297      * @return SO delete vf-module request
 
 299     private SORequest constructDeleteRequest(AaiNqInventoryResponseItem tenantItem, AaiNqInventoryResponseItem
 
 300             vnfItem, AaiNqInventoryResponseItem vnfServiceItem, AaiNqInventoryResponseItem vfModuleItem) {
 
 301         SORequest request = new SORequest();
 
 302         request.setOperationType(SoOperationType.DELETE_VF_MODULE);
 
 303         request.setRequestDetails(new SORequestDetails());
 
 304         request.getRequestDetails().setRelatedInstanceList(null);
 
 305         request.getRequestDetails().setConfigurationParameters(null);
 
 307         // cloudConfiguration
 
 308         request.getRequestDetails().setCloudConfiguration(constructCloudConfiguration(tenantItem));
 
 310         request.getRequestDetails().setModelInfo(constructVfModuleModelInfo(vfModuleItem));
 
 312         request.getRequestDetails().setRequestInfo(constructRequestInfo());
 
 313         // Save the instance IDs for the VNF, service and vfModule to static fields
 
 314         preserveInstanceIds(vnfItem.getGenericVnf().getVnfId(), vnfServiceItem.getServiceInstance()
 
 315                 .getServiceInstanceId(), vfModuleItem.getVfModule().getVfModuleId());
 
 317         if (logger.isDebugEnabled()) {
 
 318             logger.debug("Constructed SO request: {}", Serialization.gsonPretty.toJson(request));
 
 324      * construct requestInfo for the SO requestDetails
 
 326      * @return SO request information
 
 328     private SORequestInfo constructRequestInfo() {
 
 329         SORequestInfo soRequestInfo = new SORequestInfo();
 
 330         soRequestInfo.setSource("POLICY");
 
 331         soRequestInfo.setSuppressRollback(false);
 
 332         soRequestInfo.setRequestorId("policy");
 
 333         return soRequestInfo;
 
 337      * construct modelInfo of the vfModule for the SO requestDetails
 
 339      * @param vfModuleItem vf module item from A&AI named-query response
 
 340      * @return SO Model info for the vfModule
 
 342     private SOModelInfo constructVfModuleModelInfo(AaiNqInventoryResponseItem vfModuleItem) {
 
 343         SOModelInfo soModelInfo = new SOModelInfo();
 
 344         soModelInfo.setModelType("vfModule");
 
 345         soModelInfo.setModelInvariantId(vfModuleItem.getVfModule().getModelInvariantId());
 
 346         soModelInfo.setModelCustomizationId(vfModuleItem.getVfModule().getModelCustomizationId());
 
 348         for (AaiNqExtraProperty prop : vfModuleItem.getExtraProperties().getExtraProperty()) {
 
 349             if (prop.getPropertyName().equals(MODEL_NAME_PROPERTY_KEY)) {
 
 350                 soModelInfo.setModelName(prop.getPropertyValue());
 
 351             } else if (prop.getPropertyName().equals(MODEL_VERSION_PROPERTY_KEY)) {
 
 352                 soModelInfo.setModelVersion(prop.getPropertyValue());
 
 359      * construct cloudConfiguration for the SO requestDetails
 
 361      * @param tenantItem tenant item from A&AI named-query response
 
 362      * @return SO cloud configuration
 
 364     private SOCloudConfiguration constructCloudConfiguration(AaiNqInventoryResponseItem tenantItem) {
 
 365         SOCloudConfiguration cloudConfiguration = new SOCloudConfiguration();
 
 366         cloudConfiguration.setTenantId(tenantItem.getTenant().getTenantId());
 
 367         cloudConfiguration.setLcpCloudRegionId(tenantItem.getItems().getInventoryResponseItems().get(0)
 
 368                 .getCloudRegion().getCloudRegionId());
 
 369         return cloudConfiguration;
 
 373      * This method is needed to get the serviceInstanceId and vnfInstanceId which is used
 
 374      * in the asyncSORestCall.
 
 376      * @param requestId the request Id
 
 377      * @param wm the working memory
 
 378      * @param request the request
 
 380     public static void sendRequest(String requestId, WorkingMemory wm, Object request) {
 
 381         SOManager soManager = new SOManager();
 
 382         soManager.asyncSORestCall(requestId, wm, lastServiceItemServiceInstanceId, lastVNFItemVnfId,
 
 383                 lastVfModuleItemVfModuleInstanceId, (SORequest) request);
 
 387      * Find the base or non base VF module item in an AAI response.
 
 388      * If there is more than one item, then the <i>last</i> item is returned
 
 390      * @param aaiResponseWrapper the AAI response containing the VF modules
 
 391      * @param baseFlag true if we are searching for the base, false if we are searching
 
 393      * @return the base or non base VF module item or null if the module was not found
 
 395     private AaiNqInventoryResponseItem findVfModule(AaiNqResponseWrapper aaiResponseWrapper, boolean baseFlag) {
 
 396         List<AaiNqInventoryResponseItem> lst = aaiResponseWrapper.getVfModuleItems(baseFlag);
 
 397         return (lst == null || lst.isEmpty() ? null : lst.get(lst.size() - 1));
 
 401      * Builds the request parameters from the policy payload.
 
 403      * @param policy the policy
 
 404      * @return the request parameters, or {@code null} if the payload is {@code null}
 
 406     private SORequestParameters buildRequestParameters(Policy policy) {
 
 407         if (policy.getPayload() == null) {
 
 411         String json = policy.getPayload().get(REQ_PARAM_NM);
 
 416         return Serialization.gsonPretty.fromJson(json, SORequestParameters.class);
 
 420      * Builds the configuration parameters from the policy payload.
 
 422      * @param policy the policy
 
 423      * @return the configuration parameters, or {@code null} if the payload is
 
 426     private List<Map<String, String>> buildConfigurationParameters(Policy policy) {
 
 427         if (policy.getPayload() == null) {
 
 431         String json = policy.getPayload().get(CONFIG_PARAM_NM);
 
 436         return Serialization.gsonPretty.fromJson(json, CONFIG_TYPE);
 
 440      * This method is called to remember the last service instance ID, VNF Item VNF ID and vf module ID.
 
 441      * Note these fields are static, beware for multithreaded deployments
 
 443      * @param vnfInstanceId update the last VNF instance ID to this value
 
 444      * @param serviceInstanceId update the last service instance ID to this value
 
 445      * @param vfModuleId update the vfModule instance ID to this value
 
 447     private static void preserveInstanceIds(final String vnfInstanceId, final String serviceInstanceId,
 
 448                                             final String vfModuleId) {
 
 449         lastVNFItemVnfId = vnfInstanceId;
 
 450         lastServiceItemServiceInstanceId = serviceInstanceId;
 
 451         lastVfModuleItemVfModuleInstanceId = vfModuleId;