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 logger.debug("*** CREATE Network: {} of type {} in {}/{}", networkName, networkType, cloudSiteId, tenantId);
272 // Will capture execution time for metrics
273 long startTime = System.currentTimeMillis ();
275 // Build a default rollback object (no actions performed)
276 NetworkRollback networkRollback = new NetworkRollback ();
277 networkRollback.setCloudId (cloudSiteId);
278 networkRollback.setTenantId (tenantId);
279 networkRollback.setMsoRequest (msoRequest);
280 networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
282 // tenant query is not required here.
283 // If the tenant doesn't exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
284 // So this is just catching that error in a bit more obvious way up front.
286 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
287 if (!cloudSiteOpt.isPresent())
289 String error = String
290 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
291 networkName, cloudSiteId, tenantId);
292 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
293 // Set the detailed error as the Exception 'message'
294 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
298 NetworkResource networkResource = networkCheck (startTime,
300 modelCustomizationUuid,
307 String mode = networkResource.getOrchestrationMode ();
308 NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ());
310 if (NEUTRON_MODE.equals (mode)) {
312 // Use an MsoNeutronUtils for all neutron commands
314 // See if the Network already exists (by name)
315 NetworkInfo netInfo = null;
316 long queryNetworkStarttime = System.currentTimeMillis ();
318 netInfo = neutron.queryNetwork (networkName, tenantId, cloudSiteId);
319 } catch (MsoException me) {
321 "{} {} Exception while querying network {} for CloudSite {} from Tenant {} from OpenStack ",
322 MessageEnum.RA_QUERY_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
323 networkName, cloudSiteId, tenantId, me);
324 me.addContext (CREATE_NETWORK_CONTEXT);
325 throw new NetworkException (me);
328 if (netInfo != null) {
329 // Exists. If that's OK, return success with the network ID.
330 // Otherwise, return an exception.
331 if (failIfExists != null && failIfExists) {
332 String error = String
333 .format("Create Nework: Network %s already exists in %s/%s with ID %s", networkName,
334 cloudSiteId, tenantId, netInfo.getId());
335 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ALREADY_EXIST,
336 MsoLogger.ErrorCode.DataError.getValue(), error);
337 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
339 // Populate the outputs from the existing network.
340 networkId.value = netInfo.getId ();
341 neutronNetworkId.value = netInfo.getId ();
342 rollback.value = networkRollback; // Default rollback - no updates performed
343 logger.warn("{} {} Found Existing network, status={} for Neutron mode ",
344 MessageEnum.RA_NETWORK_ALREADY_EXIST, MsoLogger.ErrorCode.DataError.getValue(),
345 netInfo.getStatus());
350 long createNetworkStarttime = System.currentTimeMillis ();
352 netInfo = neutron.createNetwork (cloudSiteId,
358 } catch (MsoException me) {
359 me.addContext(CREATE_NETWORK_CONTEXT);
360 logger.error("{} {} Create Network: type {} in {}/{}: ", MessageEnum.RA_CREATE_NETWORK_EXC,
361 MsoLogger.ErrorCode.DataError.getValue(), neutronNetworkType, cloudSiteId, tenantId, me);
363 throw new NetworkException (me);
366 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
368 // If reach this point, network creation is successful.
369 // Since directly created via Neutron, networkId tracked by MSO is the same
370 // as the neutron network ID.
371 networkId.value = netInfo.getId ();
372 neutronNetworkId.value = netInfo.getId ();
374 networkRollback.setNetworkCreated (true);
375 networkRollback.setNetworkId (netInfo.getId ());
376 networkRollback.setNeutronNetworkId (netInfo.getId ());
377 networkRollback.setNetworkType (networkType);
379 logger.debug("Network {} created, id = {}", networkName, netInfo.getId());
380 } else if ("HEAT".equals (mode)) {
382 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
383 if (heatTemplate == null) {
384 String error = String
385 .format("Network error - undefined Heat Template. Network Type = %s", networkType);
386 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
388 throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
391 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
393 // "Fix" the template if it has CR/LF (getting this from Oracle)
394 String template = heatTemplate.getHeatTemplate ();
395 template = template.replaceAll ("\r\n", "\n");
397 boolean aic3template=false;
398 String aic3nw = AIC3_NW;
400 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
402 if (template.contains(aic3nw))
405 // First, look up to see if the Network already exists (by name).
406 // For HEAT orchestration of networks, the stack name will always match the network name
407 StackInfo heatStack = null;
408 long queryNetworkStarttime = System.currentTimeMillis ();
410 heatStack = heat.queryStack (cloudSiteId, tenantId, networkName);
411 } catch (MsoException me) {
412 me.addContext (CREATE_NETWORK_CONTEXT);
413 logger.error("{} {} Create Network (heat): query network {} in {}/{}: ",
414 MessageEnum.RA_QUERY_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(), networkName,
415 cloudSiteId, tenantId, me);
416 throw new NetworkException (me);
419 if (heatStack != null && (heatStack.getStatus () != HeatStatus.NOTFOUND)) {
420 // Stack exists. Return success or error depending on input directive
421 if (failIfExists != null && failIfExists) {
422 String error = String
423 .format("CreateNetwork: Stack %s already exists in %s/%s as %s", networkName, cloudSiteId,
424 tenantId, heatStack.getCanonicalName());
425 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ALREADY_EXIST,
426 MsoLogger.ErrorCode.DataError.getValue(), error);
427 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
429 // Populate the outputs from the existing stack.
430 networkId.value = heatStack.getCanonicalName ();
431 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
432 rollback.value = networkRollback; // Default rollback - no updates performed
435 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
437 Map <String, Object> outputs = heatStack.getOutputs ();
438 Map <String, String> sMap = new HashMap <> ();
439 if (outputs != null) {
440 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
441 String key=entry.getKey();
442 if (key != null && key.startsWith ("subnet")) {
443 if (aic3template) //one subnet_id output
445 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
448 else //multiples subnet_%aaid% outputs
450 String subnetUUId = (String) outputs.get(key);
451 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
456 subnetIdMap.value = sMap;
457 logger.warn("{} {} Found Existing network stack, status={} networkName={} for {}/{}",
458 MessageEnum.RA_NETWORK_ALREADY_EXIST, MsoLogger.ErrorCode.DataError.getValue(),
459 heatStack.getStatus(), networkName, cloudSiteId, tenantId);
464 // Ready to deploy the new Network
465 // Build the common set of HEAT template parameters
466 Map <String, Object> stackParams = populateNetworkParams (neutronNetworkType,
475 // Validate (and update) the input parameters against the DB definition
476 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
477 // and inputs were already validated.
479 stackParams = heat.validateStackParams (stackParams, heatTemplate);
480 } catch (IllegalArgumentException e) {
481 String error = "Create Network: Configuration Error: " + e.getMessage ();
482 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC,
483 MsoLogger.ErrorCode.DataError.getValue(), error,e);
484 // Input parameters were not valid
485 throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
488 if (subnets != null) {
492 template = mergeSubnetsAIC3 (template, subnets, stackParams);
496 template = mergeSubnets (template, subnets);
498 } catch (MsoException me) {
499 me.addContext (CREATE_NETWORK_CONTEXT);
501 .error("{} {} Exception Create Network, merging subnets for network (heat) type {} in {}/{} ",
502 MessageEnum.RA_CREATE_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(),
503 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
504 throw new NetworkException (me);
508 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
510 mergePolicyRefs (policyFqdns, stackParams);
511 } catch (MsoException me) {
512 me.addContext (CREATE_NETWORK_CONTEXT);
513 logger.error("{} {} Exception Create Network, merging policyRefs type {} in {}/{} ",
514 MessageEnum.RA_CREATE_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(),
515 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
516 throw new NetworkException (me);
520 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
522 mergeRouteTableRefs (routeTableFqdns, stackParams);
523 } catch (MsoException me) {
524 me.addContext (CREATE_NETWORK_CONTEXT);
525 logger.error("{} {} Exception Create Network, merging routeTableRefs type {} in {}/{} ",
526 MessageEnum.RA_CREATE_NETWORK_EXC, MsoLogger.ErrorCode.DataError.getValue(),
527 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
528 throw new NetworkException (me);
532 // Deploy the network stack
533 // Ignore MsoStackAlreadyExists exception because we already checked.
537 heatStack = heat.createStack (cloudSiteId,
543 heatTemplate.getTimeoutMinutes (),
547 backout.booleanValue());
548 } catch (MsoException me) {
549 me.addContext (CREATE_NETWORK_CONTEXT);
551 .error("{} {} Exception creating network type {} in {}/{} ", MessageEnum.RA_CREATE_NETWORK_EXC,
552 MsoLogger.ErrorCode.DataError.getValue(), networkName, cloudSiteId, tenantId, me);
553 throw new NetworkException (me);
556 // Reach this point if createStack is successful.
558 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
559 // and the neutronNetworkId is the network UUID returned in stack outputs.
560 networkId.value = heatStack.getCanonicalName ();
561 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
564 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
566 Map <String, Object> outputs = heatStack.getOutputs ();
567 Map <String, String> sMap = new HashMap <> ();
568 if (outputs != null) {
569 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
570 String key = entry.getKey();
571 if (key != null && key.startsWith ("subnet")) {
572 if (aic3template) //one subnet output expected
574 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
577 else //multiples subnet_%aaid% outputs allowed
579 String subnetUUId = (String) outputs.get(key);
580 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
585 subnetIdMap.value = sMap;
587 rollback.value = networkRollback;
588 // Populate remaining rollback info and response parameters.
589 networkRollback.setNetworkStackId (heatStack.getCanonicalName ());
590 networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID));
591 networkRollback.setNetworkCreated (true);
592 networkRollback.setNetworkType (networkType);
594 logger.debug("Network {} successfully created via HEAT", networkName);
601 public void updateNetwork (String cloudSiteId,
604 String modelCustomizationUuid,
607 String physicalNetworkName,
608 List <Integer> vlans,
611 List <Subnet> subnets,
612 Map<String,String> networkParams,
613 MsoRequest msoRequest,
614 Holder <Map <String, String>> subnetIdMap,
615 Holder <NetworkRollback> rollback) throws NetworkException {
616 updateNetwork (cloudSiteId,
619 modelCustomizationUuid,
637 public void updateNetworkContrail (String cloudSiteId,
640 String modelCustomizationUuid,
643 List <RouteTarget> routeTargets,
646 List <Subnet> subnets,
647 Map<String, String> networkParams,
648 List <String> policyFqdns,
649 List<String> routeTableFqdns,
650 MsoRequest msoRequest,
651 Holder <Map <String, String>> subnetIdMap,
652 Holder <NetworkRollback> rollback) throws NetworkException {
653 updateNetwork (cloudSiteId,
656 modelCustomizationUuid,
673 * This is the "Update Network" web service implementation.
674 * It will update an existing Network of the requested type in the specified cloud
675 * and tenant. The typical use will be to replace the VLANs with the supplied
676 * list (to add or remove a VLAN), but other properties may be updated as well.
678 * There will be a pre-defined set of network types defined in the MSO Catalog.
679 * All such networks will have a similar configuration, based on the allowable
680 * Openstack networking definitions. This includes basic networks, provider
681 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
683 * Initially, all provider networks must currently be "vlan" type, and multi-provider
684 * networks must be multiple VLANs on the same physical network.
686 * This service supports two modes of Network update:
687 * - via Heat Templates
689 * The network orchestration mode for each network type is declared in its
690 * catalog definition. All Heat-based templates must support some subset of
691 * the same input parameters: network_name, physical_network, vlan, segments.
693 * The method returns a NetworkRollback object. This object can be passed
694 * as-is to the rollbackNetwork operation to undo everything that was updated.
695 * This is useful if a network is successfully updated but orchestration
696 * fails on a subsequent operation.
698 private void updateNetwork (String cloudSiteId,
701 String modelCustomizationUuid,
704 String physicalNetworkName,
705 List <Integer> vlans,
706 List <RouteTarget> routeTargets,
709 List <Subnet> subnets,
710 List <String> policyFqdns,
711 List<String> routeTableFqdns,
712 MsoRequest msoRequest,
713 Holder <Map <String, String>> subnetIdMap,
714 Holder <NetworkRollback> rollback) throws NetworkException {
715 MsoLogger.setLogContext (msoRequest);
716 logger.debug("***UPDATE Network adapter with Network: {} of type {} in {}/{}", networkName, networkType,
717 cloudSiteId, tenantId);
719 // Will capture execution time for metrics
720 long startTime = System.currentTimeMillis ();
722 // Build a default rollback object (no actions performed)
723 NetworkRollback networkRollback = new NetworkRollback ();
724 networkRollback.setCloudId (cloudSiteId);
725 networkRollback.setTenantId (tenantId);
726 networkRollback.setMsoRequest (msoRequest);
728 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
729 if (!cloudSiteOpt.isPresent()) {
730 String error = String.format(
731 "UpdateNetwork: Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
732 networkName, cloudSiteId, tenantId);
733 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
734 // Set the detailed error as the Exception 'message'
735 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
741 NetworkResource networkResource = networkCheck(
744 modelCustomizationUuid,
751 String mode = networkResource.getOrchestrationMode();
752 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
754 // Use an MsoNeutronUtils for all Neutron commands
756 if (NEUTRON_MODE.equals(mode)) {
758 // Verify that the Network exists
759 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
760 NetworkInfo netInfo = null;
761 long queryNetworkStarttime = System.currentTimeMillis();
763 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
764 } catch (MsoException me) {
765 me.addContext(UPDATE_NETWORK_CONTEXT);
766 logger.error("{} {} Exception - queryNetwork query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
767 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), networkId, cloudSiteId, tenantId, me);
768 throw new NetworkException(me);
771 if (netInfo == null) {
772 String error = String
773 .format("Update Nework: Network %s does not exist in %s/%s", networkId, cloudSiteId, tenantId);
774 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND,
775 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), error);
776 // Does not exist. Throw an exception (can't update a non-existent network)
777 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
779 long updateNetworkStarttime = System.currentTimeMillis();
781 netInfo = neutron.updateNetwork(cloudSiteId,
787 } catch (MsoException me) {
788 me.addContext(UPDATE_NETWORK_CONTEXT);
789 logger.error("{} {} Exception - updateNetwork {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
790 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
791 throw new NetworkException(me);
794 // Add the network ID and previously queried vlans to the rollback object
795 networkRollback.setNetworkId(netInfo.getId());
796 networkRollback.setNeutronNetworkId(netInfo.getId());
797 networkRollback.setNetworkType(networkType);
798 // Save previous parameters
799 networkRollback.setNetworkName(netInfo.getName());
800 networkRollback.setPhysicalNetwork(netInfo.getProvider());
801 networkRollback.setVlans(netInfo.getVlans());
803 logger.debug("Network {} updated, id = {}", networkId, netInfo.getId());
804 } else if ("HEAT".equals(mode)) {
806 // First, look up to see that the Network already exists.
807 // For Heat-based orchestration, the networkId is the network Stack ID.
808 StackInfo heatStack = null;
809 long queryStackStarttime = System.currentTimeMillis();
811 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
812 } catch (MsoException me) {
813 me.addContext(UPDATE_NETWORK_CONTEXT);
814 logger.error("{} {} Exception - QueryStack query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
815 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
816 throw new NetworkException(me);
819 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
820 String error = String
821 .format("UpdateNetwork: Stack %s does not exist in %s/%s", networkName, cloudSiteId, tenantId);
822 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
824 // Network stack does not exist. Return an error
825 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
828 // Get the previous parameters for rollback
829 Map<String, Object> heatParams = heatStack.getParameters();
831 String previousNetworkName = (String) heatParams.get("network_name");
832 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
834 List<Integer> previousVlans = new ArrayList<>();
835 String vlansParam = (String) heatParams.get(VLANS);
836 if (vlansParam != null) {
837 for (String vlan : vlansParam.split(",")) {
839 previousVlans.add(Integer.parseInt(vlan));
840 } catch (NumberFormatException e) {
841 logger.warn("{} {} Exception - VLAN parse for params {} ", MessageEnum.RA_VLAN_PARSE,
842 MsoLogger.ErrorCode.DataError.getValue(), vlansParam, e);
846 logger.debug("Update Stack: Previous VLANS: {}", previousVlans);
848 // Ready to deploy the updated Network via Heat
851 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
852 if (heatTemplate == null) {
853 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
854 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
856 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
859 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
861 // "Fix" the template if it has CR/LF (getting this from Oracle)
862 String template = heatTemplate.getHeatTemplate();
863 template = template.replaceAll("\r\n", "\n");
865 boolean aic3template = false;
866 String aic3nw = AIC3_NW;
868 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
870 if (template.contains(aic3nw))
873 // Build the common set of HEAT template parameters
874 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
883 // Validate (and update) the input parameters against the DB definition
884 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
886 stackParams = heat.validateStackParams(stackParams, heatTemplate);
887 } catch (IllegalArgumentException e) {
888 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
889 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
890 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
893 if (subnets != null) {
896 template = mergeSubnetsAIC3(template, subnets, stackParams);
898 template = mergeSubnets(template, subnets);
900 } catch (MsoException me) {
901 me.addContext(UPDATE_NETWORK_CONTEXT);
902 logger.error("{} {} Exception - UpdateNetwork mergeSubnets for network type {} in {}/{} ",
903 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
904 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
905 throw new NetworkException(me);
909 if (policyFqdns != null && aic3template) {
911 mergePolicyRefs(policyFqdns, stackParams);
912 } catch (MsoException me) {
913 me.addContext(UPDATE_NETWORK_CONTEXT);
914 logger.error("{} {} Exception - UpdateNetwork mergePolicyRefs type {} in {}/{} ",
915 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
916 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
917 throw new NetworkException(me);
921 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
923 mergeRouteTableRefs(routeTableFqdns, stackParams);
924 } catch (MsoException me) {
925 me.addContext(UPDATE_NETWORK_CONTEXT);
926 logger.error("{} {} Exception - UpdateNetwork mergeRouteTableRefs type {} in {}/{} ",
927 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
928 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
929 throw new NetworkException(me);
933 // Update the network stack
934 // Ignore MsoStackNotFound exception because we already checked.
935 long updateStackStarttime = System.currentTimeMillis();
937 heatStack = heatWithUpdate.updateStack(cloudSiteId,
943 heatTemplate.getTimeoutMinutes());
944 } catch (MsoException me) {
945 me.addContext(UPDATE_NETWORK_CONTEXT);
946 logger.error("{} {} Exception - update network {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
947 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
948 throw new NetworkException(me);
951 Map<String, Object> outputs = heatStack.getOutputs();
952 Map<String, String> sMap = new HashMap<>();
953 if (outputs != null) {
954 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
955 String key=entry.getKey();
956 if (key != null && key.startsWith("subnet")) {
957 if (aic3template) //one subnet output expected
959 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
961 } else //multiples subnet_%aaid% outputs allowed
963 String subnetUUId = (String) outputs.get(key);
964 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
969 subnetIdMap.value = sMap;
971 // Reach this point if createStack is successful.
972 // Populate remaining rollback info and response parameters.
973 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
974 if(null != outputs) {
975 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
978 logger.debug("outputs is NULL");
980 networkRollback.setNetworkType(networkType);
981 // Save previous parameters
982 networkRollback.setNetworkName(previousNetworkName);
983 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
984 networkRollback.setVlans(previousVlans);
986 rollback.value = networkRollback;
988 logger.debug("Network {} successfully updated via HEAT", networkId);
994 private NetworkResource networkCheck (long startTime,
996 String modelCustomizationUuid,
998 String physicalNetworkName,
999 List <Integer> vlans,
1000 List <RouteTarget> routeTargets,
1002 CloudSite cloudSite) throws NetworkException {
1003 // Retrieve the Network Resource definition
1004 NetworkResource networkResource = null;
1005 NetworkResourceCustomization networkCust = null;
1006 CollectionNetworkResourceCustomization collectionNetworkCust = null;
1007 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1008 if (!commonUtils.isNullOrEmpty(networkType)) {
1009 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1012 networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1013 if (networkCust == null) {
1014 collectionNetworkCust = collectionNetworkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1017 if(networkCust != null){
1018 logger.debug("Got Network Customization definition from Catalog: {}", networkCust.toString());
1020 networkResource = networkCust.getNetworkResource();
1021 } else if (collectionNetworkCust != null) {
1022 logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}",
1023 collectionNetworkCust.toString());
1024 networkResource = collectionNetworkCust.getNetworkResource();
1026 if (networkResource == null) {
1027 String error = String.format(
1028 "Create/UpdateNetwork: Unable to get network resource with NetworkType: %s or ModelCustomizationUUID:%s",
1029 networkType, modelCustomizationUuid);
1030 logger.error("{} {} {} ", MessageEnum.RA_UNKOWN_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1032 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1034 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1036 String mode = networkResource.getOrchestrationMode();
1037 NetworkType neutronNetworkType = NetworkType
1038 .valueOf(networkResource.getNeutronNetworkType());
1040 // All Networks are orchestrated via HEAT or Neutron
1041 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1042 String error = "CreateNetwork: Configuration Error: Network Type = " + networkType;
1043 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1044 MsoLogger.ErrorCode.DataError.getValue(), error);
1045 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1048 MavenLikeVersioning aicV = new MavenLikeVersioning();
1049 aicV.setVersion(cloudSite.getCloudVersion());
1050 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1051 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1054 && (aicV.isTheSameVersion(networkResource
1055 .getAicVersionMax()) || !(aicV
1056 .isMoreRecentThan(networkResource
1057 .getAicVersionMax())))) // aic <= max
1059 logger.debug("Network Type:{} VersionMin:{} VersionMax:{} supported on Cloud:{} with AIC_Version:{}",
1060 networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId,
1061 cloudSite.getCloudVersion());
1063 String error = String
1064 .format("Network Type:%s Version_Min:%s Version_Max:%s not supported on Cloud:%s with AIC_Version:%s",
1065 networkType, networkType, networkResource.getAicVersionMin(),
1066 networkResource.getAicVersionMax(), cloudSiteId, cloudSite.getCloudVersion());
1067 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
1068 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1071 // Validate the Network parameters.
1072 String missing = validateNetworkParams(neutronNetworkType,
1073 networkName, physicalNetworkName, vlans, routeTargets);
1074 if (!missing.isEmpty()) {
1075 String error = "Create Network: Missing parameters: " + missing;
1076 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1078 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1081 return networkResource;
1085 public void queryNetwork (String cloudSiteId,
1087 String networkNameOrId,
1088 MsoRequest msoRequest,
1089 Holder <Boolean> networkExists,
1090 Holder <String> networkId,
1091 Holder <String> neutronNetworkId,
1092 Holder <NetworkStatus> status,
1093 Holder <List <Integer>> vlans,
1094 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1095 queryNetwork (cloudSiteId,
1109 public void queryNetworkContrail (String cloudSiteId,
1111 String networkNameOrId,
1112 MsoRequest msoRequest,
1113 Holder <Boolean> networkExists,
1114 Holder <String> networkId,
1115 Holder <String> neutronNetworkId,
1116 Holder <NetworkStatus> status,
1117 Holder <List <RouteTarget>> routeTargets,
1118 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1119 queryNetwork (cloudSiteId,
1133 * This is the queryNetwork method. It returns the existence and status of
1134 * the specified network, along with its Neutron UUID and list of VLANs.
1135 * This method attempts to find the network using both Heat and Neutron.
1136 * Heat stacks are first searched based on the provided network name/id.
1137 * If none is found, the Neutron is directly queried.
1139 private void queryNetwork (String cloudSiteId,
1141 String networkNameOrId,
1142 MsoRequest msoRequest,
1143 Holder <Boolean> networkExists,
1144 Holder <String> networkId,
1145 Holder <String> neutronNetworkId,
1146 Holder <NetworkStatus> status,
1147 Holder <List <Integer>> vlans,
1148 Holder <List <RouteTarget>> routeTargets,
1149 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1150 MsoLogger.setLogContext (msoRequest);
1151 logger.debug("*** QUERY Network with Network: {} in {}/{}", networkNameOrId, cloudSiteId, tenantId);
1153 // Will capture execution time for metrics
1154 long startTime = System.currentTimeMillis ();
1156 if (commonUtils.isNullOrEmpty (cloudSiteId)
1157 || commonUtils.isNullOrEmpty(tenantId)
1158 || commonUtils.isNullOrEmpty(networkNameOrId)) {
1160 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1161 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1162 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1165 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1166 if (!cloudSiteOpt.isPresent())
1168 String error = String
1169 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
1170 networkNameOrId, cloudSiteId, tenantId);
1171 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
1172 // Set the detailed error as the Exception 'message'
1173 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1176 // Use MsoNeutronUtils for all NEUTRON commands
1180 // Try Heat first, since networks may be named the same as the Heat stack
1181 StackInfo heatStack = null;
1182 long queryStackStarttime = System.currentTimeMillis ();
1184 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1185 } catch (MsoException me) {
1186 me.addContext ("QueryNetwork");
1187 logger.error("{} {} Exception - Query Network (heat): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1188 MsoLogger.ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1189 throw new NetworkException (me);
1192 // Populate the outputs based on the returned Stack information
1193 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1194 // Found it. Get the neutronNetworkId for further query
1195 Map <String, Object> outputs = heatStack.getOutputs ();
1196 neutronId = (String) outputs.get (NETWORK_ID);
1199 Map <String, String> sMap = new HashMap <> ();
1200 if (outputs != null) {
1201 for (String key : outputs.keySet ()) {
1202 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1204 String subnetUUId = (String) outputs.get(key);
1205 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1207 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1209 Map <String, String> map = getSubnetUUId(key, outputs, null);
1215 subnetIdMap.value = sMap;
1217 // Input ID was not a Heat stack ID. Try it directly in Neutron
1218 neutronId = networkNameOrId;
1219 mode = NEUTRON_MODE;
1222 // Query directly against the Neutron Network for the details
1223 // no RouteTargets available for ContrailV2 in neutron net-show
1224 // networkId is heatStackId
1225 long queryNetworkStarttime = System.currentTimeMillis ();
1227 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1228 if (netInfo != null) {
1229 // Found. Populate the output elements
1230 networkExists.value = Boolean.TRUE;
1231 if ("HEAT".equals (mode)) {
1232 networkId.value = heatStack.getCanonicalName ();
1234 networkId.value = netInfo.getId ();
1236 neutronNetworkId.value = netInfo.getId ();
1237 status.value = netInfo.getStatus ();
1239 vlans.value = netInfo.getVlans ();
1241 logger.debug("Network {} found({}), ID = {}{}", networkNameOrId, mode, networkId.value,
1242 ("HEAT".equals(mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1244 // Not found. Populate the status fields, leave the rest null
1245 networkExists.value = Boolean.FALSE;
1246 status.value = NetworkStatus.NOTFOUND;
1247 neutronNetworkId.value = null;
1249 vlans.value = new ArrayList<>();
1251 logger.debug("Network {} not found", networkNameOrId);
1253 } catch (MsoException me) {
1254 me.addContext ("QueryNetwork");
1255 logger.error("{} {} Exception - Query Network (neutron): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1256 MsoLogger.ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1257 throw new NetworkException (me);
1263 * This is the "Delete Network" web service implementation.
1264 * It will delete a Network in the specified cloud and tenant.
1266 * If the network is not found, it is treated as a success.
1268 * This service supports two modes of Network creation/update/delete:
1269 * - via Heat Templates
1271 * The network orchestration mode for each network type is declared in its
1272 * catalog definition.
1274 * For Heat-based orchestration, the networkId should be the stack ID.
1275 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1277 * The method returns nothing on success. Rollback is not possible for delete
1278 * commands, so any failure on delete will require manual fallout in the client.
1281 public void deleteNetwork (String cloudSiteId,
1284 String modelCustomizationUuid,
1286 MsoRequest msoRequest,
1287 Holder <Boolean> networkDeleted) throws NetworkException {
1288 MsoLogger.setLogContext (msoRequest);
1289 logger.debug("*** DELETE Network adapter with Network: {} in {}/{}", networkId, cloudSiteId, tenantId);
1291 // Will capture execution time for metrics
1292 long startTime = System.currentTimeMillis ();
1295 if (commonUtils.isNullOrEmpty (cloudSiteId)
1296 || commonUtils.isNullOrEmpty(tenantId)
1297 || commonUtils.isNullOrEmpty(networkId)) {
1298 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1299 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1300 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1303 // Retrieve the Network Resource definition
1304 NetworkResource networkResource = null;
1306 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1307 if (!commonUtils.isNullOrEmpty(networkType)) {
1308 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1311 NetworkResourceCustomization nrc = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1313 networkResource = nrc.getNetworkResource();
1318 if (networkResource != null) {
1319 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1321 mode = networkResource.getOrchestrationMode ();
1324 if (NEUTRON_MODE.equals (mode)) {
1326 // Use MsoNeutronUtils for all NEUTRON commands
1327 long deleteNetworkStarttime = System.currentTimeMillis ();
1329 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1330 // was not found. So don't bother to query first.
1331 boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1332 networkDeleted.value = deleted;
1333 } catch (MsoException me) {
1334 me.addContext ("DeleteNetwork");
1335 logger.error("{} {} Delete Network (neutron): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1336 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1337 throw new NetworkException (me);
1339 } else { // DEFAULT to ("HEAT".equals (mode))
1340 long deleteStackStarttime = System.currentTimeMillis ();
1343 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1344 // So query first to report back if stack WAS deleted or just NOTOFUND
1345 StackInfo heatStack = null;
1346 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1347 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND)
1349 heat.deleteStack (tenantId, cloudSiteId, networkId, true);
1350 networkDeleted.value = true;
1354 networkDeleted.value = false;
1356 } catch (MsoException me) {
1357 me.addContext ("DeleteNetwork");
1358 logger.error("{} {} Delete Network (heat): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1359 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1360 throw new NetworkException (me);
1365 // On success, nothing is returned.
1370 * This web service endpoint will rollback a previous Create VNF operation.
1371 * A rollback object is returned to the client in a successful creation
1372 * response. The client can pass that object as-is back to the rollbackVnf
1373 * operation to undo the creation.
1375 * The rollback includes removing the VNF and deleting the tenant if the
1376 * tenant did not exist prior to the VNF creation.
1379 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1380 // Will capture execution time for metrics
1381 long startTime = System.currentTimeMillis ();
1383 if (rollback == null) {
1385 .error("{} {} rollback is null", MessageEnum.RA_ROLLBACK_NULL, MsoLogger.ErrorCode.DataError.getValue());
1389 MsoLogger.setLogContext (rollback.getMsoRequest());
1391 // Get the elements of the VnfRollback object for easier access
1392 String cloudSiteId = rollback.getCloudId ();
1393 String tenantId = rollback.getTenantId ();
1394 String networkId = rollback.getNetworkStackId ();
1395 String networkType = rollback.getNetworkType ();
1396 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1398 logger.debug("*** ROLLBACK Network {} in {}/{}", networkId, cloudSiteId, tenantId);
1401 // Retrieve the Network Resource definition
1402 NetworkResource networkResource = null;
1403 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1404 networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource();
1406 networkResource = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource();
1409 if (networkResource != null) {
1411 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1413 mode = networkResource.getOrchestrationMode ();
1416 if (rollback.getNetworkCreated ()) {
1417 // Rolling back a newly created network, so delete it.
1418 if (NEUTRON_MODE.equals (mode)) {
1419 // Use MsoNeutronUtils for all NEUTRON commands
1420 long deleteNetworkStarttime = System.currentTimeMillis ();
1422 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1423 // was not found. So don't bother to query first.
1424 neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1425 } catch (MsoException me) {
1426 me.addContext ("RollbackNetwork");
1427 logger.error("{} {} Exception - Rollback Network (neutron): {} in {}/{} ",
1428 MessageEnum.RA_DELETE_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1429 networkId, cloudSiteId, tenantId, me);
1430 throw new NetworkException (me);
1432 } else { // DEFAULT to if ("HEAT".equals (mode))
1433 long deleteStackStarttime = System.currentTimeMillis ();
1435 // The deleteStack function in MsoHeatUtils returns success if the stack
1436 // was not found. So don't bother to query first.
1437 heat.deleteStack (tenantId, cloudSiteId, networkId, true);
1438 } catch (MsoException me) {
1439 me.addContext ("RollbackNetwork");
1440 logger.error("{} {} Exception - Rollback Network (heat): {} in {}/{} ",
1441 MessageEnum.RA_DELETE_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1442 networkId, cloudSiteId, tenantId, me);
1443 throw new NetworkException (me);
1451 private String validateNetworkParams (NetworkType neutronNetworkType,
1453 String physicalNetwork,
1454 List <Integer> vlans,
1455 List <RouteTarget> routeTargets) {
1457 StringBuilder missing = new StringBuilder ();
1458 if (commonUtils.isNullOrEmpty(networkName)) {
1459 missing.append ("networkName");
1463 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1464 if (commonUtils.isNullOrEmpty(physicalNetwork)) {
1465 missing.append (sep).append ("physicalNetworkName");
1468 if (vlans == null || vlans.isEmpty ()) {
1469 missing.append (sep).append (VLANS);
1473 return missing.toString ();
1476 private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1478 String physicalNetwork,
1479 List <Integer> vlans,
1480 List <RouteTarget> routeTargets,
1483 boolean aic3template) {
1484 // Build the common set of HEAT template parameters
1485 Map <String, Object> stackParams = new HashMap <> ();
1486 stackParams.put ("network_name", networkName);
1488 if (neutronNetworkType == NetworkType.PROVIDER) {
1489 // For Provider type
1490 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1491 stackParams.put ("vlan", vlans.get (0).toString ());
1492 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1493 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1494 // It supports all ProviderNet properties except segmentation_id, and adds a
1495 // comma-separated-list of VLANs as a "segments" property.
1496 // Note that this does not match the Neutron definition of Multi-Provider network,
1497 // which contains a list of 'segments', each having physical_network, network_type,
1498 // and segmentation_id.
1499 StringBuilder buf = new StringBuilder ();
1501 for (Integer vlan : vlans) {
1502 buf.append (sep).append (vlan.toString ());
1505 String csl = buf.toString ();
1507 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1508 stackParams.put (VLANS, csl);
1510 if (routeTargets != null) {
1512 String rtGlobal = "";
1513 String rtImport = "";
1514 String rtExport = "";
1516 for (RouteTarget rt : routeTargets) {
1517 boolean rtIsNull = false;
1520 String routeTarget = rt.getRouteTarget();
1521 String routeTargetRole = rt.getRouteTargetRole();
1522 logger.debug("Checking for an actually null route target: {}", rt);
1523 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1525 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1531 logger.debug("Input RT:{}", rt);
1532 String role = rt.getRouteTargetRole();
1533 String rtValue = rt.getRouteTarget();
1535 if ("IMPORT".equalsIgnoreCase(role))
1537 sep = rtImport.isEmpty() ? "" : ",";
1538 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1540 else if ("EXPORT".equalsIgnoreCase(role))
1542 sep = rtExport.isEmpty() ? "" : ",";
1543 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1545 else // covers BOTH, empty etc
1547 sep = rtGlobal.isEmpty() ? "" : ",";
1548 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1554 if (!rtImport.isEmpty())
1556 stackParams.put ("route_targets_import", rtImport);
1558 if (!rtExport.isEmpty())
1560 stackParams.put ("route_targets_export", rtExport);
1562 if (!rtGlobal.isEmpty())
1564 stackParams.put ("route_targets", rtGlobal);
1567 if (commonUtils.isNullOrEmpty(shared)) {
1568 stackParams.put ("shared", "False");
1570 stackParams.put ("shared", shared);
1572 if (commonUtils.isNullOrEmpty(external)) {
1573 stackParams.put ("external", "False");
1575 stackParams.put ("external", external);
1582 /** policyRef_list structure in stackParams
1585 "network_policy_refs_data_sequence": {
1586 "network_policy_refs_data_sequence_major": "1",
1587 "network_policy_refs_data_sequence_minor": "0"
1591 "network_policy_refs_data_sequence": {
1592 "network_policy_refs_data_sequence_major": "2",
1593 "network_policy_refs_data_sequence_minor": "0"
1598 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1600 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1602 for (String pf : pFqdns) {
1603 if (!commonUtils.isNullOrEmpty(pf))
1605 ContrailPolicyRef pr = new ContrailPolicyRef();
1606 ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0");
1609 logger.debug("Contrail PolicyRefs Data:{}", pr);
1614 JsonNode node = null;
1617 ObjectMapper mapper = new ObjectMapper();
1618 node = mapper.convertValue(prlist, JsonNode.class);
1619 String jsonString = mapper.writeValueAsString(prlist);
1620 logger.debug("Json PolicyRefs Data:{}", jsonString);
1624 String error = "Error creating JsonNode for policyRefs Data";
1625 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1627 throw new MsoAdapterException (error);
1630 if (pFqdns != null && node != null)
1632 StringBuilder buf = new StringBuilder ();
1634 for (String pf : pFqdns) {
1635 if (!commonUtils.isNullOrEmpty(pf))
1637 buf.append (sep).append (pf);
1641 String csl = buf.toString ();
1642 stackParams.put ("policy_refs", csl);
1643 stackParams.put ("policy_refsdata", node);
1646 logger.debug("StackParams updated with policy refs");
1650 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1653 if (rtFqdns != null)
1655 StringBuilder buf = new StringBuilder ();
1657 for (String rtf : rtFqdns) {
1658 if (!commonUtils.isNullOrEmpty(rtf))
1660 buf.append (sep).append (rtf);
1664 String csl = buf.toString ();
1665 stackParams.put ("route_table_refs", csl);
1668 logger.debug("StackParams updated with route_table refs");
1673 /*** Subnet Output structure from Juniper
1678 "ip_prefix": "10.100.1.0",
1681 "addr_from_start": null,
1682 "enable_dhcp": false,
1683 "default_gateway": "10.100.1.1",
1684 "dns_nameservers": [],
1685 "dhcp_option_list": null,
1686 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
1687 "allocation_pools": [
1689 "start": "10.100.1.3",
1693 "start": "10.100.1.6",
1697 "host_routes": null,
1698 "dns_server_address": "10.100.1.13",
1699 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
1703 "ip_prefix": "10.100.2.16",
1706 "addr_from_start": null,
1707 "enable_dhcp": true,
1708 "default_gateway": "10.100.2.17",
1709 "dns_nameservers": [],
1710 "dhcp_option_list": null,
1711 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
1712 "allocation_pools": [
1714 "start": "10.100.2.18",
1715 "end": "10.100.2.20"
1718 "host_routes": null,
1719 "dns_server_address": "10.100.2.29",
1720 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
1726 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
1729 List<ContrailSubnet> cslist = new ArrayList <> ();
1730 for (Subnet subnet : subnets) {
1731 logger.debug("Input Subnet:{}", subnet.toString());
1732 ContrailSubnet cs = new ContrailSubnetMapper(subnet).map();
1733 logger.debug("Contrail Subnet:{}", cs.toString());
1737 JsonNode node = null;
1740 ObjectMapper mapper = new ObjectMapper();
1741 node = mapper.convertValue(cslist, JsonNode.class);
1742 String jsonString = mapper.writeValueAsString(cslist);
1743 logger.debug("Json Subnet List:{}", jsonString);
1747 String error = "Error creating JsonNode from input subnets";
1748 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, MsoLogger.ErrorCode.DataError.getValue(), error, e);
1749 throw new MsoAdapterException (error);
1754 stackParams.put ("subnet_list", node);
1756 //Outputs - All subnets are in one ipam_subnets structure
1757 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
1758 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
1760 // append outputs in heatTemplate
1761 int outputsIdx = heatTemplate.indexOf ("outputs:");
1762 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
1763 logger.debug("Template updated with all AIC3.0 subnets:{}", heatTemplate);
1764 return heatTemplate;
1768 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
1770 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
1773 + " network_id: { get_resource: network }\n"
1774 + " cidr: %cidr%\n";
1776 /* make these optional
1777 + " ip_version: %ipversion%\n"
1778 + " enable_dhcp: %enabledhcp%\n"
1779 + " gateway_ip: %gatewayip%\n"
1780 + " allocation_pools:\n"
1781 + " - start: %poolstart%\n"
1782 + " end: %poolend%\n";
1786 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
1787 + " value: {get_resource: subnet_%subnetId%}\n";
1791 StringBuilder resourcesBuf = new StringBuilder ();
1792 StringBuilder outputsBuf = new StringBuilder ();
1793 for (Subnet subnet : subnets) {
1795 // build template for each subnet
1796 curR = resourceTempl;
1797 if (subnet.getSubnetId () != null) {
1798 curR = curR.replace ("%subnetId%", subnet.getSubnetId ());
1800 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
1801 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1802 throw new MsoAdapterException (error);
1805 if (subnet.getSubnetName () != null) {
1806 curR = curR.replace ("%name%", subnet.getSubnetName ());
1808 curR = curR.replace ("%name%", subnet.getSubnetId ());
1811 if (subnet.getCidr () != null) {
1812 curR = curR.replace ("%cidr%", subnet.getCidr ());
1814 String error = "Missing Required cidr for subnet in HEAT Template";
1815 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1816 throw new MsoAdapterException (error);
1819 if (subnet.getIpVersion () != null) {
1820 curR = curR + " ip_version: " + subnet.getIpVersion () + "\n";
1822 if (subnet.getEnableDHCP () != null) {
1823 curR = curR + " enable_dhcp: " + Boolean.toString (subnet.getEnableDHCP ()) + "\n";
1825 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
1826 curR = curR + " gateway_ip: " + subnet.getGatewayIp () + "\n";
1829 if (subnet.getAllocationPools() != null) {
1830 curR = curR + " allocation_pools:\n";
1831 for (Pool pool : subnet.getAllocationPools())
1833 if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd()))
1835 curR = curR + " - start: " + pool.getStart () + "\n";
1836 curR = curR + " end: " + pool.getEnd () + "\n";
1841 resourcesBuf.append (curR);
1844 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
1846 outputsBuf.append (curO);
1849 // append resources and outputs in heatTemplate
1850 logger.debug("Tempate initial:{}", heatTemplate);
1851 int outputsIdx = heatTemplate.indexOf ("outputs:");
1852 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
1853 int resourcesIdx = heatTemplate.indexOf ("resources:");
1854 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
1856 logger.debug("Template updated with all subnets:{}", heatTemplate);
1857 return heatTemplate;
1860 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
1862 Map <String, String> sMap = new HashMap <> ();
1865 Object obj = outputs.get(key);
1866 ObjectMapper mapper = new ObjectMapper();
1867 String jStr = mapper.writeValueAsString(obj);
1868 logger.debug("Subnet_Ipam Output JSON String:{} {}", obj.getClass(), jStr);
1870 JsonNode rootNode = mapper.readTree(jStr);
1871 for (JsonNode sNode : rootNode.path("ipam_subnets"))
1873 logger.debug("Output Subnet Node {}", sNode.toString());
1874 String name = sNode.path("subnet_name").textValue();
1875 String uuid = sNode.path("subnet_uuid").textValue();
1876 String aaiId = name; // default
1877 // try to find aaiId for name in input subnetList
1878 if (subnets != null)
1880 for (Subnet subnet : subnets)
1882 if ( subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName()))
1884 if (subnet.getSubnetName().equals(name))
1886 aaiId = subnet.getSubnetId();
1892 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
1897 logger.error("{} {} Exception getting subnet-uuids ", MessageEnum.RA_MARSHING_ERROR,
1898 MsoLogger.ErrorCode.DataError.getValue(), e);
1901 logger.debug("Return sMap {}", sMap.toString());
1905 private static String insertStr (String template, String snippet, int index) {
1907 String updatedTemplate;
1909 logger.debug("Index:{} Snippet:{}", index, snippet);
1911 String templateBeg = template.substring (0, index);
1912 String templateEnd = template.substring (index);
1914 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
1916 logger.debug("Template updated with a subnet:{}", updatedTemplate);
1917 return updatedTemplate;