2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
 
   6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
 
   7  * ================================================================================
 
   8  * Modifications Copyright (C) 2018 IBM.
 
   9  * Modifications Copyright (c) 2019 Samsung
 
  10  * ================================================================================
 
  11  * Licensed under the Apache License, Version 2.0 (the "License");
 
  12  * you may not use this file except in compliance with the License.
 
  13  * You may obtain a copy of the License at
 
  15  *      http://www.apache.org/licenses/LICENSE-2.0
 
  17  * Unless required by applicable law or agreed to in writing, software
 
  18  * distributed under the License is distributed on an "AS IS" BASIS,
 
  19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  20  * See the License for the specific language governing permissions and
 
  21  * limitations under the License.
 
  22  * ============LICENSE_END=========================================================
 
  25 package org.onap.so.adapters.network;
 
  27 import java.util.ArrayList;
 
  28 import java.util.HashMap;
 
  29 import java.util.List;
 
  31 import java.util.Optional;
 
  32 import javax.jws.WebService;
 
  33 import javax.xml.ws.Holder;
 
  34 import org.onap.so.adapters.network.beans.ContrailPolicyRef;
 
  35 import org.onap.so.adapters.network.beans.ContrailPolicyRefSeq;
 
  36 import org.onap.so.adapters.network.beans.ContrailSubnet;
 
  37 import org.onap.so.adapters.network.exceptions.NetworkException;
 
  38 import org.onap.so.adapters.network.mappers.ContrailSubnetMapper;
 
  39 import org.onap.so.cloud.CloudConfig;
 
  40 import org.onap.so.db.catalog.beans.CloudSite;
 
  41 import org.onap.so.db.catalog.beans.CollectionNetworkResourceCustomization;
 
  42 import org.onap.so.db.catalog.beans.HeatTemplate;
 
  43 import org.onap.so.db.catalog.beans.NetworkResource;
 
  44 import org.onap.so.db.catalog.beans.NetworkResourceCustomization;
 
  45 import org.onap.so.db.catalog.data.repository.CollectionNetworkResourceCustomizationRepository;
 
  46 import org.onap.so.db.catalog.data.repository.NetworkResourceCustomizationRepository;
 
  47 import org.onap.so.db.catalog.data.repository.NetworkResourceRepository;
 
  48 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
 
  49 import org.onap.so.entity.MsoRequest;
 
  50 import org.onap.logging.filter.base.ErrorCode;
 
  51 import org.onap.so.logger.LoggingAnchor;
 
  52 import org.onap.so.logger.MessageEnum;
 
  53 import org.onap.so.openstack.beans.HeatStatus;
 
  54 import org.onap.so.openstack.beans.NetworkInfo;
 
  55 import org.onap.so.openstack.beans.NetworkRollback;
 
  56 import org.onap.so.openstack.beans.NetworkStatus;
 
  57 import org.onap.so.openstack.beans.Pool;
 
  58 import org.onap.so.openstack.beans.RouteTarget;
 
  59 import org.onap.so.openstack.beans.StackInfo;
 
  60 import org.onap.so.openstack.beans.Subnet;
 
  61 import org.onap.so.openstack.exceptions.MsoAdapterException;
 
  62 import org.onap.so.openstack.exceptions.MsoException;
 
  63 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
 
  64 import org.onap.so.openstack.utils.MsoCommonUtils;
 
  65 import org.onap.so.openstack.utils.MsoHeatUtils;
 
  66 import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
 
  67 import org.onap.so.openstack.utils.MsoNeutronUtils;
 
  68 import org.onap.so.openstack.utils.MsoNeutronUtils.NetworkType;
 
  69 import org.slf4j.Logger;
 
  70 import org.slf4j.LoggerFactory;
 
  71 import org.springframework.beans.factory.annotation.Autowired;
 
  72 import org.springframework.core.env.Environment;
 
  73 import org.springframework.stereotype.Component;
 
  74 import org.springframework.transaction.annotation.Transactional;
 
  75 import com.fasterxml.jackson.databind.JsonNode;
 
  76 import com.fasterxml.jackson.databind.ObjectMapper;
 
  80 @WebService(serviceName = "NetworkAdapter", endpointInterface = "org.onap.so.adapters.network.MsoNetworkAdapter",
 
  81         targetNamespace = "http://org.onap.so/network")
 
  82 public class MsoNetworkAdapterImpl implements MsoNetworkAdapter {
 
  84     private static final String AIC3_NW_PROPERTY = "org.onap.so.adapters.network.aic3nw";
 
  85     private static final String AIC3_NW = "OS::ContrailV2::VirtualNetwork";
 
  86     private static final String VLANS = "vlans";
 
  87     private static final String PHYSICAL_NETWORK = "physical_network";
 
  88     private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork";
 
  89     private static final String NETWORK_ID = "network_id";
 
  90     private static final String NETWORK_FQDN = "network_fqdn";
 
  91     private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork";
 
  92     private static final String NEUTRON_MODE = "NEUTRON";
 
  93     private static final String CLOUD_OWNER = "CloudOwner";
 
  94     private static final String LOG_DEBUG_MSG = "Got Network definition from Catalog: {}";
 
  95     private static final String NETWORK_EXIST_STATUS_MESSAGE =
 
  96             "The network was found to already exist, thus no new network was created in the cloud via this request";
 
  97     private static final String NETWORK_CREATED_STATUS_MESSAGE =
 
  98             "The new network was successfully created in the cloud";
 
  99     private static final String NETWORK_NOT_EXIST_STATUS_MESSAGE =
 
 100             "The network was not found, thus no network was deleted in the cloud via this request";
 
 101     private static final String NETWORK_DELETED_STATUS_MESSAGE = "The network was successfully deleted in the cloud";
 
 103     private static final Logger logger = LoggerFactory.getLogger(MsoNetworkAdapterImpl.class);
 
 106     private CloudConfig cloudConfig;
 
 108     private Environment environment;
 
 110     private MsoNeutronUtils neutron;
 
 112     private MsoHeatUtils heat;
 
 114     private MsoHeatUtilsWithUpdate heatWithUpdate;
 
 116     private MsoCommonUtils commonUtils;
 
 119     private NetworkResourceCustomizationRepository networkCustomRepo;
 
 122     private CollectionNetworkResourceCustomizationRepository collectionNetworkCustomRepo;
 
 125     private NetworkResourceRepository networkResourceRepo;
 
 127     public MsoNetworkAdapterImpl() {}
 
 130      * Health Check web method. Does nothing but return to show the adapter is deployed.
 
 133     public void healthCheck() {
 
 134         logger.debug("Health check call in Network Adapter");
 
 138      * Do not use this constructor or the msoPropertiesFactory will be NULL.
 
 140      * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
 
 144     public void createNetwork(String cloudSiteId, String tenantId, String networkType, String modelCustomizationUuid,
 
 145             String networkName, String physicalNetworkName, List<Integer> vlans, String shared, String external,
 
 146             Boolean failIfExists, Boolean backout, List<Subnet> subnets, Map<String, String> networkParams,
 
 147             MsoRequest msoRequest, Holder<String> networkId, Holder<String> neutronNetworkId,
 
 148             Holder<Map<String, String>> subnetIdMap, Holder<NetworkRollback> rollback) throws NetworkException {
 
 149         Holder<String> networkFqdn = new Holder<>();
 
 150         createNetwork(cloudSiteId, tenantId, networkType, modelCustomizationUuid, networkName, physicalNetworkName,
 
 151                 vlans, null, shared, external, failIfExists, backout, subnets, null, null, msoRequest, networkId,
 
 152                 neutronNetworkId, networkFqdn, subnetIdMap, rollback);
 
 156     public void createNetworkContrail(String cloudSiteId, String tenantId, String networkType,
 
 157             String modelCustomizationUuid, String networkName, List<RouteTarget> routeTargets, String shared,
 
 158             String external, Boolean failIfExists, Boolean backout, List<Subnet> subnets,
 
 159             Map<String, String> networkParams, List<String> policyFqdns, List<String> routeTableFqdns,
 
 160             MsoRequest msoRequest, Holder<String> networkId, Holder<String> neutronNetworkId,
 
 161             Holder<String> networkFqdn, Holder<Map<String, String>> subnetIdMap, Holder<NetworkRollback> rollback)
 
 162             throws NetworkException {
 
 163         createNetwork(cloudSiteId, tenantId, networkType, modelCustomizationUuid, networkName, null, null, routeTargets,
 
 164                 shared, external, failIfExists, backout, subnets, policyFqdns, routeTableFqdns, msoRequest, networkId,
 
 165                 neutronNetworkId, networkFqdn, subnetIdMap, rollback);
 
 169      * This is the "Create Network" web service implementation. It will create a new Network of the requested type in
 
 170      * the specified cloud and tenant. The tenant must exist at the time this service is called.
 
 172      * If a network with the same name already exists, this can be considered a success or failure, depending on the
 
 173      * value of the 'failIfExists' parameter.
 
 175      * There will be a pre-defined set of network types defined in the MSO Catalog. All such networks will have a
 
 176      * similar configuration, based on the allowable Openstack networking definitions. This includes basic networks,
 
 177      * provider networks (with a single VLAN), and multi-provider networks (one or more VLANs)
 
 179      * Initially, all provider networks must be "vlan" type, and multiple segments in a multi-provider network must be
 
 180      * multiple VLANs on the same physical network.
 
 182      * This service supports two modes of Network creation/update: - via Heat Templates - via Neutron API The network
 
 183      * orchestration mode for each network type is declared in its catalog definition. All Heat-based templates must
 
 184      * support some subset of the same input parameters: network_name, physical_network, vlan(s).
 
 186      * The method returns the network ID and a NetworkRollback object. This latter object can be passed as-is to the
 
 187      * rollbackNetwork operation to undo everything that was created. This is useful if a network is successfully
 
 188      * created but the orchestration fails on a subsequent operation.
 
 191     private void createNetwork(String cloudSiteId, String tenantId, String networkType, String modelCustomizationUuid,
 
 192             String networkName, String physicalNetworkName, List<Integer> vlans, List<RouteTarget> routeTargets,
 
 193             String shared, String external, Boolean failIfExists, Boolean backout, List<Subnet> subnets,
 
 194             List<String> policyFqdns, List<String> routeTableFqdns, MsoRequest msoRequest, Holder<String> networkId,
 
 195             Holder<String> neutronNetworkId, Holder<String> networkFqdn, Holder<Map<String, String>> subnetIdMap,
 
 196             Holder<NetworkRollback> rollback) throws NetworkException {
 
 197         logger.debug("*** CREATE Network: {} of type {} in {}/{}", networkName, networkType, cloudSiteId, tenantId);
 
 199         // Will capture execution time for metrics
 
 200         long startTime = System.currentTimeMillis();
 
 202         // Build a default rollback object (no actions performed)
 
 203         NetworkRollback networkRollback = new NetworkRollback();
 
 204         networkRollback.setCloudId(cloudSiteId);
 
 205         networkRollback.setTenantId(tenantId);
 
 206         networkRollback.setMsoRequest(msoRequest);
 
 207         networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
 
 209         // tenant query is not required here.
 
 210         // If the tenant doesn't exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
 
 211         // So this is just catching that error in a bit more obvious way up front.
 
 213         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
 
 214         if (!cloudSiteOpt.isPresent()) {
 
 215             String error = String.format(
 
 216                     "Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
 
 217                     networkName, cloudSiteId, tenantId);
 
 218             logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
 
 219             // Set the detailed error as the Exception 'message'
 
 220             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 224         NetworkResource networkResource = networkCheck(startTime, networkType, modelCustomizationUuid, networkName,
 
 225                 physicalNetworkName, vlans, routeTargets, cloudSiteId, cloudSiteOpt.get());
 
 226         String mode = networkResource.getOrchestrationMode();
 
 227         NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
 
 229         if (NEUTRON_MODE.equals(mode)) {
 
 231             // Use an MsoNeutronUtils for all neutron commands
 
 233             // See if the Network already exists (by name)
 
 234             NetworkInfo netInfo = null;
 
 236                 netInfo = neutron.queryNetwork(networkName, tenantId, cloudSiteId);
 
 237             } catch (MsoException me) {
 
 239                         "{} {} Exception while querying network {} for CloudSite {} from Tenant {} from OpenStack ",
 
 240                         MessageEnum.RA_QUERY_NETWORK_EXC, ErrorCode.BusinessProcessError.getValue(), networkName,
 
 241                         cloudSiteId, tenantId, me);
 
 242                 me.addContext(CREATE_NETWORK_CONTEXT);
 
 243                 throw new NetworkException(me);
 
 246             if (netInfo != null) {
 
 247                 // Exists. If that's OK, return success with the network ID.
 
 248                 // Otherwise, return an exception.
 
 249                 if (failIfExists != null && failIfExists) {
 
 250                     String error = String.format("Create Nework: Network %s already exists in %s/%s with ID %s",
 
 251                             networkName, cloudSiteId, tenantId, netInfo.getId());
 
 252                     logger.error(LoggingAnchor.THREE, MessageEnum.RA_NETWORK_ALREADY_EXIST,
 
 253                             ErrorCode.DataError.getValue(), error);
 
 254                     throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 256                     // Populate the outputs from the existing network.
 
 257                     networkId.value = netInfo.getId();
 
 258                     neutronNetworkId.value = netInfo.getId();
 
 259                     rollback.value = networkRollback; // Default rollback - no updates performed
 
 260                     logger.warn("{} {} Found Existing network, status={} for Neutron mode ",
 
 261                             MessageEnum.RA_NETWORK_ALREADY_EXIST, ErrorCode.DataError.getValue(), netInfo.getStatus());
 
 263                 heat.updateResourceStatus(msoRequest.getRequestId(), NETWORK_EXIST_STATUS_MESSAGE);
 
 268                 netInfo = neutron.createNetwork(cloudSiteId, tenantId, neutronNetworkType, networkName,
 
 269                         physicalNetworkName, vlans);
 
 270             } catch (MsoException me) {
 
 271                 me.addContext(CREATE_NETWORK_CONTEXT);
 
 272                 logger.error("{} {} Create Network: type {} in {}/{}: ", MessageEnum.RA_CREATE_NETWORK_EXC,
 
 273                         ErrorCode.DataError.getValue(), neutronNetworkType, cloudSiteId, tenantId, me);
 
 275                 throw new NetworkException(me);
 
 278             // Note: ignoring MsoNetworkAlreadyExists because we already checked.
 
 280             // If reach this point, network creation is successful.
 
 281             // Since directly created via Neutron, networkId tracked by MSO is the same
 
 282             // as the neutron network ID.
 
 283             networkId.value = netInfo.getId();
 
 284             neutronNetworkId.value = netInfo.getId();
 
 286             networkRollback.setNetworkCreated(true);
 
 287             networkRollback.setNetworkId(netInfo.getId());
 
 288             networkRollback.setNeutronNetworkId(netInfo.getId());
 
 289             networkRollback.setNetworkType(networkType);
 
 291             logger.debug("Network {} created, id = {}", networkName, netInfo.getId());
 
 292         } else if ("HEAT".equals(mode)) {
 
 294             HeatTemplate heatTemplate = networkResource.getHeatTemplate();
 
 295             if (heatTemplate == null) {
 
 296                 String error = String.format("Network error - undefined Heat Template. Network Type = %s", networkType);
 
 297                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_PARAM_NOT_FOUND, ErrorCode.DataError.getValue(),
 
 299                 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
 
 302             logger.debug("Got HEAT Template from DB: {}", heatTemplate);
 
 304             // "Fix" the template if it has CR/LF (getting this from Oracle)
 
 305             String template = heatTemplate.getHeatTemplate();
 
 306             template = template.replaceAll("\r\n", "\n");
 
 308             boolean aic3template = false;
 
 309             String aic3nw = AIC3_NW;
 
 311             aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
 
 313             if (template.contains(aic3nw))
 
 316             // First, look up to see if the Network already exists (by name).
 
 317             // For HEAT orchestration of networks, the stack name will always match the network name
 
 318             StackInfo heatStack = null;
 
 320                 heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkName);
 
 321             } catch (MsoException me) {
 
 322                 me.addContext(CREATE_NETWORK_CONTEXT);
 
 323                 logger.error("{} {} Create Network (heat): query network {} in {}/{}: ",
 
 324                         MessageEnum.RA_QUERY_NETWORK_EXC, ErrorCode.DataError.getValue(), networkName, cloudSiteId,
 
 326                 throw new NetworkException(me);
 
 329             if (heatStack != null && (heatStack.getStatus() != HeatStatus.NOTFOUND)) {
 
 330                 // Stack exists. Return success or error depending on input directive
 
 331                 if (failIfExists != null && failIfExists) {
 
 332                     String error = String.format("CreateNetwork: Stack %s already exists in %s/%s as %s", networkName,
 
 333                             cloudSiteId, tenantId, heatStack.getCanonicalName());
 
 334                     logger.error(LoggingAnchor.THREE, MessageEnum.RA_NETWORK_ALREADY_EXIST,
 
 335                             ErrorCode.DataError.getValue(), error);
 
 336                     throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 338                     // Populate the outputs from the existing stack.
 
 339                     networkId.value = heatStack.getCanonicalName();
 
 340                     Map<String, String> sMap = new HashMap<>();
 
 341                     if (heatStack.getOutputs() != null) {
 
 342                         neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
 
 343                         rollback.value = networkRollback; // Default rollback - no updates performed
 
 345                             networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
 
 347                         Map<String, Object> outputs = heatStack.getOutputs();
 
 349                         for (Map.Entry<String, Object> entry : outputs.entrySet()) {
 
 350                             String key = entry.getKey();
 
 351                             if (key != null && key.startsWith("subnet")) {
 
 352                                 if (aic3template) // one subnet_id output
 
 354                                     Map<String, String> map = getSubnetUUId(key, outputs, subnets);
 
 356                                 } else // multiples subnet_%aaid% outputs
 
 358                                     String subnetUUId = (String) outputs.get(key);
 
 359                                     sMap.put(key.substring("subnet_id_".length()), subnetUUId);
 
 364                     subnetIdMap.value = sMap;
 
 365                     logger.warn("{} {} Found Existing network stack, status={} networkName={} for {}/{}",
 
 366                             MessageEnum.RA_NETWORK_ALREADY_EXIST, ErrorCode.DataError.getValue(), heatStack.getStatus(),
 
 367                             networkName, cloudSiteId, tenantId);
 
 369                 heat.updateResourceStatus(msoRequest.getRequestId(), NETWORK_EXIST_STATUS_MESSAGE);
 
 373             // Ready to deploy the new Network
 
 374             // Build the common set of HEAT template parameters
 
 375             Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType, networkName,
 
 376                     physicalNetworkName, vlans, routeTargets, shared, external, aic3template);
 
 378             // Validate (and update) the input parameters against the DB definition
 
 379             // Shouldn't happen unless DB config is wrong, since all networks use same inputs
 
 380             // and inputs were already validated.
 
 382                 stackParams = heat.validateStackParams(stackParams, heatTemplate);
 
 383             } catch (IllegalArgumentException e) {
 
 384                 String error = "Create Network: Configuration Error: " + e.getMessage();
 
 385                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error, e);
 
 386                 // Input parameters were not valid
 
 387                 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
 
 390             if (subnets != null) {
 
 393                         template = mergeSubnetsAIC3(template, subnets, stackParams);
 
 395                         template = mergeSubnets(template, subnets);
 
 397                 } catch (MsoException me) {
 
 398                     me.addContext(CREATE_NETWORK_CONTEXT);
 
 399                     logger.error("{} {} Exception Create Network, merging subnets for network (heat) type {} in {}/{} ",
 
 400                             MessageEnum.RA_CREATE_NETWORK_EXC, ErrorCode.DataError.getValue(),
 
 401                             neutronNetworkType.toString(), cloudSiteId, tenantId, me);
 
 402                     throw new NetworkException(me);
 
 406             if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
 
 408                     mergePolicyRefs(policyFqdns, stackParams);
 
 409                 } catch (MsoException me) {
 
 410                     me.addContext(CREATE_NETWORK_CONTEXT);
 
 411                     logger.error("{} {} Exception Create Network, merging policyRefs type {} in {}/{} ",
 
 412                             MessageEnum.RA_CREATE_NETWORK_EXC, ErrorCode.DataError.getValue(),
 
 413                             neutronNetworkType.toString(), cloudSiteId, tenantId, me);
 
 414                     throw new NetworkException(me);
 
 418             if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
 
 420                     mergeRouteTableRefs(routeTableFqdns, stackParams);
 
 421                 } catch (MsoException me) {
 
 422                     me.addContext(CREATE_NETWORK_CONTEXT);
 
 423                     logger.error("{} {} Exception Create Network, merging routeTableRefs type {} in {}/{} ",
 
 424                             MessageEnum.RA_CREATE_NETWORK_EXC, ErrorCode.DataError.getValue(),
 
 425                             neutronNetworkType.toString(), cloudSiteId, tenantId, me);
 
 426                     throw new NetworkException(me);
 
 430             // Deploy the network stack
 
 431             // Ignore MsoStackAlreadyExists exception because we already checked.
 
 435                 heatStack = heat.createStack(cloudSiteId, CLOUD_OWNER, tenantId, networkName, null, template,
 
 436                         stackParams, true, heatTemplate.getTimeoutMinutes(), null, null, null, backout.booleanValue(),
 
 438             } catch (MsoException me) {
 
 439                 me.addContext(CREATE_NETWORK_CONTEXT);
 
 440                 logger.error("{} {} Exception creating network type {} in {}/{} ", MessageEnum.RA_CREATE_NETWORK_EXC,
 
 441                         ErrorCode.DataError.getValue(), networkName, cloudSiteId, tenantId, me);
 
 442                 throw new NetworkException(me);
 
 445             // Reach this point if createStack is successful.
 
 447             // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
 
 448             // and the neutronNetworkId is the network UUID returned in stack outputs.
 
 449             networkId.value = heatStack.getCanonicalName();
 
 450             if (heatStack.getOutputs() != null) {
 
 451                 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
 
 453                     networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
 
 456             Map<String, Object> outputs = heatStack.getOutputs();
 
 457             Map<String, String> sMap = new HashMap<>();
 
 458             if (outputs != null) {
 
 459                 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
 
 460                     String key = entry.getKey();
 
 461                     if (key != null && key.startsWith("subnet")) {
 
 462                         if (aic3template) // one subnet output expected
 
 464                             Map<String, String> map = getSubnetUUId(key, outputs, subnets);
 
 466                         } else // multiples subnet_%aaid% outputs allowed
 
 468                             String subnetUUId = (String) outputs.get(key);
 
 469                             sMap.put(key.substring("subnet_id_".length()), subnetUUId);
 
 473                 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
 
 475             subnetIdMap.value = sMap;
 
 477             rollback.value = networkRollback;
 
 478             // Populate remaining rollback info and response parameters.
 
 479             networkRollback.setNetworkStackId(heatStack.getCanonicalName());
 
 480             networkRollback.setNetworkCreated(true);
 
 481             networkRollback.setNetworkType(networkType);
 
 484                 heat.updateResourceStatus(msoRequest.getRequestId(), NETWORK_CREATED_STATUS_MESSAGE);
 
 485             } catch (Exception e) {
 
 486                 logger.warn("Exception while updating infra active request", e);
 
 489             logger.debug("Network {} successfully created via HEAT", networkName);
 
 496     public void updateNetwork(String cloudSiteId, String tenantId, String networkType, String modelCustomizationUuid,
 
 497             String networkId, String networkName, String physicalNetworkName, List<Integer> vlans, String shared,
 
 498             String external, List<Subnet> subnets, Map<String, String> networkParams, MsoRequest msoRequest,
 
 499             Holder<Map<String, String>> subnetIdMap, Holder<NetworkRollback> rollback) throws NetworkException {
 
 500         updateNetwork(cloudSiteId, tenantId, networkType, modelCustomizationUuid, networkId, networkName,
 
 501                 physicalNetworkName, vlans, null, shared, external, subnets, null, null, msoRequest, subnetIdMap,
 
 507     public void updateNetworkContrail(String cloudSiteId, String tenantId, String networkType,
 
 508             String modelCustomizationUuid, String networkId, String networkName, List<RouteTarget> routeTargets,
 
 509             String shared, String external, List<Subnet> subnets, Map<String, String> networkParams,
 
 510             List<String> policyFqdns, List<String> routeTableFqdns, MsoRequest msoRequest,
 
 511             Holder<Map<String, String>> subnetIdMap, Holder<NetworkRollback> rollback) throws NetworkException {
 
 512         updateNetwork(cloudSiteId, tenantId, networkType, modelCustomizationUuid, networkId, networkName, null, null,
 
 513                 routeTargets, shared, external, subnets, policyFqdns, routeTableFqdns, msoRequest, subnetIdMap,
 
 518      * This is the "Update Network" web service implementation. It will update an existing Network of the requested type
 
 519      * in the specified cloud and tenant. The typical use will be to replace the VLANs with the supplied list (to add or
 
 520      * remove a VLAN), but other properties may be updated as well.
 
 522      * There will be a pre-defined set of network types defined in the MSO Catalog. All such networks will have a
 
 523      * similar configuration, based on the allowable Openstack networking definitions. This includes basic networks,
 
 524      * provider networks (with a single VLAN), and multi-provider networks (one or more VLANs).
 
 526      * Initially, all provider networks must currently be "vlan" type, and multi-provider networks must be multiple
 
 527      * VLANs on the same physical network.
 
 529      * This service supports two modes of Network update: - via Heat Templates - via Neutron API The network
 
 530      * orchestration mode for each network type is declared in its catalog definition. All Heat-based templates must
 
 531      * support some subset of the same input parameters: network_name, physical_network, vlan, segments.
 
 533      * The method returns a NetworkRollback object. This object can be passed as-is to the rollbackNetwork operation to
 
 534      * undo everything that was updated. This is useful if a network is successfully updated but orchestration fails on
 
 535      * a subsequent operation.
 
 537     private void updateNetwork(String cloudSiteId, String tenantId, String networkType, String modelCustomizationUuid,
 
 538             String networkId, String networkName, String physicalNetworkName, List<Integer> vlans,
 
 539             List<RouteTarget> routeTargets, String shared, String external, List<Subnet> subnets,
 
 540             List<String> policyFqdns, List<String> routeTableFqdns, MsoRequest msoRequest,
 
 541             Holder<Map<String, String>> subnetIdMap, Holder<NetworkRollback> rollback) throws NetworkException {
 
 543         logger.debug("***UPDATE Network adapter with Network: {} of type {} in {}/{}", networkName, networkType,
 
 544                 cloudSiteId, tenantId);
 
 546         // Will capture execution time for metrics
 
 547         long startTime = System.currentTimeMillis();
 
 549         // Build a default rollback object (no actions performed)
 
 550         NetworkRollback networkRollback = new NetworkRollback();
 
 551         networkRollback.setCloudId(cloudSiteId);
 
 552         networkRollback.setTenantId(tenantId);
 
 553         networkRollback.setMsoRequest(msoRequest);
 
 555         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
 
 556         if (!cloudSiteOpt.isPresent()) {
 
 557             String error = String.format(
 
 558                     "UpdateNetwork: Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
 
 559                     networkName, cloudSiteId, tenantId);
 
 560             logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
 
 561             // Set the detailed error as the Exception 'message'
 
 562             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 567         NetworkResource networkResource = networkCheck(startTime, networkType, modelCustomizationUuid, networkName,
 
 568                 physicalNetworkName, vlans, routeTargets, cloudSiteId, cloudSiteOpt.get());
 
 569         String mode = networkResource.getOrchestrationMode();
 
 570         NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
 
 572         // Use an MsoNeutronUtils for all Neutron commands
 
 574         if (NEUTRON_MODE.equals(mode)) {
 
 576             // Verify that the Network exists
 
 577             // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
 
 578             NetworkInfo netInfo = null;
 
 580                 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
 
 581             } catch (MsoException me) {
 
 582                 me.addContext(UPDATE_NETWORK_CONTEXT);
 
 583                 logger.error("{} {} Exception - queryNetwork query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
 
 584                         ErrorCode.BusinessProcessError.getValue(), networkId, cloudSiteId, tenantId, me);
 
 585                 throw new NetworkException(me);
 
 588             if (netInfo == null) {
 
 589                 String error = String.format("Update Nework: Network %s does not exist in %s/%s", networkId,
 
 590                         cloudSiteId, tenantId);
 
 591                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_NETWORK_NOT_FOUND,
 
 592                         ErrorCode.BusinessProcessError.getValue(), error);
 
 593                 // Does not exist. Throw an exception (can't update a non-existent network)
 
 594                 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 596             long updateNetworkStarttime = System.currentTimeMillis();
 
 598                 netInfo = neutron.updateNetwork(cloudSiteId, tenantId, networkId, neutronNetworkType,
 
 599                         physicalNetworkName, vlans);
 
 600             } catch (MsoException me) {
 
 601                 me.addContext(UPDATE_NETWORK_CONTEXT);
 
 602                 logger.error("{} {} Exception - updateNetwork {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
 
 603                         ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
 
 604                 throw new NetworkException(me);
 
 607             // Add the network ID and previously queried vlans to the rollback object
 
 608             networkRollback.setNetworkId(netInfo.getId());
 
 609             networkRollback.setNeutronNetworkId(netInfo.getId());
 
 610             networkRollback.setNetworkType(networkType);
 
 611             // Save previous parameters
 
 612             networkRollback.setNetworkName(netInfo.getName());
 
 613             networkRollback.setPhysicalNetwork(netInfo.getProvider());
 
 614             networkRollback.setVlans(netInfo.getVlans());
 
 616             logger.debug("Network {} updated, id = {}", networkId, netInfo.getId());
 
 617         } else if ("HEAT".equals(mode)) {
 
 619             // First, look up to see that the Network already exists.
 
 620             // For Heat-based orchestration, the networkId is the network Stack ID.
 
 621             StackInfo heatStack = null;
 
 623                 heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkName);
 
 624             } catch (MsoException me) {
 
 625                 me.addContext(UPDATE_NETWORK_CONTEXT);
 
 626                 logger.error("{} {} Exception - QueryStack query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
 
 627                         ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
 
 628                 throw new NetworkException(me);
 
 631             if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
 
 632                 String error = String.format("UpdateNetwork: Stack %s does not exist in %s/%s", networkName,
 
 633                         cloudSiteId, tenantId);
 
 634                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_NETWORK_NOT_FOUND, ErrorCode.DataError.getValue(),
 
 636                 // Network stack does not exist. Return an error
 
 637                 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 640             // Get the previous parameters for rollback
 
 641             Map<String, Object> heatParams = heatStack.getParameters();
 
 643             String previousNetworkName = (String) heatParams.get("network_name");
 
 644             String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
 
 646             List<Integer> previousVlans = new ArrayList<>();
 
 647             String vlansParam = (String) heatParams.get(VLANS);
 
 648             if (vlansParam != null) {
 
 649                 for (String vlan : vlansParam.split(",")) {
 
 651                         previousVlans.add(Integer.parseInt(vlan));
 
 652                     } catch (NumberFormatException e) {
 
 653                         logger.warn("{} {} Exception - VLAN parse for params {} ", MessageEnum.RA_VLAN_PARSE,
 
 654                                 ErrorCode.DataError.getValue(), vlansParam, e);
 
 658             logger.debug("Update Stack:  Previous VLANS: {}", previousVlans);
 
 660             // Ready to deploy the updated Network via Heat
 
 663             HeatTemplate heatTemplate = networkResource.getHeatTemplate();
 
 664             if (heatTemplate == null) {
 
 665                 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
 
 666                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_PARAM_NOT_FOUND, ErrorCode.DataError.getValue(),
 
 668                 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
 
 671             logger.debug("Got HEAT Template from DB: {}", heatTemplate);
 
 673             // "Fix" the template if it has CR/LF (getting this from Oracle)
 
 674             String template = heatTemplate.getHeatTemplate();
 
 675             template = template.replaceAll("\r\n", "\n");
 
 677             boolean aic3template = false;
 
 678             String aic3nw = AIC3_NW;
 
 680             aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
 
 682             if (template.contains(aic3nw))
 
 685             // Build the common set of HEAT template parameters
 
 686             Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType, networkName,
 
 687                     physicalNetworkName, vlans, routeTargets, shared, external, aic3template);
 
 689             // Validate (and update) the input parameters against the DB definition
 
 690             // Shouldn't happen unless DB config is wrong, since all networks use same inputs
 
 692                 stackParams = heat.validateStackParams(stackParams, heatTemplate);
 
 693             } catch (IllegalArgumentException e) {
 
 694                 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
 
 695                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
 
 696                 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
 
 699             if (subnets != null) {
 
 702                         template = mergeSubnetsAIC3(template, subnets, stackParams);
 
 704                         template = mergeSubnets(template, subnets);
 
 706                 } catch (MsoException me) {
 
 707                     me.addContext(UPDATE_NETWORK_CONTEXT);
 
 708                     logger.error("{} {} Exception - UpdateNetwork mergeSubnets for network type {} in {}/{} ",
 
 709                             MessageEnum.RA_UPDATE_NETWORK_ERR, ErrorCode.DataError.getValue(),
 
 710                             neutronNetworkType.toString(), cloudSiteId, tenantId, me);
 
 711                     throw new NetworkException(me);
 
 715             if (policyFqdns != null && aic3template) {
 
 717                     mergePolicyRefs(policyFqdns, stackParams);
 
 718                 } catch (MsoException me) {
 
 719                     me.addContext(UPDATE_NETWORK_CONTEXT);
 
 720                     logger.error("{} {} Exception - UpdateNetwork mergePolicyRefs type {} in {}/{} ",
 
 721                             MessageEnum.RA_UPDATE_NETWORK_ERR, ErrorCode.DataError.getValue(),
 
 722                             neutronNetworkType.toString(), cloudSiteId, tenantId, me);
 
 723                     throw new NetworkException(me);
 
 727             if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
 
 729                     mergeRouteTableRefs(routeTableFqdns, stackParams);
 
 730                 } catch (MsoException me) {
 
 731                     me.addContext(UPDATE_NETWORK_CONTEXT);
 
 732                     logger.error("{} {} Exception - UpdateNetwork mergeRouteTableRefs type {} in {}/{} ",
 
 733                             MessageEnum.RA_UPDATE_NETWORK_ERR, ErrorCode.DataError.getValue(),
 
 734                             neutronNetworkType.toString(), cloudSiteId, tenantId, me);
 
 735                     throw new NetworkException(me);
 
 739             // Update the network stack
 
 740             // Ignore MsoStackNotFound exception because we already checked.
 
 742                 heatStack = heatWithUpdate.updateStack(cloudSiteId, CLOUD_OWNER, tenantId, networkId, template,
 
 743                         stackParams, true, heatTemplate.getTimeoutMinutes());
 
 744             } catch (MsoException me) {
 
 745                 me.addContext(UPDATE_NETWORK_CONTEXT);
 
 746                 logger.error("{} {} Exception - update network {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
 
 747                         ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
 
 748                 throw new NetworkException(me);
 
 751             Map<String, Object> outputs = heatStack.getOutputs();
 
 752             Map<String, String> sMap = new HashMap<>();
 
 753             if (outputs != null) {
 
 754                 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
 
 755                     String key = entry.getKey();
 
 756                     if (key != null && key.startsWith("subnet")) {
 
 757                         if (aic3template) // one subnet output expected
 
 759                             Map<String, String> map = getSubnetUUId(key, outputs, subnets);
 
 761                         } else // multiples subnet_%aaid% outputs allowed
 
 763                             String subnetUUId = (String) outputs.get(key);
 
 764                             sMap.put(key.substring("subnet_id_".length()), subnetUUId);
 
 769             subnetIdMap.value = sMap;
 
 771             // Reach this point if createStack is successful.
 
 772             // Populate remaining rollback info and response parameters.
 
 773             networkRollback.setNetworkStackId(heatStack.getCanonicalName());
 
 774             if (null != outputs) {
 
 775                 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
 
 777                 logger.debug("outputs is NULL");
 
 779             networkRollback.setNetworkType(networkType);
 
 780             // Save previous parameters
 
 781             networkRollback.setNetworkName(previousNetworkName);
 
 782             networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
 
 783             networkRollback.setVlans(previousVlans);
 
 785             rollback.value = networkRollback;
 
 787             logger.debug("Network {} successfully updated via HEAT", networkId);
 
 793     private NetworkResource networkCheck(long startTime, String networkType, String modelCustomizationUuid,
 
 794             String networkName, String physicalNetworkName, List<Integer> vlans, List<RouteTarget> routeTargets,
 
 795             String cloudSiteId, CloudSite cloudSite) throws NetworkException {
 
 796         // Retrieve the Network Resource definition
 
 797         NetworkResource networkResource = null;
 
 798         NetworkResourceCustomization networkCust = null;
 
 799         CollectionNetworkResourceCustomization collectionNetworkCust = null;
 
 800         if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
 
 801             if (!commonUtils.isNullOrEmpty(networkType)) {
 
 802                 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
 
 805             networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
 
 806             if (networkCust == null) {
 
 807                 collectionNetworkCust =
 
 808                         collectionNetworkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
 
 811         if (networkCust != null) {
 
 812             logger.debug("Got Network Customization definition from Catalog: {}", networkCust);
 
 814             networkResource = networkCust.getNetworkResource();
 
 815         } else if (collectionNetworkCust != null) {
 
 816             logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}", collectionNetworkCust);
 
 817             networkResource = collectionNetworkCust.getNetworkResource();
 
 819         if (networkResource == null) {
 
 820             String error = String.format(
 
 821                     "Create/UpdateNetwork: Unable to get network resource with NetworkType: %s or ModelCustomizationUUID:%s",
 
 822                     networkType, modelCustomizationUuid);
 
 823             logger.error(LoggingAnchor.THREE, MessageEnum.RA_UNKOWN_PARAM, ErrorCode.DataError.getValue(), error);
 
 825             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 827         logger.debug(LOG_DEBUG_MSG, networkResource);
 
 829         String mode = networkResource.getOrchestrationMode();
 
 830         NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
 
 832         // All Networks are orchestrated via HEAT or Neutron
 
 833         if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
 
 834             String error = "CreateNetwork: Configuration Error: Network Type = " + networkType;
 
 835             logger.error(LoggingAnchor.THREE, MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
 
 836                     ErrorCode.DataError.getValue(), error);
 
 837             throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
 
 840         MavenLikeVersioning aicV = new MavenLikeVersioning();
 
 841         aicV.setVersion(cloudSite.getCloudVersion());
 
 842         if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin())
 
 843                 || aicV.isTheSameVersion(networkResource.getAicVersionMin())) // aic
 
 846                 && (aicV.isTheSameVersion(networkResource.getAicVersionMax())
 
 847                         || !(aicV.isMoreRecentThan(networkResource.getAicVersionMax())))) // aic <= max
 
 849             logger.debug("Network Type:{} VersionMin:{} VersionMax:{} supported on Cloud:{} with AIC_Version:{}",
 
 850                     networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId,
 
 851                     cloudSite.getCloudVersion());
 
 853             String error = String.format(
 
 854                     "Network Type:%s Version_Min:%s Version_Max:%s not supported on Cloud:%s with AIC_Version:%s",
 
 855                     networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId,
 
 856                     cloudSite.getCloudVersion());
 
 857             logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
 
 858             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 861         // Validate the Network parameters.
 
 863                 validateNetworkParams(neutronNetworkType, networkName, physicalNetworkName, vlans, routeTargets);
 
 864         if (!missing.isEmpty()) {
 
 865             String error = "Create Network: Missing parameters: " + missing;
 
 866             logger.error(LoggingAnchor.THREE, MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
 
 868             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 871         return networkResource;
 
 875     public void queryNetwork(String cloudSiteId, String tenantId, String networkNameOrId, MsoRequest msoRequest,
 
 876             Holder<Boolean> networkExists, Holder<String> networkId, Holder<String> neutronNetworkId,
 
 877             Holder<NetworkStatus> status, Holder<List<Integer>> vlans, Holder<Map<String, String>> subnetIdMap)
 
 878             throws NetworkException {
 
 879         queryNetwork(cloudSiteId, tenantId, networkNameOrId, msoRequest, networkExists, networkId, neutronNetworkId,
 
 880                 status, vlans, null, subnetIdMap);
 
 884     public void queryNetworkContrail(String cloudSiteId, String tenantId, String networkNameOrId, MsoRequest msoRequest,
 
 885             Holder<Boolean> networkExists, Holder<String> networkId, Holder<String> neutronNetworkId,
 
 886             Holder<NetworkStatus> status, Holder<List<RouteTarget>> routeTargets,
 
 887             Holder<Map<String, String>> subnetIdMap) throws NetworkException {
 
 888         queryNetwork(cloudSiteId, tenantId, networkNameOrId, msoRequest, networkExists, networkId, neutronNetworkId,
 
 889                 status, null, routeTargets, subnetIdMap);
 
 893      * This is the queryNetwork method. It returns the existence and status of the specified network, along with its
 
 894      * Neutron UUID and list of VLANs. This method attempts to find the network using both Heat and Neutron. Heat stacks
 
 895      * are first searched based on the provided network name/id. If none is found, the Neutron is directly queried.
 
 897     private void queryNetwork(String cloudSiteId, String tenantId, String networkNameOrId, MsoRequest msoRequest,
 
 898             Holder<Boolean> networkExists, Holder<String> networkId, Holder<String> neutronNetworkId,
 
 899             Holder<NetworkStatus> status, Holder<List<Integer>> vlans, Holder<List<RouteTarget>> routeTargets,
 
 900             Holder<Map<String, String>> subnetIdMap) throws NetworkException {
 
 902         logger.debug("*** QUERY Network with Network: {} in {}/{}", networkNameOrId, cloudSiteId, tenantId);
 
 904         if (commonUtils.isNullOrEmpty(cloudSiteId) || commonUtils.isNullOrEmpty(tenantId)
 
 905                 || commonUtils.isNullOrEmpty(networkNameOrId)) {
 
 907             String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
 
 908             logger.error(LoggingAnchor.THREE, MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
 
 909             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 912         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
 
 913         if (!cloudSiteOpt.isPresent()) {
 
 914             String error = String.format(
 
 915                     "Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
 
 916                     networkNameOrId, cloudSiteId, tenantId);
 
 917             logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
 
 918             // Set the detailed error as the Exception 'message'
 
 919             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
 922         // Use MsoNeutronUtils for all NEUTRON commands
 
 925         String neutronId = null;
 
 926         // Try Heat first, since networks may be named the same as the Heat stack
 
 927         StackInfo heatStack = null;
 
 929             heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkNameOrId);
 
 930         } catch (MsoException me) {
 
 931             me.addContext("QueryNetwork");
 
 932             logger.error("{} {} Exception - Query Network (heat): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
 
 933                     ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
 
 934             throw new NetworkException(me);
 
 937         // Populate the outputs based on the returned Stack information
 
 938         if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
 
 939             // Found it. Get the neutronNetworkId for further query
 
 940             Map<String, String> sMap = new HashMap<>();
 
 941             Map<String, Object> outputs = heatStack.getOutputs();
 
 943             if (outputs != null) {
 
 944                 neutronId = (String) outputs.get(NETWORK_ID);
 
 946                 for (String key : outputs.keySet()) {
 
 947                     if (key != null && key.startsWith("subnet_id_")) // multiples subnet_%aaid% outputs
 
 949                         String subnetUUId = (String) outputs.get(key);
 
 950                         sMap.put(key.substring("subnet_id_".length()), subnetUUId);
 
 951                     } else if (key != null && key.startsWith("subnet")) // one subnet output expected
 
 953                         Map<String, String> map = getSubnetUUId(key, outputs, null);
 
 959             subnetIdMap.value = sMap;
 
 961             // Input ID was not a Heat stack ID. Try it directly in Neutron
 
 962             neutronId = networkNameOrId;
 
 966         // Query directly against the Neutron Network for the details
 
 967         // no RouteTargets available for ContrailV2 in neutron net-show
 
 968         // networkId is heatStackId
 
 970             NetworkInfo netInfo = neutron.queryNetwork(neutronId, tenantId, cloudSiteId);
 
 971             if (netInfo != null) {
 
 972                 // Found. Populate the output elements
 
 973                 networkExists.value = Boolean.TRUE;
 
 974                 if ("HEAT".equals(mode) && heatStack != null) {
 
 975                     networkId.value = heatStack.getCanonicalName();
 
 977                     networkId.value = netInfo.getId();
 
 979                 neutronNetworkId.value = netInfo.getId();
 
 980                 status.value = netInfo.getStatus();
 
 982                     vlans.value = netInfo.getVlans();
 
 984                 logger.debug("Network {} found({}), ID = {}{}", networkNameOrId, mode, networkId.value,
 
 985                         ("HEAT".equals(mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
 
 987                 // Not found. Populate the status fields, leave the rest null
 
 988                 networkExists.value = Boolean.FALSE;
 
 989                 status.value = NetworkStatus.NOTFOUND;
 
 990                 neutronNetworkId.value = null;
 
 992                     vlans.value = new ArrayList<>();
 
 994                 logger.debug("Network {} not found", networkNameOrId);
 
 996         } catch (MsoException me) {
 
 997             me.addContext("QueryNetwork");
 
 998             logger.error("{} {} Exception - Query Network (neutron): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
 
 999                     ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
 
1000             throw new NetworkException(me);
 
1006      * This is the "Delete Network" web service implementation. It will delete a Network in the specified cloud and
 
1009      * If the network is not found, it is treated as a success.
 
1011      * This service supports two modes of Network creation/update/delete: - via Heat Templates - via Neutron API The
 
1012      * network orchestration mode for each network type is declared in its catalog definition.
 
1014      * For Heat-based orchestration, the networkId should be the stack ID. For Neutron-based orchestration, the
 
1015      * networkId should be the Neutron network UUID.
 
1017      * The method returns nothing on success. Rollback is not possible for delete commands, so any failure on delete
 
1018      * will require manual fallout in the client.
 
1021     public void deleteNetwork(String cloudSiteId, String tenantId, String networkType, String modelCustomizationUuid,
 
1022             String networkId, MsoRequest msoRequest, Holder<Boolean> networkDeleted) throws NetworkException {
 
1023         logger.debug("*** DELETE Network adapter with Network: {} in {}/{}", networkId, cloudSiteId, tenantId);
 
1024         if (commonUtils.isNullOrEmpty(cloudSiteId) || commonUtils.isNullOrEmpty(tenantId)
 
1025                 || commonUtils.isNullOrEmpty(networkId)) {
 
1026             String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
 
1027             logger.error(LoggingAnchor.THREE, MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
 
1028             throw new NetworkException(error, MsoExceptionCategory.USERDATA);
 
1031         // Retrieve the Network Resource definition
 
1032         NetworkResource networkResource = null;
 
1033         if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
 
1034             if (!commonUtils.isNullOrEmpty(networkType)) {
 
1035                 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
 
1038             NetworkResourceCustomization nrc =
 
1039                     networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
 
1041                 networkResource = nrc.getNetworkResource();
 
1045         int timeoutMinutes = 118;
 
1047         if (networkResource != null) {
 
1048             logger.debug(LOG_DEBUG_MSG, networkResource.toString());
 
1049             mode = networkResource.getOrchestrationMode();
 
1050             networkResource.getHeatTemplate().getTimeoutMinutes();
 
1051             HeatTemplate heat = networkResource.getHeatTemplate();
 
1052             if (heat != null && heat.getTimeoutMinutes() != null) {
 
1053                 if (heat.getTimeoutMinutes() < 118) {
 
1054                     timeoutMinutes = heat.getTimeoutMinutes();
 
1059         if (NEUTRON_MODE.equals(mode)) {
 
1061                 boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
 
1062                 networkDeleted.value = deleted;
 
1063             } catch (MsoException me) {
 
1064                 me.addContext("DeleteNetwork");
 
1065                 logger.error("{} {} Delete Network (neutron): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
 
1066                         ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
 
1067                 throw new NetworkException(me);
 
1071                 StackInfo stack = heat.deleteStack(tenantId, CLOUD_OWNER, cloudSiteId, networkId, true, timeoutMinutes);
 
1072                 networkDeleted.value = stack.isOperationPerformed();
 
1073             } catch (MsoException me) {
 
1074                 me.addContext("DeleteNetwork");
 
1075                 logger.error("{} {} Delete Network (heat): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
 
1076                         ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
 
1077                 throw new NetworkException(me);
 
1081             heat.updateResourceStatus(msoRequest.getRequestId(),
 
1082                     networkDeleted.value ? NETWORK_DELETED_STATUS_MESSAGE : NETWORK_NOT_EXIST_STATUS_MESSAGE);
 
1083         } catch (Exception e) {
 
1084             logger.warn("Exception while updating infra active request", e);
 
1089      * This web service endpoint will rollback a previous Create VNF operation. A rollback object is returned to the
 
1090      * client in a successful creation response. The client can pass that object as-is back to the rollbackVnf operation
 
1091      * to undo the creation.
 
1093      * The rollback includes removing the VNF and deleting the tenant if the tenant did not exist prior to the VNF
 
1097     public void rollbackNetwork(NetworkRollback rollback) throws NetworkException {
 
1098         if (rollback == null) {
 
1099             logger.error("{} {} rollback is null", MessageEnum.RA_ROLLBACK_NULL, ErrorCode.DataError.getValue());
 
1103         // Get the elements of the VnfRollback object for easier access
 
1104         String cloudSiteId = rollback.getCloudId();
 
1105         String tenantId = rollback.getTenantId();
 
1106         String networkId = rollback.getNetworkStackId();
 
1107         String networkType = rollback.getNetworkType();
 
1108         String modelCustomizationUuid = rollback.getModelCustomizationUuid();
 
1110         logger.debug("*** ROLLBACK Network {} in {}/{}", networkId, cloudSiteId, tenantId);
 
1111         // Retrieve the Network Resource definition
 
1112         NetworkResource networkResource = null;
 
1113         if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
 
1114             networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource();
 
1117                     networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource();
 
1120         if (networkResource != null) {
 
1122             logger.debug(LOG_DEBUG_MSG, networkResource);
 
1124             mode = networkResource.getOrchestrationMode();
 
1127         if (rollback.getNetworkCreated()) {
 
1128             if (NEUTRON_MODE.equals(mode)) {
 
1130                     neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
 
1131                 } catch (MsoException me) {
 
1132                     me.addContext("RollbackNetwork");
 
1133                     logger.error("{} {} Exception - Rollback Network (neutron): {} in {}/{} ",
 
1134                             MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcessError.getValue(), networkId,
 
1135                             cloudSiteId, tenantId, me);
 
1136                     throw new NetworkException(me);
 
1140                     heat.deleteStack(tenantId, CLOUD_OWNER, cloudSiteId, networkId, true, 120);
 
1141                 } catch (MsoException me) {
 
1142                     me.addContext("RollbackNetwork");
 
1143                     logger.error("{} {} Exception - Rollback Network (heat): {} in {}/{} ",
 
1144                             MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcessError.getValue(), networkId,
 
1145                             cloudSiteId, tenantId, me);
 
1146                     throw new NetworkException(me);
 
1152     private String validateNetworkParams(NetworkType neutronNetworkType, String networkName, String physicalNetwork,
 
1153             List<Integer> vlans, List<RouteTarget> routeTargets) {
 
1155         StringBuilder missing = new StringBuilder();
 
1156         if (commonUtils.isNullOrEmpty(networkName)) {
 
1157             missing.append("networkName");
 
1161         if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
 
1162             if (commonUtils.isNullOrEmpty(physicalNetwork)) {
 
1163                 missing.append(sep).append("physicalNetworkName");
 
1166             if (vlans == null || vlans.isEmpty()) {
 
1167                 missing.append(sep).append(VLANS);
 
1171         return missing.toString();
 
1174     private Map<String, Object> populateNetworkParams(NetworkType neutronNetworkType, String networkName,
 
1175             String physicalNetwork, List<Integer> vlans, List<RouteTarget> routeTargets, String shared, String external,
 
1176             boolean aic3template) {
 
1177         // Build the common set of HEAT template parameters
 
1178         Map<String, Object> stackParams = new HashMap<>();
 
1179         stackParams.put("network_name", networkName);
 
1181         if (neutronNetworkType == NetworkType.PROVIDER) {
 
1182             // For Provider type
 
1183             stackParams.put(PHYSICAL_NETWORK, physicalNetwork);
 
1184             stackParams.put("vlan", vlans.get(0).toString());
 
1185         } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
 
1186             // For Multi-provider, PO supports a custom resource extension of ProviderNet.
 
1187             // It supports all ProviderNet properties except segmentation_id, and adds a
 
1188             // comma-separated-list of VLANs as a "segments" property.
 
1189             // Note that this does not match the Neutron definition of Multi-Provider network,
 
1190             // which contains a list of 'segments', each having physical_network, network_type,
 
1191             // and segmentation_id.
 
1192             StringBuilder buf = new StringBuilder();
 
1194             for (Integer vlan : vlans) {
 
1195                 buf.append(sep).append(vlan.toString());
 
1198             String csl = buf.toString();
 
1200             stackParams.put(PHYSICAL_NETWORK, physicalNetwork);
 
1201             stackParams.put(VLANS, csl);
 
1203         if (routeTargets != null) {
 
1205             String rtGlobal = "";
 
1206             String rtImport = "";
 
1207             String rtExport = "";
 
1209             for (RouteTarget rt : routeTargets) {
 
1210                 boolean rtIsNull = false;
 
1212                     String routeTarget = rt.getRouteTarget();
 
1213                     String routeTargetRole = rt.getRouteTargetRole();
 
1214                     logger.debug("Checking for an actually null route target: {}", rt);
 
1215                     if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
 
1217                     if (routeTargetRole == null || routeTargetRole.equals("")
 
1218                             || routeTargetRole.equalsIgnoreCase("null"))
 
1224                     logger.debug("Input RT:{}", rt);
 
1225                     String role = rt.getRouteTargetRole();
 
1226                     String rtValue = rt.getRouteTarget();
 
1228                     if ("IMPORT".equalsIgnoreCase(role)) {
 
1229                         sep = rtImport.isEmpty() ? "" : ",";
 
1230                         rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue;
 
1231                     } else if ("EXPORT".equalsIgnoreCase(role)) {
 
1232                         sep = rtExport.isEmpty() ? "" : ",";
 
1233                         rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue;
 
1234                     } else // covers BOTH, empty etc
 
1236                         sep = rtGlobal.isEmpty() ? "" : ",";
 
1237                         rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue;
 
1243             if (!rtImport.isEmpty()) {
 
1244                 stackParams.put("route_targets_import", rtImport);
 
1246             if (!rtExport.isEmpty()) {
 
1247                 stackParams.put("route_targets_export", rtExport);
 
1249             if (!rtGlobal.isEmpty()) {
 
1250                 stackParams.put("route_targets", rtGlobal);
 
1253         if (commonUtils.isNullOrEmpty(shared)) {
 
1254             stackParams.put("shared", "False");
 
1256             stackParams.put("shared", shared);
 
1258         if (commonUtils.isNullOrEmpty(external)) {
 
1259             stackParams.put("external", "False");
 
1261             stackParams.put("external", external);
 
1269      * policyRef_list structure in stackParams [ { "network_policy_refs_data_sequence": {
 
1270      * "network_policy_refs_data_sequence_major": "1", "network_policy_refs_data_sequence_minor": "0" } }, {
 
1271      * "network_policy_refs_data_sequence": { "network_policy_refs_data_sequence_major": "2",
 
1272      * "network_policy_refs_data_sequence_minor": "0" } } ]
 
1274     private void mergePolicyRefs(List<String> pFqdns, Map<String, Object> stackParams) throws MsoException {
 
1275         // Resource Property
 
1276         List<ContrailPolicyRef> prlist = new ArrayList<>();
 
1279         if (pFqdns != null) {
 
1280             for (String pf : pFqdns) {
 
1281                 if (!commonUtils.isNullOrEmpty(pf)) {
 
1282                     ContrailPolicyRef pr = new ContrailPolicyRef();
 
1283                     ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0");
 
1286                     logger.debug("Contrail PolicyRefs Data:{}", pr);
 
1291             String error = "Null pFqdns at start of mergePolicyRefs";
 
1292             logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcessError.getValue(),
 
1294             throw new MsoAdapterException(error);
 
1297         JsonNode node = null;
 
1299             ObjectMapper mapper = new ObjectMapper();
 
1300             node = mapper.convertValue(prlist, JsonNode.class);
 
1301             String jsonString = mapper.writeValueAsString(prlist);
 
1302             logger.debug("Json PolicyRefs Data:{}", jsonString);
 
1303         } catch (Exception e) {
 
1304             String error = "Error creating JsonNode for policyRefs Data";
 
1305             logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcessError.getValue(),
 
1307             throw new MsoAdapterException(error);
 
1309         // update parameters
 
1310         if (pFqdns != null && node != null) {
 
1311             StringBuilder buf = new StringBuilder();
 
1313             for (String pf : pFqdns) {
 
1314                 if (!commonUtils.isNullOrEmpty(pf)) {
 
1315                     buf.append(sep).append(pf);
 
1319             String csl = buf.toString();
 
1320             stackParams.put("policy_refs", csl);
 
1321             stackParams.put("policy_refsdata", node);
 
1324         logger.debug("StackParams updated with policy refs");
 
1328     private void mergeRouteTableRefs(List<String> rtFqdns, Map<String, Object> stackParams) throws MsoException {
 
1330         // update parameters
 
1331         if (rtFqdns != null) {
 
1332             StringBuilder buf = new StringBuilder();
 
1334             for (String rtf : rtFqdns) {
 
1335                 if (!commonUtils.isNullOrEmpty(rtf)) {
 
1336                     buf.append(sep).append(rtf);
 
1340             String csl = buf.toString();
 
1341             stackParams.put("route_table_refs", csl);
 
1344         logger.debug("StackParams updated with route_table refs");
 
1350      * Subnet Output structure from Juniper { "ipam_subnets": [ { "subnet": { "ip_prefix": "10.100.1.0",
 
1351      * "ip_prefix_len": 28 }, "addr_from_start": null, "enable_dhcp": false, "default_gateway": "10.100.1.1",
 
1352      * "dns_nameservers": [], "dhcp_option_list": null, "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
 
1353      * "allocation_pools": [ { "start": "10.100.1.3", "end": "10.100.1.5" }, { "start": "10.100.1.6", "end":
 
1354      * "10.100.1.9" } ], "host_routes": null, "dns_server_address": "10.100.1.13", "subnet_name":
 
1355      * "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0" }, { "subnet": { "ip_prefix": "10.100.2.16",
 
1356      * "ip_prefix_len": 28 }, "addr_from_start": null, "enable_dhcp": true, "default_gateway": "10.100.2.17",
 
1357      * "dns_nameservers": [], "dhcp_option_list": null, "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
 
1358      * "allocation_pools": [ { "start": "10.100.2.18", "end": "10.100.2.20" } ], "host_routes": null,
 
1359      * "dns_server_address": "10.100.2.29", "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1" } ],
 
1360      * "host_routes": null }
 
1362     private String mergeSubnetsAIC3(String heatTemplate, List<Subnet> subnets, Map<String, Object> stackParams)
 
1363             throws MsoException {
 
1365         // Resource Property
 
1366         List<ContrailSubnet> cslist = new ArrayList<>();
 
1367         for (Subnet subnet : subnets) {
 
1368             logger.debug("Input Subnet:{}", subnet);
 
1369             ContrailSubnet cs = new ContrailSubnetMapper(subnet).map();
 
1370             logger.debug("Contrail Subnet:{}", cs);
 
1374         JsonNode node = null;
 
1376             ObjectMapper mapper = new ObjectMapper();
 
1377             node = mapper.convertValue(cslist, JsonNode.class);
 
1378             String jsonString = mapper.writeValueAsString(cslist);
 
1379             logger.debug("Json Subnet List:{}", jsonString);
 
1380         } catch (Exception e) {
 
1381             String error = "Error creating JsonNode from input subnets";
 
1382             logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.DataError.getValue(), error, e);
 
1383             throw new MsoAdapterException(error);
 
1385         // update parameters
 
1387             stackParams.put("subnet_list", node);
 
1389         // Outputs - All subnets are in one ipam_subnets structure
 
1390         String outputTempl = "  subnet:\n" + "    description: Openstack subnet identifier\n"
 
1391                 + "    value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
 
1393         // append outputs in heatTemplate
 
1394         int outputsIdx = heatTemplate.indexOf("outputs:");
 
1395         heatTemplate = insertStr(heatTemplate, outputTempl, outputsIdx + 8);
 
1396         logger.debug("Template updated with all AIC3.0 subnets:{}", heatTemplate);
 
1397         return heatTemplate;
 
1401     private String mergeSubnets(String heatTemplate, List<Subnet> subnets) throws MsoException {
 
1403         String resourceTempl = "  subnet_%subnetId%:\n" + "    type: OS::Neutron::Subnet\n" + "    properties:\n"
 
1404                 + "      name: %name%\n" + "      network_id: { get_resource: network }\n" + "      cidr: %cidr%\n";
 
1407          * make these optional + "      ip_version: %ipversion%\n" + "      enable_dhcp: %enabledhcp%\n" +
 
1408          * "      gateway_ip: %gatewayip%\n" + "      allocation_pools:\n" + "       - start: %poolstart%\n" +
 
1409          * "         end: %poolend%\n";
 
1413         String outputTempl = "  subnet_id_%subnetId%:\n" + "    description: Openstack subnet identifier\n"
 
1414                 + "    value: {get_resource: subnet_%subnetId%}\n";
 
1418         StringBuilder resourcesBuf = new StringBuilder();
 
1419         StringBuilder outputsBuf = new StringBuilder();
 
1420         for (Subnet subnet : subnets) {
 
1422             // build template for each subnet
 
1423             curR = resourceTempl;
 
1424             if (subnet.getSubnetId() != null) {
 
1425                 curR = curR.replace("%subnetId%", subnet.getSubnetId());
 
1427                 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
 
1428                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
 
1429                 throw new MsoAdapterException(error);
 
1432             if (subnet.getSubnetName() != null) {
 
1433                 curR = curR.replace("%name%", subnet.getSubnetName());
 
1435                 curR = curR.replace("%name%", subnet.getSubnetId());
 
1438             if (subnet.getCidr() != null) {
 
1439                 curR = curR.replace("%cidr%", subnet.getCidr());
 
1441                 String error = "Missing Required cidr for subnet in HEAT Template";
 
1442                 logger.error(LoggingAnchor.THREE, MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
 
1443                 throw new MsoAdapterException(error);
 
1446             if (subnet.getIpVersion() != null) {
 
1447                 curR = curR + "      ip_version: " + subnet.getIpVersion() + "\n";
 
1449             if (subnet.getEnableDHCP() != null) {
 
1450                 curR = curR + "      enable_dhcp: " + Boolean.toString(subnet.getEnableDHCP()) + "\n";
 
1452             if (subnet.getGatewayIp() != null && !subnet.getGatewayIp().isEmpty()) {
 
1453                 curR = curR + "      gateway_ip: " + subnet.getGatewayIp() + "\n";
 
1456             if (subnet.getAllocationPools() != null) {
 
1457                 StringBuilder tempBuf = new StringBuilder();
 
1458                 tempBuf.append(curR);
 
1459                 tempBuf.append("      allocation_pools:\n");
 
1460                 for (Pool pool : subnet.getAllocationPools()) {
 
1461                     if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd())) {
 
1462                         tempBuf.append("       - start: ");
 
1463                         tempBuf.append(pool.getStart());
 
1464                         tempBuf.append("\n         end: ");
 
1465                         tempBuf.append(pool.getEnd());
 
1466                         tempBuf.append("\n");
 
1469                 curR = tempBuf.toString();
 
1472             resourcesBuf.append(curR);
 
1475             curO = curO.replace("%subnetId%", subnet.getSubnetId());
 
1477             outputsBuf.append(curO);
 
1479         // append resources and outputs in heatTemplate
 
1480         logger.debug("Tempate initial:{}", heatTemplate);
 
1481         int outputsIdx = heatTemplate.indexOf("outputs:");
 
1482         heatTemplate = insertStr(heatTemplate, outputsBuf.toString(), outputsIdx + 8);
 
1483         int resourcesIdx = heatTemplate.indexOf("resources:");
 
1484         heatTemplate = insertStr(heatTemplate, resourcesBuf.toString(), resourcesIdx + 10);
 
1486         logger.debug("Template updated with all subnets:{}", heatTemplate);
 
1487         return heatTemplate;
 
1490     private Map<String, String> getSubnetUUId(String key, Map<String, Object> outputs, List<Subnet> subnets) {
 
1492         Map<String, String> sMap = new HashMap<>();
 
1495             Object obj = outputs.get(key);
 
1496             ObjectMapper mapper = new ObjectMapper();
 
1497             String jStr = mapper.writeValueAsString(obj);
 
1498             logger.debug("Subnet_Ipam Output JSON String:{} {}", obj.getClass(), jStr);
 
1500             JsonNode rootNode = mapper.readTree(jStr);
 
1501             if (rootNode != null) {
 
1502                 for (JsonNode sNode : rootNode.path("ipam_subnets")) {
 
1503                     logger.debug("Output Subnet Node {}", sNode);
 
1504                     String name = sNode.path("subnet_name").textValue();
 
1505                     String uuid = sNode.path("subnet_uuid").textValue();
 
1506                     String aaiId = name; // default
 
1507                     // try to find aaiId for name in input subnetList
 
1508                     if (subnets != null) {
 
1509                         for (Subnet subnet : subnets) {
 
1510                             if (subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName())
 
1511                                     && subnet.getSubnetName().equals(name)) {
 
1512                                 aaiId = subnet.getSubnetId();
 
1517                     sMap.put(aaiId, uuid); // bpmn needs aaid to uuid map
 
1520                 logger.error("{} {} null rootNode - cannot get subnet-uuids", MessageEnum.RA_MARSHING_ERROR,
 
1521                         ErrorCode.DataError.getValue());
 
1523         } catch (Exception e) {
 
1524             logger.error("{} {} Exception getting subnet-uuids ", MessageEnum.RA_MARSHING_ERROR,
 
1525                     ErrorCode.DataError.getValue(), e);
 
1528         logger.debug("Return sMap {}", sMap);
 
1532     private static String insertStr(String template, String snippet, int index) {
 
1534         String updatedTemplate;
 
1536         logger.debug("Index:{} Snippet:{}", index, snippet);
 
1538         String templateBeg = template.substring(0, index);
 
1539         String templateEnd = template.substring(index);
 
1541         updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
 
1543         logger.debug("Template updated with a subnet:{}", updatedTemplate);
 
1544         return updatedTemplate;