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 com.fasterxml.jackson.databind.JsonNode;
28 import com.fasterxml.jackson.databind.ObjectMapper;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.List;
33 import java.util.Optional;
34 import javax.jws.WebService;
35 import javax.xml.ws.Holder;
36 import org.onap.so.adapters.network.beans.ContrailPolicyRef;
37 import org.onap.so.adapters.network.beans.ContrailPolicyRefSeq;
38 import org.onap.so.adapters.network.beans.ContrailSubnet;
39 import org.onap.so.adapters.network.exceptions.NetworkException;
40 import org.onap.so.adapters.network.mappers.ContrailSubnetMapper;
41 import org.onap.so.cloud.CloudConfig;
42 import org.onap.so.db.catalog.beans.CloudSite;
43 import org.onap.so.db.catalog.beans.CollectionNetworkResourceCustomization;
44 import org.onap.so.db.catalog.beans.HeatTemplate;
45 import org.onap.so.db.catalog.beans.NetworkResource;
46 import org.onap.so.db.catalog.beans.NetworkResourceCustomization;
47 import org.onap.so.db.catalog.data.repository.CollectionNetworkResourceCustomizationRepository;
48 import org.onap.so.db.catalog.data.repository.NetworkResourceCustomizationRepository;
49 import org.onap.so.db.catalog.data.repository.NetworkResourceRepository;
50 import org.onap.so.db.catalog.utils.MavenLikeVersioning;
51 import org.onap.so.entity.MsoRequest;
52 import org.onap.so.logger.MessageEnum;
53 import org.onap.so.logger.MsoLogger;
54 import org.onap.so.openstack.beans.HeatStatus;
55 import org.onap.so.openstack.beans.NetworkInfo;
56 import org.onap.so.openstack.beans.NetworkRollback;
57 import org.onap.so.openstack.beans.NetworkStatus;
58 import org.onap.so.openstack.beans.Pool;
59 import org.onap.so.openstack.beans.RouteTarget;
60 import org.onap.so.openstack.beans.StackInfo;
61 import org.onap.so.openstack.beans.Subnet;
62 import org.onap.so.openstack.exceptions.MsoAdapterException;
63 import org.onap.so.openstack.exceptions.MsoException;
64 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
65 import org.onap.so.openstack.utils.MsoCommonUtils;
66 import org.onap.so.openstack.utils.MsoHeatUtils;
67 import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
68 import org.onap.so.openstack.utils.MsoNeutronUtils;
69 import org.onap.so.openstack.utils.MsoNeutronUtils.NetworkType;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72 import org.springframework.beans.factory.annotation.Autowired;
73 import org.springframework.core.env.Environment;
74 import org.springframework.stereotype.Component;
75 import org.springframework.transaction.annotation.Transactional;
79 @WebService(serviceName = "NetworkAdapter", endpointInterface = "org.onap.so.adapters.network.MsoNetworkAdapter", targetNamespace = "http://org.onap.so/network")
80 public class MsoNetworkAdapterImpl implements MsoNetworkAdapter {
82 private static final String AIC3_NW_PROPERTY= "org.onap.so.adapters.network.aic3nw";
83 private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork";
84 private static final String VLANS = "vlans";
85 private static final String PHYSICAL_NETWORK = "physical_network";
86 private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork";
87 private static final String NETWORK_ID = "network_id";
88 private static final String NETWORK_FQDN = "network_fqdn";
89 private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork";
90 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
91 private static final String NEUTRON_MODE = "NEUTRON";
93 private static final Logger logger = LoggerFactory.getLogger(MsoNetworkAdapterImpl.class);
96 private CloudConfig cloudConfig;
98 private Environment environment;
100 private MsoNeutronUtils neutron;
102 private MsoHeatUtils heat;
104 private MsoHeatUtilsWithUpdate heatWithUpdate;
106 private MsoCommonUtils commonUtils;
109 private NetworkResourceCustomizationRepository networkCustomRepo;
112 private CollectionNetworkResourceCustomizationRepository collectionNetworkCustomRepo;
115 private NetworkResourceRepository networkResourceRepo;
117 * Health Check web method. Does nothing but return to show the adapter is deployed.
120 public void healthCheck () {
121 logger.debug ("Health check call in Network Adapter");
125 * Do not use this constructor or the msoPropertiesFactory will be NULL.
127 * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
129 public MsoNetworkAdapterImpl() {
133 public void createNetwork (String cloudSiteId,
136 String modelCustomizationUuid,
138 String physicalNetworkName,
139 List <Integer> vlans,
142 Boolean failIfExists,
144 List <Subnet> subnets,
145 Map<String, String> networkParams,
146 MsoRequest msoRequest,
147 Holder <String> networkId,
148 Holder <String> neutronNetworkId,
149 Holder <Map <String, String>> subnetIdMap,
150 Holder <NetworkRollback> rollback) throws NetworkException {
151 Holder <String> networkFqdn = new Holder <> ();
152 createNetwork (cloudSiteId,
155 modelCustomizationUuid,
176 public void createNetworkContrail (String cloudSiteId,
179 String modelCustomizationUuid,
181 List <RouteTarget> routeTargets,
184 Boolean failIfExists,
186 List <Subnet> subnets,
187 Map<String, String> networkParams,
188 List <String> policyFqdns,
189 List<String> routeTableFqdns,
190 MsoRequest msoRequest,
191 Holder <String> networkId,
192 Holder <String> neutronNetworkId,
193 Holder <String> networkFqdn,
194 Holder <Map <String, String>> subnetIdMap,
195 Holder <NetworkRollback> rollback) throws NetworkException {
196 createNetwork (cloudSiteId,
199 modelCustomizationUuid,
220 * This is the "Create Network" web service implementation.
221 * It will create a new Network of the requested type in the specified cloud
222 * and tenant. The tenant must exist at the time this service is called.
224 * If a network with the same name already exists, this can be considered a
225 * success or failure, depending on the value of the 'failIfExists' parameter.
227 * There will be a pre-defined set of network types defined in the MSO Catalog.
228 * All such networks will have a similar configuration, based on the allowable
229 * Openstack networking definitions. This includes basic networks, provider
230 * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
232 * Initially, all provider networks must be "vlan" type, and multiple segments in
233 * a multi-provider network must be multiple VLANs on the same physical network.
235 * This service supports two modes of Network creation/update:
236 * - via Heat Templates
238 * The network orchestration mode for each network type is declared in its
239 * catalog definition. All Heat-based templates must support some subset of
240 * the same input parameters: network_name, physical_network, vlan(s).
242 * The method returns the network ID and a NetworkRollback object. This latter
243 * object can be passed as-is to the rollbackNetwork operation to undo everything
244 * that was created. This is useful if a network is successfully created but
245 * the orchestration fails on a subsequent operation.
248 private void createNetwork (String cloudSiteId,
251 String modelCustomizationUuid,
253 String physicalNetworkName,
254 List <Integer> vlans,
255 List <RouteTarget> routeTargets,
258 Boolean failIfExists,
260 List <Subnet> subnets,
261 List <String> policyFqdns,
262 List <String> routeTableFqdns,
263 MsoRequest msoRequest,
264 Holder <String> networkId,
265 Holder <String> neutronNetworkId,
266 Holder <String> networkFqdn,
267 Holder <Map <String, String>> subnetIdMap,
268 Holder <NetworkRollback> rollback) throws NetworkException {
269 MsoLogger.setLogContext (msoRequest);
270 MsoLogger.setServiceName (CREATE_NETWORK_CONTEXT);
272 logger.debug("*** CREATE Network: {} of type {} in {}/{}", networkName, networkType, cloudSiteId, tenantId);
274 // Will capture execution time for metrics
275 long startTime = System.currentTimeMillis ();
277 // Build a default rollback object (no actions performed)
278 NetworkRollback networkRollback = new NetworkRollback ();
279 networkRollback.setCloudId (cloudSiteId);
280 networkRollback.setTenantId (tenantId);
281 networkRollback.setMsoRequest (msoRequest);
282 networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
284 // tenant query is not required here.
285 // If the tenant doesn't exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
286 // So this is just catching that error in a bit more obvious way up front.
288 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
289 if (!cloudSiteOpt.isPresent())
291 String error = String
292 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
293 networkName, cloudSiteId, tenantId);
294 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
295 // Set the detailed error as the Exception 'message'
296 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
300 NetworkResource networkResource = networkCheck (startTime,
302 modelCustomizationUuid,
309 String mode = networkResource.getOrchestrationMode ();
310 NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ());
312 if (NEUTRON_MODE.equals (mode)) {
314 // Use an MsoNeutronUtils for all neutron commands
316 // See if the Network already exists (by name)
317 NetworkInfo netInfo = null;
318 long queryNetworkStarttime = System.currentTimeMillis ();
320 netInfo = neutron.queryNetwork (networkName, tenantId, cloudSiteId);
321 } catch (MsoException me) {
323 "{} {} Exception while querying network {} for CloudSite {} from Tenant {} from OpenStack ",
324 MessageEnum.RA_QUERY_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
325 networkName, cloudSiteId, tenantId, me);
326 me.addContext (CREATE_NETWORK_CONTEXT);
327 throw new NetworkException (me);
330 if (netInfo != null) {
331 // Exists. If that's OK, return success with the network ID.
332 // Otherwise, return an exception.
333 if (failIfExists != null && failIfExists) {
334 String error = String
335 .format("Create Nework: Network %s already exists in %s/%s with ID %s", networkName,
336 cloudSiteId, tenantId, netInfo.getId());
337 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ALREADY_EXIST,
338 MsoLogger.ErrorCode.DataError.getValue(), error);
339 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
341 // Populate the outputs from the existing network.
342 networkId.value = netInfo.getId ();
343 neutronNetworkId.value = netInfo.getId ();
344 rollback.value = networkRollback; // Default rollback - no updates performed
345 logger.warn("{} {} Found Existing network, status={} for Neutron mode ",
346 MessageEnum.RA_NETWORK_ALREADY_EXIST, MsoLogger.ErrorCode.DataError.getValue(),
347 netInfo.getStatus());
352 long createNetworkStarttime = System.currentTimeMillis ();
354 netInfo = neutron.createNetwork (cloudSiteId,
360 } catch (MsoException me) {
361 me.addContext(CREATE_NETWORK_CONTEXT);
362 logger.error("{} {} Create Network: type {} in {}/{}: ", MessageEnum.RA_CREATE_NETWORK_EXC,
363 MsoLogger.ErrorCode.DataError.getValue(), neutronNetworkType, cloudSiteId, tenantId, me);
365 throw new NetworkException (me);
368 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
370 // If reach this point, network creation is successful.
371 // Since directly created via Neutron, networkId tracked by MSO is the same
372 // as the neutron network ID.
373 networkId.value = netInfo.getId ();
374 neutronNetworkId.value = netInfo.getId ();
376 networkRollback.setNetworkCreated (true);
377 networkRollback.setNetworkId (netInfo.getId ());
378 networkRollback.setNeutronNetworkId (netInfo.getId ());
379 networkRollback.setNetworkType (networkType);
381 logger.debug("Network {} created, id = {}", networkName, netInfo.getId());
382 } else if ("HEAT".equals (mode)) {
384 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
385 if (heatTemplate == null) {
386 String error = String
387 .format("Network error - undefined Heat Template. Network Type = %s", networkType);
388 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
390 throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
393 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
395 // "Fix" the template if it has CR/LF (getting this from Oracle)
396 String template = heatTemplate.getHeatTemplate ();
397 template = template.replaceAll ("\r\n", "\n");
399 boolean aic3template=false;
400 String aic3nw = AIC3_NW;
402 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
404 if (template.contains(aic3nw))
407 // First, look up to see if the Network already exists (by name).
408 // For HEAT orchestration of networks, the stack name will always match the network name
409 StackInfo heatStack = null;
410 long queryNetworkStarttime = System.currentTimeMillis ();
412 heatStack = heat.queryStack (cloudSiteId, tenantId, networkName);
413 } catch (MsoException me) {
414 me.addContext (CREATE_NETWORK_CONTEXT);
415 logger.error("{} {} Create Network (heat): query network {} in {}/{}: ",
416 MessageEnum.RA_QUERY_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(), networkName,
417 cloudSiteId, tenantId, me);
418 throw new NetworkException (me);
421 if (heatStack != null && (heatStack.getStatus () != HeatStatus.NOTFOUND)) {
422 // Stack exists. Return success or error depending on input directive
423 if (failIfExists != null && failIfExists) {
424 String error = String
425 .format("CreateNetwork: Stack %s already exists in %s/%s as %s", networkName, cloudSiteId,
426 tenantId, heatStack.getCanonicalName());
427 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ALREADY_EXIST,
428 MsoLogger.ErrorCode.DataError.getValue(), error);
429 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
431 // Populate the outputs from the existing stack.
432 networkId.value = heatStack.getCanonicalName ();
433 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
434 rollback.value = networkRollback; // Default rollback - no updates performed
437 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
439 Map <String, Object> outputs = heatStack.getOutputs ();
440 Map <String, String> sMap = new HashMap <> ();
441 if (outputs != null) {
442 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
443 String key=entry.getKey();
444 if (key != null && key.startsWith ("subnet")) {
445 if (aic3template) //one subnet_id output
447 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
450 else //multiples subnet_%aaid% outputs
452 String subnetUUId = (String) outputs.get(key);
453 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
458 subnetIdMap.value = sMap;
459 logger.warn("{} {} Found Existing network stack, status={} networkName={} for {}/{}",
460 MessageEnum.RA_NETWORK_ALREADY_EXIST, MsoLogger.ErrorCode.DataError.getValue(),
461 heatStack.getStatus(), networkName, cloudSiteId, tenantId);
466 // Ready to deploy the new Network
467 // Build the common set of HEAT template parameters
468 Map <String, Object> stackParams = populateNetworkParams (neutronNetworkType,
477 // Validate (and update) the input parameters against the DB definition
478 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
479 // and inputs were already validated.
481 stackParams = heat.validateStackParams (stackParams, heatTemplate);
482 } catch (IllegalArgumentException e) {
483 String error = "Create Network: Configuration Error: " + e.getMessage ();
484 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC,
485 MsoLogger.ErrorCode.DataError.getValue(), error,e);
486 // Input parameters were not valid
487 throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
490 if (subnets != null) {
494 template = mergeSubnetsAIC3 (template, subnets, stackParams);
498 template = mergeSubnets (template, subnets);
500 } catch (MsoException me) {
501 me.addContext (CREATE_NETWORK_CONTEXT);
503 .error("{} {} Exception Create Network, merging subnets for network (heat) type {} in {}/{} ",
504 MessageEnum.RA_CREATE_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(),
505 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
506 throw new NetworkException (me);
510 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
512 mergePolicyRefs (policyFqdns, stackParams);
513 } catch (MsoException me) {
514 me.addContext (CREATE_NETWORK_CONTEXT);
515 logger.error("{} {} Exception Create Network, merging policyRefs type {} in {}/{} ",
516 MessageEnum.RA_CREATE_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(),
517 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
518 throw new NetworkException (me);
522 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
524 mergeRouteTableRefs (routeTableFqdns, stackParams);
525 } catch (MsoException me) {
526 me.addContext (CREATE_NETWORK_CONTEXT);
527 logger.error("{} {} Exception Create Network, merging routeTableRefs type {} in {}/{} ",
528 MessageEnum.RA_CREATE_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(),
529 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
530 throw new NetworkException (me);
534 // Deploy the network stack
535 // Ignore MsoStackAlreadyExists exception because we already checked.
539 heatStack = heat.createStack (cloudSiteId,
545 heatTemplate.getTimeoutMinutes (),
549 backout.booleanValue());
550 } catch (MsoException me) {
551 me.addContext (CREATE_NETWORK_CONTEXT);
553 .error("{} {} Exception creating network type {} in {}/{} ", MessageEnum.RA_CREATE_NETWORK_EXC,
554 MsoLogger.ErrorCode.DataError.getValue(), networkName, cloudSiteId, tenantId, me);
555 throw new NetworkException (me);
558 // Reach this point if createStack is successful.
560 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
561 // and the neutronNetworkId is the network UUID returned in stack outputs.
562 networkId.value = heatStack.getCanonicalName ();
563 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
566 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
568 Map <String, Object> outputs = heatStack.getOutputs ();
569 Map <String, String> sMap = new HashMap <> ();
570 if (outputs != null) {
571 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
572 String key = entry.getKey();
573 if (key != null && key.startsWith ("subnet")) {
574 if (aic3template) //one subnet output expected
576 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
579 else //multiples subnet_%aaid% outputs allowed
581 String subnetUUId = (String) outputs.get(key);
582 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
587 subnetIdMap.value = sMap;
589 rollback.value = networkRollback;
590 // Populate remaining rollback info and response parameters.
591 networkRollback.setNetworkStackId (heatStack.getCanonicalName ());
592 networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID));
593 networkRollback.setNetworkCreated (true);
594 networkRollback.setNetworkType (networkType);
596 logger.debug("Network {} successfully created via HEAT", networkName);
603 public void updateNetwork (String cloudSiteId,
606 String modelCustomizationUuid,
609 String physicalNetworkName,
610 List <Integer> vlans,
613 List <Subnet> subnets,
614 Map<String,String> networkParams,
615 MsoRequest msoRequest,
616 Holder <Map <String, String>> subnetIdMap,
617 Holder <NetworkRollback> rollback) throws NetworkException {
618 updateNetwork (cloudSiteId,
621 modelCustomizationUuid,
639 public void updateNetworkContrail (String cloudSiteId,
642 String modelCustomizationUuid,
645 List <RouteTarget> routeTargets,
648 List <Subnet> subnets,
649 Map<String, String> networkParams,
650 List <String> policyFqdns,
651 List<String> routeTableFqdns,
652 MsoRequest msoRequest,
653 Holder <Map <String, String>> subnetIdMap,
654 Holder <NetworkRollback> rollback) throws NetworkException {
655 updateNetwork (cloudSiteId,
658 modelCustomizationUuid,
675 * This is the "Update Network" web service implementation.
676 * It will update an existing Network of the requested type in the specified cloud
677 * and tenant. The typical use will be to replace the VLANs with the supplied
678 * list (to add or remove a VLAN), but other properties may be updated as well.
680 * There will be a pre-defined set of network types defined in the MSO Catalog.
681 * All such networks will have a similar configuration, based on the allowable
682 * Openstack networking definitions. This includes basic networks, provider
683 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
685 * Initially, all provider networks must currently be "vlan" type, and multi-provider
686 * networks must be multiple VLANs on the same physical network.
688 * This service supports two modes of Network update:
689 * - via Heat Templates
691 * The network orchestration mode for each network type is declared in its
692 * catalog definition. All Heat-based templates must support some subset of
693 * the same input parameters: network_name, physical_network, vlan, segments.
695 * The method returns a NetworkRollback object. This object can be passed
696 * as-is to the rollbackNetwork operation to undo everything that was updated.
697 * This is useful if a network is successfully updated but orchestration
698 * fails on a subsequent operation.
700 private void updateNetwork (String cloudSiteId,
703 String modelCustomizationUuid,
706 String physicalNetworkName,
707 List <Integer> vlans,
708 List <RouteTarget> routeTargets,
711 List <Subnet> subnets,
712 List <String> policyFqdns,
713 List<String> routeTableFqdns,
714 MsoRequest msoRequest,
715 Holder <Map <String, String>> subnetIdMap,
716 Holder <NetworkRollback> rollback) throws NetworkException {
717 MsoLogger.setLogContext (msoRequest);
718 MsoLogger.setServiceName (UPDATE_NETWORK_CONTEXT);
719 logger.debug("***UPDATE Network adapter with Network: {} of type {} in {}/{}", networkName, networkType,
720 cloudSiteId, tenantId);
722 // Will capture execution time for metrics
723 long startTime = System.currentTimeMillis ();
725 // Build a default rollback object (no actions performed)
726 NetworkRollback networkRollback = new NetworkRollback ();
727 networkRollback.setCloudId (cloudSiteId);
728 networkRollback.setTenantId (tenantId);
729 networkRollback.setMsoRequest (msoRequest);
731 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
732 if (!cloudSiteOpt.isPresent()) {
733 String error = String.format(
734 "UpdateNetwork: Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
735 networkName, cloudSiteId, tenantId);
736 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
737 // Set the detailed error as the Exception 'message'
738 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
744 NetworkResource networkResource = networkCheck(
747 modelCustomizationUuid,
754 String mode = networkResource.getOrchestrationMode();
755 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
757 // Use an MsoNeutronUtils for all Neutron commands
759 if (NEUTRON_MODE.equals(mode)) {
761 // Verify that the Network exists
762 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
763 NetworkInfo netInfo = null;
764 long queryNetworkStarttime = System.currentTimeMillis();
766 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
767 } catch (MsoException me) {
768 me.addContext(UPDATE_NETWORK_CONTEXT);
769 logger.error("{} {} Exception - queryNetwork query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
770 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), networkId, cloudSiteId, tenantId, me);
771 throw new NetworkException(me);
774 if (netInfo == null) {
775 String error = String
776 .format("Update Nework: Network %s does not exist in %s/%s", networkId, cloudSiteId, tenantId);
777 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND,
778 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), error);
779 // Does not exist. Throw an exception (can't update a non-existent network)
780 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
782 long updateNetworkStarttime = System.currentTimeMillis();
784 netInfo = neutron.updateNetwork(cloudSiteId,
790 } catch (MsoException me) {
791 me.addContext(UPDATE_NETWORK_CONTEXT);
792 logger.error("{} {} Exception - updateNetwork {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
793 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
794 throw new NetworkException(me);
797 // Add the network ID and previously queried vlans to the rollback object
798 networkRollback.setNetworkId(netInfo.getId());
799 networkRollback.setNeutronNetworkId(netInfo.getId());
800 networkRollback.setNetworkType(networkType);
801 // Save previous parameters
802 networkRollback.setNetworkName(netInfo.getName());
803 networkRollback.setPhysicalNetwork(netInfo.getProvider());
804 networkRollback.setVlans(netInfo.getVlans());
806 logger.debug("Network {} updated, id = {}", networkId, netInfo.getId());
807 } else if ("HEAT".equals(mode)) {
809 // First, look up to see that the Network already exists.
810 // For Heat-based orchestration, the networkId is the network Stack ID.
811 StackInfo heatStack = null;
812 long queryStackStarttime = System.currentTimeMillis();
814 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
815 } catch (MsoException me) {
816 me.addContext(UPDATE_NETWORK_CONTEXT);
817 logger.error("{} {} Exception - QueryStack query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
818 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
819 throw new NetworkException(me);
822 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
823 String error = String
824 .format("UpdateNetwork: Stack %s does not exist in %s/%s", networkName, cloudSiteId, tenantId);
825 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
827 // Network stack does not exist. Return an error
828 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
831 // Get the previous parameters for rollback
832 Map<String, Object> heatParams = heatStack.getParameters();
834 String previousNetworkName = (String) heatParams.get("network_name");
835 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
837 List<Integer> previousVlans = new ArrayList<>();
838 String vlansParam = (String) heatParams.get(VLANS);
839 if (vlansParam != null) {
840 for (String vlan : vlansParam.split(",")) {
842 previousVlans.add(Integer.parseInt(vlan));
843 } catch (NumberFormatException e) {
844 logger.warn("{} {} Exception - VLAN parse for params {} ", MessageEnum.RA_VLAN_PARSE,
845 MsoLogger.ErrorCode.DataError.getValue(), vlansParam, e);
849 logger.debug("Update Stack: Previous VLANS: {}", previousVlans);
851 // Ready to deploy the updated Network via Heat
854 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
855 if (heatTemplate == null) {
856 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
857 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
859 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
862 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
864 // "Fix" the template if it has CR/LF (getting this from Oracle)
865 String template = heatTemplate.getHeatTemplate();
866 template = template.replaceAll("\r\n", "\n");
868 boolean aic3template = false;
869 String aic3nw = AIC3_NW;
871 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
873 if (template.contains(aic3nw))
876 // Build the common set of HEAT template parameters
877 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
886 // Validate (and update) the input parameters against the DB definition
887 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
889 stackParams = heat.validateStackParams(stackParams, heatTemplate);
890 } catch (IllegalArgumentException e) {
891 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
892 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
893 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
896 if (subnets != null) {
899 template = mergeSubnetsAIC3(template, subnets, stackParams);
901 template = mergeSubnets(template, subnets);
903 } catch (MsoException me) {
904 me.addContext(UPDATE_NETWORK_CONTEXT);
905 logger.error("{} {} Exception - UpdateNetwork mergeSubnets for network type {} in {}/{} ",
906 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
907 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
908 throw new NetworkException(me);
912 if (policyFqdns != null && aic3template) {
914 mergePolicyRefs(policyFqdns, stackParams);
915 } catch (MsoException me) {
916 me.addContext(UPDATE_NETWORK_CONTEXT);
917 logger.error("{} {} Exception - UpdateNetwork mergePolicyRefs type {} in {}/{} ",
918 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
919 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
920 throw new NetworkException(me);
924 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
926 mergeRouteTableRefs(routeTableFqdns, stackParams);
927 } catch (MsoException me) {
928 me.addContext(UPDATE_NETWORK_CONTEXT);
929 logger.error("{} {} Exception - UpdateNetwork mergeRouteTableRefs type {} in {}/{} ",
930 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
931 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
932 throw new NetworkException(me);
936 // Update the network stack
937 // Ignore MsoStackNotFound exception because we already checked.
938 long updateStackStarttime = System.currentTimeMillis();
940 heatStack = heatWithUpdate.updateStack(cloudSiteId,
946 heatTemplate.getTimeoutMinutes());
947 } catch (MsoException me) {
948 me.addContext(UPDATE_NETWORK_CONTEXT);
949 logger.error("{} {} Exception - update network {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
950 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
951 throw new NetworkException(me);
954 Map<String, Object> outputs = heatStack.getOutputs();
955 Map<String, String> sMap = new HashMap<>();
956 if (outputs != null) {
957 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
958 String key=entry.getKey();
959 if (key != null && key.startsWith("subnet")) {
960 if (aic3template) //one subnet output expected
962 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
964 } else //multiples subnet_%aaid% outputs allowed
966 String subnetUUId = (String) outputs.get(key);
967 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
972 subnetIdMap.value = sMap;
974 // Reach this point if createStack is successful.
975 // Populate remaining rollback info and response parameters.
976 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
977 if(null != outputs) {
978 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
981 logger.debug("outputs is NULL");
983 networkRollback.setNetworkType(networkType);
984 // Save previous parameters
985 networkRollback.setNetworkName(previousNetworkName);
986 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
987 networkRollback.setVlans(previousVlans);
989 rollback.value = networkRollback;
991 logger.debug("Network {} successfully updated via HEAT", networkId);
997 private NetworkResource networkCheck (long startTime,
999 String modelCustomizationUuid,
1001 String physicalNetworkName,
1002 List <Integer> vlans,
1003 List <RouteTarget> routeTargets,
1005 CloudSite cloudSite) throws NetworkException {
1006 // Retrieve the Network Resource definition
1007 NetworkResource networkResource = null;
1008 NetworkResourceCustomization networkCust = null;
1009 CollectionNetworkResourceCustomization collectionNetworkCust = null;
1010 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1011 if (!commonUtils.isNullOrEmpty(networkType)) {
1012 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1015 networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1016 if (networkCust == null) {
1017 collectionNetworkCust = collectionNetworkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1020 if(networkCust != null){
1021 logger.debug("Got Network Customization definition from Catalog: {}", networkCust.toString());
1023 networkResource = networkCust.getNetworkResource();
1024 } else if (collectionNetworkCust != null) {
1025 logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}",
1026 collectionNetworkCust.toString());
1027 networkResource = collectionNetworkCust.getNetworkResource();
1029 if (networkResource == null) {
1030 String error = String.format(
1031 "Create/UpdateNetwork: Unable to get network resource with NetworkType: %s or ModelCustomizationUUID:%s",
1032 networkType, modelCustomizationUuid);
1033 logger.error("{} {} {} ", MessageEnum.RA_UNKOWN_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1035 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1037 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1039 String mode = networkResource.getOrchestrationMode();
1040 NetworkType neutronNetworkType = NetworkType
1041 .valueOf(networkResource.getNeutronNetworkType());
1043 // All Networks are orchestrated via HEAT or Neutron
1044 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1045 String error = "CreateNetwork: Configuration Error: Network Type = " + networkType;
1046 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1047 MsoLogger.ErrorCode.DataError.getValue(), error);
1048 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1051 MavenLikeVersioning aicV = new MavenLikeVersioning();
1052 aicV.setVersion(cloudSite.getCloudVersion());
1053 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1054 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1057 && (aicV.isTheSameVersion(networkResource
1058 .getAicVersionMax()) || !(aicV
1059 .isMoreRecentThan(networkResource
1060 .getAicVersionMax())))) // aic <= max
1062 logger.debug("Network Type:{} VersionMin:{} VersionMax:{} supported on Cloud:{} with AIC_Version:{}",
1063 networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId,
1064 cloudSite.getCloudVersion());
1066 String error = String
1067 .format("Network Type:%s Version_Min:%s Version_Max:%s not supported on Cloud:%s with AIC_Version:%s",
1068 networkType, networkType, networkResource.getAicVersionMin(),
1069 networkResource.getAicVersionMax(), cloudSiteId, cloudSite.getCloudVersion());
1070 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
1071 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1074 // Validate the Network parameters.
1075 String missing = validateNetworkParams(neutronNetworkType,
1076 networkName, physicalNetworkName, vlans, routeTargets);
1077 if (!missing.isEmpty()) {
1078 String error = "Create Network: Missing parameters: " + missing;
1079 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1081 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1084 return networkResource;
1088 public void queryNetwork (String cloudSiteId,
1090 String networkNameOrId,
1091 MsoRequest msoRequest,
1092 Holder <Boolean> networkExists,
1093 Holder <String> networkId,
1094 Holder <String> neutronNetworkId,
1095 Holder <NetworkStatus> status,
1096 Holder <List <Integer>> vlans,
1097 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1098 queryNetwork (cloudSiteId,
1112 public void queryNetworkContrail (String cloudSiteId,
1114 String networkNameOrId,
1115 MsoRequest msoRequest,
1116 Holder <Boolean> networkExists,
1117 Holder <String> networkId,
1118 Holder <String> neutronNetworkId,
1119 Holder <NetworkStatus> status,
1120 Holder <List <RouteTarget>> routeTargets,
1121 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1122 queryNetwork (cloudSiteId,
1136 * This is the queryNetwork method. It returns the existence and status of
1137 * the specified network, along with its Neutron UUID and list of VLANs.
1138 * This method attempts to find the network using both Heat and Neutron.
1139 * Heat stacks are first searched based on the provided network name/id.
1140 * If none is found, the Neutron is directly queried.
1142 private void queryNetwork (String cloudSiteId,
1144 String networkNameOrId,
1145 MsoRequest msoRequest,
1146 Holder <Boolean> networkExists,
1147 Holder <String> networkId,
1148 Holder <String> neutronNetworkId,
1149 Holder <NetworkStatus> status,
1150 Holder <List <Integer>> vlans,
1151 Holder <List <RouteTarget>> routeTargets,
1152 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1153 MsoLogger.setLogContext (msoRequest);
1154 MsoLogger.setServiceName ("QueryNetwork");
1155 logger.debug("*** QUERY Network with Network: {} in {}/{}", networkNameOrId, cloudSiteId, tenantId);
1157 // Will capture execution time for metrics
1158 long startTime = System.currentTimeMillis ();
1160 if (commonUtils.isNullOrEmpty (cloudSiteId)
1161 || commonUtils.isNullOrEmpty(tenantId)
1162 || commonUtils.isNullOrEmpty(networkNameOrId)) {
1164 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1165 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1166 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1169 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1170 if (!cloudSiteOpt.isPresent())
1172 String error = String
1173 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
1174 networkNameOrId, cloudSiteId, tenantId);
1175 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
1176 // Set the detailed error as the Exception 'message'
1177 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1180 // Use MsoNeutronUtils for all NEUTRON commands
1184 // Try Heat first, since networks may be named the same as the Heat stack
1185 StackInfo heatStack = null;
1186 long queryStackStarttime = System.currentTimeMillis ();
1188 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1189 } catch (MsoException me) {
1190 me.addContext ("QueryNetwork");
1191 logger.error("{} {} Exception - Query Network (heat): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1192 MsoLogger.ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1193 throw new NetworkException (me);
1196 // Populate the outputs based on the returned Stack information
1197 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1198 // Found it. Get the neutronNetworkId for further query
1199 Map <String, Object> outputs = heatStack.getOutputs ();
1200 neutronId = (String) outputs.get (NETWORK_ID);
1203 Map <String, String> sMap = new HashMap <> ();
1204 if (outputs != null) {
1205 for (String key : outputs.keySet ()) {
1206 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1208 String subnetUUId = (String) outputs.get(key);
1209 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1211 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1213 Map <String, String> map = getSubnetUUId(key, outputs, null);
1219 subnetIdMap.value = sMap;
1221 // Input ID was not a Heat stack ID. Try it directly in Neutron
1222 neutronId = networkNameOrId;
1223 mode = NEUTRON_MODE;
1226 // Query directly against the Neutron Network for the details
1227 // no RouteTargets available for ContrailV2 in neutron net-show
1228 // networkId is heatStackId
1229 long queryNetworkStarttime = System.currentTimeMillis ();
1231 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1232 if (netInfo != null) {
1233 // Found. Populate the output elements
1234 networkExists.value = Boolean.TRUE;
1235 if ("HEAT".equals (mode)) {
1236 networkId.value = heatStack.getCanonicalName ();
1238 networkId.value = netInfo.getId ();
1240 neutronNetworkId.value = netInfo.getId ();
1241 status.value = netInfo.getStatus ();
1243 vlans.value = netInfo.getVlans ();
1245 logger.debug("Network {} found({}), ID = {}{}", networkNameOrId, mode, networkId.value,
1246 ("HEAT".equals(mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1248 // Not found. Populate the status fields, leave the rest null
1249 networkExists.value = Boolean.FALSE;
1250 status.value = NetworkStatus.NOTFOUND;
1251 neutronNetworkId.value = null;
1253 vlans.value = new ArrayList<>();
1255 logger.debug("Network {} not found", networkNameOrId);
1257 } catch (MsoException me) {
1258 me.addContext ("QueryNetwork");
1259 logger.error("{} {} Exception - Query Network (neutron): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1260 MsoLogger.ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1261 throw new NetworkException (me);
1267 * This is the "Delete Network" web service implementation.
1268 * It will delete a Network in the specified cloud and tenant.
1270 * If the network is not found, it is treated as a success.
1272 * This service supports two modes of Network creation/update/delete:
1273 * - via Heat Templates
1275 * The network orchestration mode for each network type is declared in its
1276 * catalog definition.
1278 * For Heat-based orchestration, the networkId should be the stack ID.
1279 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1281 * The method returns nothing on success. Rollback is not possible for delete
1282 * commands, so any failure on delete will require manual fallout in the client.
1285 public void deleteNetwork (String cloudSiteId,
1288 String modelCustomizationUuid,
1290 MsoRequest msoRequest,
1291 Holder <Boolean> networkDeleted) throws NetworkException {
1292 MsoLogger.setLogContext (msoRequest);
1293 MsoLogger.setServiceName ("DeleteNetwork");
1294 logger.debug("*** DELETE Network adapter with Network: {} in {}/{}", networkId, cloudSiteId, tenantId);
1296 // Will capture execution time for metrics
1297 long startTime = System.currentTimeMillis ();
1300 if (commonUtils.isNullOrEmpty (cloudSiteId)
1301 || commonUtils.isNullOrEmpty(tenantId)
1302 || commonUtils.isNullOrEmpty(networkId)) {
1303 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1304 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1305 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1308 // Retrieve the Network Resource definition
1309 NetworkResource networkResource = null;
1311 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1312 if (!commonUtils.isNullOrEmpty(networkType)) {
1313 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1316 NetworkResourceCustomization nrc = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1318 networkResource = nrc.getNetworkResource();
1323 if (networkResource != null) {
1324 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1326 mode = networkResource.getOrchestrationMode ();
1329 if (NEUTRON_MODE.equals (mode)) {
1331 // Use MsoNeutronUtils for all NEUTRON commands
1332 long deleteNetworkStarttime = System.currentTimeMillis ();
1334 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1335 // was not found. So don't bother to query first.
1336 boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1337 networkDeleted.value = deleted;
1338 } catch (MsoException me) {
1339 me.addContext ("DeleteNetwork");
1340 logger.error("{} {} Delete Network (neutron): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1341 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1342 throw new NetworkException (me);
1344 } else { // DEFAULT to ("HEAT".equals (mode))
1345 long deleteStackStarttime = System.currentTimeMillis ();
1348 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1349 // So query first to report back if stack WAS deleted or just NOTOFUND
1350 StackInfo heatStack = null;
1351 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1352 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND)
1354 heat.deleteStack (tenantId, cloudSiteId, networkId, true);
1355 networkDeleted.value = true;
1359 networkDeleted.value = false;
1361 } catch (MsoException me) {
1362 me.addContext ("DeleteNetwork");
1363 logger.error("{} {} Delete Network (heat): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1364 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1365 throw new NetworkException (me);
1370 // On success, nothing is returned.
1375 * This web service endpoint will rollback a previous Create VNF operation.
1376 * A rollback object is returned to the client in a successful creation
1377 * response. The client can pass that object as-is back to the rollbackVnf
1378 * operation to undo the creation.
1380 * The rollback includes removing the VNF and deleting the tenant if the
1381 * tenant did not exist prior to the VNF creation.
1384 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1385 MsoLogger.setServiceName ("RollbackNetwork");
1386 // Will capture execution time for metrics
1387 long startTime = System.currentTimeMillis ();
1389 if (rollback == null) {
1391 .error("{} {} rollback is null", MessageEnum.RA_ROLLBACK_NULL, MsoLogger.ErrorCode.DataError.getValue());
1395 MsoLogger.setLogContext (rollback.getMsoRequest());
1397 // Get the elements of the VnfRollback object for easier access
1398 String cloudSiteId = rollback.getCloudId ();
1399 String tenantId = rollback.getTenantId ();
1400 String networkId = rollback.getNetworkStackId ();
1401 String networkType = rollback.getNetworkType ();
1402 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1404 logger.debug("*** ROLLBACK Network {} in {}/{}", networkId, cloudSiteId, tenantId);
1407 // Retrieve the Network Resource definition
1408 NetworkResource networkResource = null;
1409 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1410 networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource();
1412 networkResource = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource();
1415 if (networkResource != null) {
1417 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1419 mode = networkResource.getOrchestrationMode ();
1422 if (rollback.getNetworkCreated ()) {
1423 // Rolling back a newly created network, so delete it.
1424 if (NEUTRON_MODE.equals (mode)) {
1425 // Use MsoNeutronUtils for all NEUTRON commands
1426 long deleteNetworkStarttime = System.currentTimeMillis ();
1428 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1429 // was not found. So don't bother to query first.
1430 neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1431 } catch (MsoException me) {
1432 me.addContext ("RollbackNetwork");
1433 logger.error("{} {} Exception - Rollback Network (neutron): {} in {}/{} ",
1434 MessageEnum.RA_DELETE_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1435 networkId, cloudSiteId, tenantId, me);
1436 throw new NetworkException (me);
1438 } else { // DEFAULT to if ("HEAT".equals (mode))
1439 long deleteStackStarttime = System.currentTimeMillis ();
1441 // The deleteStack function in MsoHeatUtils returns success if the stack
1442 // was not found. So don't bother to query first.
1443 heat.deleteStack (tenantId, cloudSiteId, networkId, true);
1444 } catch (MsoException me) {
1445 me.addContext ("RollbackNetwork");
1446 logger.error("{} {} Exception - Rollback Network (heat): {} in {}/{} ",
1447 MessageEnum.RA_DELETE_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1448 networkId, cloudSiteId, tenantId, me);
1449 throw new NetworkException (me);
1457 private String validateNetworkParams (NetworkType neutronNetworkType,
1459 String physicalNetwork,
1460 List <Integer> vlans,
1461 List <RouteTarget> routeTargets) {
1463 StringBuilder missing = new StringBuilder ();
1464 if (commonUtils.isNullOrEmpty(networkName)) {
1465 missing.append ("networkName");
1469 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1470 if (commonUtils.isNullOrEmpty(physicalNetwork)) {
1471 missing.append (sep).append ("physicalNetworkName");
1474 if (vlans == null || vlans.isEmpty ()) {
1475 missing.append (sep).append (VLANS);
1479 return missing.toString ();
1482 private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1484 String physicalNetwork,
1485 List <Integer> vlans,
1486 List <RouteTarget> routeTargets,
1489 boolean aic3template) {
1490 // Build the common set of HEAT template parameters
1491 Map <String, Object> stackParams = new HashMap <> ();
1492 stackParams.put ("network_name", networkName);
1494 if (neutronNetworkType == NetworkType.PROVIDER) {
1495 // For Provider type
1496 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1497 stackParams.put ("vlan", vlans.get (0).toString ());
1498 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1499 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1500 // It supports all ProviderNet properties except segmentation_id, and adds a
1501 // comma-separated-list of VLANs as a "segments" property.
1502 // Note that this does not match the Neutron definition of Multi-Provider network,
1503 // which contains a list of 'segments', each having physical_network, network_type,
1504 // and segmentation_id.
1505 StringBuilder buf = new StringBuilder ();
1507 for (Integer vlan : vlans) {
1508 buf.append (sep).append (vlan.toString ());
1511 String csl = buf.toString ();
1513 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1514 stackParams.put (VLANS, csl);
1516 if (routeTargets != null) {
1518 String rtGlobal = "";
1519 String rtImport = "";
1520 String rtExport = "";
1522 for (RouteTarget rt : routeTargets) {
1523 boolean rtIsNull = false;
1526 String routeTarget = rt.getRouteTarget();
1527 String routeTargetRole = rt.getRouteTargetRole();
1528 logger.debug("Checking for an actually null route target: {}", rt);
1529 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1531 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1537 logger.debug("Input RT:{}", rt);
1538 String role = rt.getRouteTargetRole();
1539 String rtValue = rt.getRouteTarget();
1541 if ("IMPORT".equalsIgnoreCase(role))
1543 sep = rtImport.isEmpty() ? "" : ",";
1544 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1546 else if ("EXPORT".equalsIgnoreCase(role))
1548 sep = rtExport.isEmpty() ? "" : ",";
1549 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1551 else // covers BOTH, empty etc
1553 sep = rtGlobal.isEmpty() ? "" : ",";
1554 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1560 if (!rtImport.isEmpty())
1562 stackParams.put ("route_targets_import", rtImport);
1564 if (!rtExport.isEmpty())
1566 stackParams.put ("route_targets_export", rtExport);
1568 if (!rtGlobal.isEmpty())
1570 stackParams.put ("route_targets", rtGlobal);
1573 if (commonUtils.isNullOrEmpty(shared)) {
1574 stackParams.put ("shared", "False");
1576 stackParams.put ("shared", shared);
1578 if (commonUtils.isNullOrEmpty(external)) {
1579 stackParams.put ("external", "False");
1581 stackParams.put ("external", external);
1588 /** policyRef_list structure in stackParams
1591 "network_policy_refs_data_sequence": {
1592 "network_policy_refs_data_sequence_major": "1",
1593 "network_policy_refs_data_sequence_minor": "0"
1597 "network_policy_refs_data_sequence": {
1598 "network_policy_refs_data_sequence_major": "2",
1599 "network_policy_refs_data_sequence_minor": "0"
1604 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1606 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1608 for (String pf : pFqdns) {
1609 if (!commonUtils.isNullOrEmpty(pf))
1611 ContrailPolicyRef pr = new ContrailPolicyRef();
1612 ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0");
1615 logger.debug("Contrail PolicyRefs Data:{}", pr);
1620 JsonNode node = null;
1623 ObjectMapper mapper = new ObjectMapper();
1624 node = mapper.convertValue(prlist, JsonNode.class);
1625 String jsonString = mapper.writeValueAsString(prlist);
1626 logger.debug("Json PolicyRefs Data:{}", jsonString);
1630 String error = "Error creating JsonNode for policyRefs Data";
1631 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1633 throw new MsoAdapterException (error);
1636 if (pFqdns != null && node != null)
1638 StringBuilder buf = new StringBuilder ();
1640 for (String pf : pFqdns) {
1641 if (!commonUtils.isNullOrEmpty(pf))
1643 buf.append (sep).append (pf);
1647 String csl = buf.toString ();
1648 stackParams.put ("policy_refs", csl);
1649 stackParams.put ("policy_refsdata", node);
1652 logger.debug("StackParams updated with policy refs");
1656 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1659 if (rtFqdns != null)
1661 StringBuilder buf = new StringBuilder ();
1663 for (String rtf : rtFqdns) {
1664 if (!commonUtils.isNullOrEmpty(rtf))
1666 buf.append (sep).append (rtf);
1670 String csl = buf.toString ();
1671 stackParams.put ("route_table_refs", csl);
1674 logger.debug("StackParams updated with route_table refs");
1679 /*** Subnet Output structure from Juniper
1684 "ip_prefix": "10.100.1.0",
1687 "addr_from_start": null,
1688 "enable_dhcp": false,
1689 "default_gateway": "10.100.1.1",
1690 "dns_nameservers": [],
1691 "dhcp_option_list": null,
1692 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
1693 "allocation_pools": [
1695 "start": "10.100.1.3",
1699 "start": "10.100.1.6",
1703 "host_routes": null,
1704 "dns_server_address": "10.100.1.13",
1705 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
1709 "ip_prefix": "10.100.2.16",
1712 "addr_from_start": null,
1713 "enable_dhcp": true,
1714 "default_gateway": "10.100.2.17",
1715 "dns_nameservers": [],
1716 "dhcp_option_list": null,
1717 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
1718 "allocation_pools": [
1720 "start": "10.100.2.18",
1721 "end": "10.100.2.20"
1724 "host_routes": null,
1725 "dns_server_address": "10.100.2.29",
1726 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
1732 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
1735 List<ContrailSubnet> cslist = new ArrayList <> ();
1736 for (Subnet subnet : subnets) {
1737 logger.debug("Input Subnet:{}", subnet.toString());
1738 ContrailSubnet cs = new ContrailSubnetMapper(subnet).map();
1739 logger.debug("Contrail Subnet:{}", cs.toString());
1743 JsonNode node = null;
1746 ObjectMapper mapper = new ObjectMapper();
1747 node = mapper.convertValue(cslist, JsonNode.class);
1748 String jsonString = mapper.writeValueAsString(cslist);
1749 logger.debug("Json Subnet List:{}", jsonString);
1753 String error = "Error creating JsonNode from input subnets";
1754 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, MsoLogger.ErrorCode.DataError.getValue(), error, e);
1755 throw new MsoAdapterException (error);
1760 stackParams.put ("subnet_list", node);
1762 //Outputs - All subnets are in one ipam_subnets structure
1763 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
1764 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
1766 // append outputs in heatTemplate
1767 int outputsIdx = heatTemplate.indexOf ("outputs:");
1768 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
1769 logger.debug("Template updated with all AIC3.0 subnets:{}", heatTemplate);
1770 return heatTemplate;
1774 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
1776 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
1779 + " network_id: { get_resource: network }\n"
1780 + " cidr: %cidr%\n";
1782 /* make these optional
1783 + " ip_version: %ipversion%\n"
1784 + " enable_dhcp: %enabledhcp%\n"
1785 + " gateway_ip: %gatewayip%\n"
1786 + " allocation_pools:\n"
1787 + " - start: %poolstart%\n"
1788 + " end: %poolend%\n";
1792 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
1793 + " value: {get_resource: subnet_%subnetId%}\n";
1797 StringBuilder resourcesBuf = new StringBuilder ();
1798 StringBuilder outputsBuf = new StringBuilder ();
1799 for (Subnet subnet : subnets) {
1801 // build template for each subnet
1802 curR = resourceTempl;
1803 if (subnet.getSubnetId () != null) {
1804 curR = curR.replace ("%subnetId%", subnet.getSubnetId ());
1806 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
1807 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1808 throw new MsoAdapterException (error);
1811 if (subnet.getSubnetName () != null) {
1812 curR = curR.replace ("%name%", subnet.getSubnetName ());
1814 curR = curR.replace ("%name%", subnet.getSubnetId ());
1817 if (subnet.getCidr () != null) {
1818 curR = curR.replace ("%cidr%", subnet.getCidr ());
1820 String error = "Missing Required cidr for subnet in HEAT Template";
1821 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1822 throw new MsoAdapterException (error);
1825 if (subnet.getIpVersion () != null) {
1826 curR = curR + " ip_version: " + subnet.getIpVersion () + "\n";
1828 if (subnet.getEnableDHCP () != null) {
1829 curR = curR + " enable_dhcp: " + Boolean.toString (subnet.getEnableDHCP ()) + "\n";
1831 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
1832 curR = curR + " gateway_ip: " + subnet.getGatewayIp () + "\n";
1835 if (subnet.getAllocationPools() != null) {
1836 curR = curR + " allocation_pools:\n";
1837 for (Pool pool : subnet.getAllocationPools())
1839 if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd()))
1841 curR = curR + " - start: " + pool.getStart () + "\n";
1842 curR = curR + " end: " + pool.getEnd () + "\n";
1847 resourcesBuf.append (curR);
1850 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
1852 outputsBuf.append (curO);
1855 // append resources and outputs in heatTemplate
1856 logger.debug("Tempate initial:{}", heatTemplate);
1857 int outputsIdx = heatTemplate.indexOf ("outputs:");
1858 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
1859 int resourcesIdx = heatTemplate.indexOf ("resources:");
1860 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
1862 logger.debug("Template updated with all subnets:{}", heatTemplate);
1863 return heatTemplate;
1866 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
1868 Map <String, String> sMap = new HashMap <> ();
1871 Object obj = outputs.get(key);
1872 ObjectMapper mapper = new ObjectMapper();
1873 String jStr = mapper.writeValueAsString(obj);
1874 logger.debug("Subnet_Ipam Output JSON String:{} {}", obj.getClass(), jStr);
1876 JsonNode rootNode = mapper.readTree(jStr);
1877 for (JsonNode sNode : rootNode.path("ipam_subnets"))
1879 logger.debug("Output Subnet Node {}", sNode.toString());
1880 String name = sNode.path("subnet_name").textValue();
1881 String uuid = sNode.path("subnet_uuid").textValue();
1882 String aaiId = name; // default
1883 // try to find aaiId for name in input subnetList
1884 if (subnets != null)
1886 for (Subnet subnet : subnets)
1888 if ( subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName()))
1890 if (subnet.getSubnetName().equals(name))
1892 aaiId = subnet.getSubnetId();
1898 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
1903 logger.error("{} {} Exception getting subnet-uuids ", MessageEnum.RA_MARSHING_ERROR,
1904 MsoLogger.ErrorCode.DataError.getValue(), e);
1907 logger.debug("Return sMap {}", sMap.toString());
1911 private static String insertStr (String template, String snippet, int index) {
1913 String updatedTemplate;
1915 logger.debug("Index:{} Snippet:{}", index, snippet);
1917 String templateBeg = template.substring (0, index);
1918 String templateEnd = template.substring (index);
1920 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
1922 logger.debug("Template updated with a subnet:{}", updatedTemplate);
1923 return updatedTemplate;