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.ErrorCode;
53 import org.onap.so.logger.MessageEnum;
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 logger.debug("*** CREATE Network: {} of type {} in {}/{}", networkName, networkType, cloudSiteId, tenantId);
271 // Will capture execution time for metrics
272 long startTime = System.currentTimeMillis ();
274 // Build a default rollback object (no actions performed)
275 NetworkRollback networkRollback = new NetworkRollback ();
276 networkRollback.setCloudId (cloudSiteId);
277 networkRollback.setTenantId (tenantId);
278 networkRollback.setMsoRequest (msoRequest);
279 networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
281 // tenant query is not required here.
282 // If the tenant doesn't exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
283 // So this is just catching that error in a bit more obvious way up front.
285 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
286 if (!cloudSiteOpt.isPresent())
288 String error = String
289 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
290 networkName, cloudSiteId, tenantId);
291 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
292 // Set the detailed error as the Exception 'message'
293 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
297 NetworkResource networkResource = networkCheck (startTime,
299 modelCustomizationUuid,
306 String mode = networkResource.getOrchestrationMode ();
307 NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ());
309 if (NEUTRON_MODE.equals (mode)) {
311 // Use an MsoNeutronUtils for all neutron commands
313 // See if the Network already exists (by name)
314 NetworkInfo netInfo = null;
315 long queryNetworkStarttime = System.currentTimeMillis ();
317 netInfo = neutron.queryNetwork (networkName, tenantId, cloudSiteId);
318 } catch (MsoException me) {
320 "{} {} Exception while querying network {} for CloudSite {} from Tenant {} from OpenStack ",
321 MessageEnum.RA_QUERY_NETWORK_EXC, ErrorCode.BusinessProcesssError.getValue(),
322 networkName, cloudSiteId, tenantId, me);
323 me.addContext (CREATE_NETWORK_CONTEXT);
324 throw new NetworkException (me);
327 if (netInfo != null) {
328 // Exists. If that's OK, return success with the network ID.
329 // Otherwise, return an exception.
330 if (failIfExists != null && failIfExists) {
331 String error = String
332 .format("Create Nework: Network %s already exists in %s/%s with ID %s", networkName,
333 cloudSiteId, tenantId, netInfo.getId());
334 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ALREADY_EXIST,
335 ErrorCode.DataError.getValue(), error);
336 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
338 // Populate the outputs from the existing network.
339 networkId.value = netInfo.getId ();
340 neutronNetworkId.value = netInfo.getId ();
341 rollback.value = networkRollback; // Default rollback - no updates performed
342 logger.warn("{} {} Found Existing network, status={} for Neutron mode ",
343 MessageEnum.RA_NETWORK_ALREADY_EXIST, ErrorCode.DataError.getValue(),
344 netInfo.getStatus());
349 long createNetworkStarttime = System.currentTimeMillis ();
351 netInfo = neutron.createNetwork (cloudSiteId,
357 } catch (MsoException me) {
358 me.addContext(CREATE_NETWORK_CONTEXT);
359 logger.error("{} {} Create Network: type {} in {}/{}: ", MessageEnum.RA_CREATE_NETWORK_EXC,
360 ErrorCode.DataError.getValue(), neutronNetworkType, cloudSiteId, tenantId, me);
362 throw new NetworkException (me);
365 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
367 // If reach this point, network creation is successful.
368 // Since directly created via Neutron, networkId tracked by MSO is the same
369 // as the neutron network ID.
370 networkId.value = netInfo.getId ();
371 neutronNetworkId.value = netInfo.getId ();
373 networkRollback.setNetworkCreated (true);
374 networkRollback.setNetworkId (netInfo.getId ());
375 networkRollback.setNeutronNetworkId (netInfo.getId ());
376 networkRollback.setNetworkType (networkType);
378 logger.debug("Network {} created, id = {}", networkName, netInfo.getId());
379 } else if ("HEAT".equals (mode)) {
381 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
382 if (heatTemplate == null) {
383 String error = String
384 .format("Network error - undefined Heat Template. Network Type = %s", networkType);
385 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, ErrorCode.DataError.getValue(),
387 throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
390 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
392 // "Fix" the template if it has CR/LF (getting this from Oracle)
393 String template = heatTemplate.getHeatTemplate ();
394 template = template.replaceAll ("\r\n", "\n");
396 boolean aic3template=false;
397 String aic3nw = AIC3_NW;
399 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
401 if (template.contains(aic3nw))
404 // First, look up to see if the Network already exists (by name).
405 // For HEAT orchestration of networks, the stack name will always match the network name
406 StackInfo heatStack = null;
407 long queryNetworkStarttime = System.currentTimeMillis ();
409 heatStack = heat.queryStack (cloudSiteId, "CloudOwner", tenantId, networkName);
410 } catch (MsoException me) {
411 me.addContext (CREATE_NETWORK_CONTEXT);
412 logger.error("{} {} Create Network (heat): query network {} in {}/{}: ",
413 MessageEnum.RA_QUERY_NETWORK_EXC, ErrorCode.DataError.getValue(), networkName,
414 cloudSiteId, tenantId, me);
415 throw new NetworkException (me);
418 if (heatStack != null && (heatStack.getStatus () != HeatStatus.NOTFOUND)) {
419 // Stack exists. Return success or error depending on input directive
420 if (failIfExists != null && failIfExists) {
421 String error = String
422 .format("CreateNetwork: Stack %s already exists in %s/%s as %s", networkName, cloudSiteId,
423 tenantId, heatStack.getCanonicalName());
424 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ALREADY_EXIST,
425 ErrorCode.DataError.getValue(), error);
426 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
428 // Populate the outputs from the existing stack.
429 networkId.value = heatStack.getCanonicalName ();
430 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
431 rollback.value = networkRollback; // Default rollback - no updates performed
434 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
436 Map <String, Object> outputs = heatStack.getOutputs ();
437 Map <String, String> sMap = new HashMap <> ();
438 if (outputs != null) {
439 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
440 String key=entry.getKey();
441 if (key != null && key.startsWith ("subnet")) {
442 if (aic3template) //one subnet_id output
444 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
447 else //multiples subnet_%aaid% outputs
449 String subnetUUId = (String) outputs.get(key);
450 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
455 subnetIdMap.value = sMap;
456 logger.warn("{} {} Found Existing network stack, status={} networkName={} for {}/{}",
457 MessageEnum.RA_NETWORK_ALREADY_EXIST, ErrorCode.DataError.getValue(),
458 heatStack.getStatus(), networkName, cloudSiteId, tenantId);
463 // Ready to deploy the new Network
464 // Build the common set of HEAT template parameters
465 Map <String, Object> stackParams = populateNetworkParams (neutronNetworkType,
474 // Validate (and update) the input parameters against the DB definition
475 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
476 // and inputs were already validated.
478 stackParams = heat.validateStackParams (stackParams, heatTemplate);
479 } catch (IllegalArgumentException e) {
480 String error = "Create Network: Configuration Error: " + e.getMessage ();
481 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC,
482 ErrorCode.DataError.getValue(), error,e);
483 // Input parameters were not valid
484 throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
487 if (subnets != null) {
491 template = mergeSubnetsAIC3 (template, subnets, stackParams);
495 template = mergeSubnets (template, subnets);
497 } catch (MsoException me) {
498 me.addContext (CREATE_NETWORK_CONTEXT);
500 .error("{} {} Exception Create Network, merging subnets for network (heat) type {} in {}/{} ",
501 MessageEnum.RA_CREATE_NETWORK_EXC, ErrorCode.DataError.getValue(),
502 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
503 throw new NetworkException (me);
507 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
509 mergePolicyRefs (policyFqdns, stackParams);
510 } catch (MsoException me) {
511 me.addContext (CREATE_NETWORK_CONTEXT);
512 logger.error("{} {} Exception Create Network, merging policyRefs type {} in {}/{} ",
513 MessageEnum.RA_CREATE_NETWORK_EXC, ErrorCode.DataError.getValue(),
514 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
515 throw new NetworkException (me);
519 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
521 mergeRouteTableRefs (routeTableFqdns, stackParams);
522 } catch (MsoException me) {
523 me.addContext (CREATE_NETWORK_CONTEXT);
524 logger.error("{} {} Exception Create Network, merging routeTableRefs type {} in {}/{} ",
525 MessageEnum.RA_CREATE_NETWORK_EXC, ErrorCode.DataError.getValue(),
526 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
527 throw new NetworkException (me);
531 // Deploy the network stack
532 // Ignore MsoStackAlreadyExists exception because we already checked.
536 heatStack = heat.createStack (cloudSiteId,
544 heatTemplate.getTimeoutMinutes (),
548 backout.booleanValue());
549 } catch (MsoException me) {
550 me.addContext (CREATE_NETWORK_CONTEXT);
552 .error("{} {} Exception creating network type {} in {}/{} ", MessageEnum.RA_CREATE_NETWORK_EXC,
553 ErrorCode.DataError.getValue(), networkName, cloudSiteId, tenantId, me);
554 throw new NetworkException (me);
557 // Reach this point if createStack is successful.
559 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
560 // and the neutronNetworkId is the network UUID returned in stack outputs.
561 networkId.value = heatStack.getCanonicalName ();
562 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
565 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
567 Map <String, Object> outputs = heatStack.getOutputs ();
568 Map <String, String> sMap = new HashMap <> ();
569 if (outputs != null) {
570 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
571 String key = entry.getKey();
572 if (key != null && key.startsWith ("subnet")) {
573 if (aic3template) //one subnet output expected
575 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
578 else //multiples subnet_%aaid% outputs allowed
580 String subnetUUId = (String) outputs.get(key);
581 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
586 subnetIdMap.value = sMap;
588 rollback.value = networkRollback;
589 // Populate remaining rollback info and response parameters.
590 networkRollback.setNetworkStackId (heatStack.getCanonicalName ());
591 networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID));
592 networkRollback.setNetworkCreated (true);
593 networkRollback.setNetworkType (networkType);
595 logger.debug("Network {} successfully created via HEAT", networkName);
602 public void updateNetwork (String cloudSiteId,
605 String modelCustomizationUuid,
608 String physicalNetworkName,
609 List <Integer> vlans,
612 List <Subnet> subnets,
613 Map<String,String> networkParams,
614 MsoRequest msoRequest,
615 Holder <Map <String, String>> subnetIdMap,
616 Holder <NetworkRollback> rollback) throws NetworkException {
617 updateNetwork (cloudSiteId,
620 modelCustomizationUuid,
638 public void updateNetworkContrail (String cloudSiteId,
641 String modelCustomizationUuid,
644 List <RouteTarget> routeTargets,
647 List <Subnet> subnets,
648 Map<String, String> networkParams,
649 List <String> policyFqdns,
650 List<String> routeTableFqdns,
651 MsoRequest msoRequest,
652 Holder <Map <String, String>> subnetIdMap,
653 Holder <NetworkRollback> rollback) throws NetworkException {
654 updateNetwork (cloudSiteId,
657 modelCustomizationUuid,
674 * This is the "Update Network" web service implementation.
675 * It will update an existing Network of the requested type in the specified cloud
676 * and tenant. The typical use will be to replace the VLANs with the supplied
677 * list (to add or remove a VLAN), but other properties may be updated as well.
679 * There will be a pre-defined set of network types defined in the MSO Catalog.
680 * All such networks will have a similar configuration, based on the allowable
681 * Openstack networking definitions. This includes basic networks, provider
682 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
684 * Initially, all provider networks must currently be "vlan" type, and multi-provider
685 * networks must be multiple VLANs on the same physical network.
687 * This service supports two modes of Network update:
688 * - via Heat Templates
690 * The network orchestration mode for each network type is declared in its
691 * catalog definition. All Heat-based templates must support some subset of
692 * the same input parameters: network_name, physical_network, vlan, segments.
694 * The method returns a NetworkRollback object. This object can be passed
695 * as-is to the rollbackNetwork operation to undo everything that was updated.
696 * This is useful if a network is successfully updated but orchestration
697 * fails on a subsequent operation.
699 private void updateNetwork (String cloudSiteId,
702 String modelCustomizationUuid,
705 String physicalNetworkName,
706 List <Integer> vlans,
707 List <RouteTarget> routeTargets,
710 List <Subnet> subnets,
711 List <String> policyFqdns,
712 List<String> routeTableFqdns,
713 MsoRequest msoRequest,
714 Holder <Map <String, String>> subnetIdMap,
715 Holder <NetworkRollback> rollback) throws NetworkException {
717 logger.debug("***UPDATE Network adapter with Network: {} of type {} in {}/{}", networkName, networkType,
718 cloudSiteId, tenantId);
720 // Will capture execution time for metrics
721 long startTime = System.currentTimeMillis ();
723 // Build a default rollback object (no actions performed)
724 NetworkRollback networkRollback = new NetworkRollback ();
725 networkRollback.setCloudId (cloudSiteId);
726 networkRollback.setTenantId (tenantId);
727 networkRollback.setMsoRequest (msoRequest);
729 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
730 if (!cloudSiteOpt.isPresent()) {
731 String error = String.format(
732 "UpdateNetwork: Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
733 networkName, cloudSiteId, tenantId);
734 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
735 // Set the detailed error as the Exception 'message'
736 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
742 NetworkResource networkResource = networkCheck(
745 modelCustomizationUuid,
752 String mode = networkResource.getOrchestrationMode();
753 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
755 // Use an MsoNeutronUtils for all Neutron commands
757 if (NEUTRON_MODE.equals(mode)) {
759 // Verify that the Network exists
760 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
761 NetworkInfo netInfo = null;
762 long queryNetworkStarttime = System.currentTimeMillis();
764 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
765 } catch (MsoException me) {
766 me.addContext(UPDATE_NETWORK_CONTEXT);
767 logger.error("{} {} Exception - queryNetwork query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
768 ErrorCode.BusinessProcesssError.getValue(), networkId, cloudSiteId, tenantId, me);
769 throw new NetworkException(me);
772 if (netInfo == null) {
773 String error = String
774 .format("Update Nework: Network %s does not exist in %s/%s", networkId, cloudSiteId, tenantId);
775 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND,
776 ErrorCode.BusinessProcesssError.getValue(), error);
777 // Does not exist. Throw an exception (can't update a non-existent network)
778 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
780 long updateNetworkStarttime = System.currentTimeMillis();
782 netInfo = neutron.updateNetwork(cloudSiteId,
788 } catch (MsoException me) {
789 me.addContext(UPDATE_NETWORK_CONTEXT);
790 logger.error("{} {} Exception - updateNetwork {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
791 ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
792 throw new NetworkException(me);
795 // Add the network ID and previously queried vlans to the rollback object
796 networkRollback.setNetworkId(netInfo.getId());
797 networkRollback.setNeutronNetworkId(netInfo.getId());
798 networkRollback.setNetworkType(networkType);
799 // Save previous parameters
800 networkRollback.setNetworkName(netInfo.getName());
801 networkRollback.setPhysicalNetwork(netInfo.getProvider());
802 networkRollback.setVlans(netInfo.getVlans());
804 logger.debug("Network {} updated, id = {}", networkId, netInfo.getId());
805 } else if ("HEAT".equals(mode)) {
807 // First, look up to see that the Network already exists.
808 // For Heat-based orchestration, the networkId is the network Stack ID.
809 StackInfo heatStack = null;
810 long queryStackStarttime = System.currentTimeMillis();
812 heatStack = heat.queryStack(cloudSiteId, "CloudOwner", tenantId, networkName);
813 } catch (MsoException me) {
814 me.addContext(UPDATE_NETWORK_CONTEXT);
815 logger.error("{} {} Exception - QueryStack query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
816 ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
817 throw new NetworkException(me);
820 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
821 String error = String
822 .format("UpdateNetwork: Stack %s does not exist in %s/%s", networkName, cloudSiteId, tenantId);
823 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND, ErrorCode.DataError.getValue(),
825 // Network stack does not exist. Return an error
826 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
829 // Get the previous parameters for rollback
830 Map<String, Object> heatParams = heatStack.getParameters();
832 String previousNetworkName = (String) heatParams.get("network_name");
833 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
835 List<Integer> previousVlans = new ArrayList<>();
836 String vlansParam = (String) heatParams.get(VLANS);
837 if (vlansParam != null) {
838 for (String vlan : vlansParam.split(",")) {
840 previousVlans.add(Integer.parseInt(vlan));
841 } catch (NumberFormatException e) {
842 logger.warn("{} {} Exception - VLAN parse for params {} ", MessageEnum.RA_VLAN_PARSE,
843 ErrorCode.DataError.getValue(), vlansParam, e);
847 logger.debug("Update Stack: Previous VLANS: {}", previousVlans);
849 // Ready to deploy the updated Network via Heat
852 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
853 if (heatTemplate == null) {
854 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
855 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, ErrorCode.DataError.getValue(),
857 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
860 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
862 // "Fix" the template if it has CR/LF (getting this from Oracle)
863 String template = heatTemplate.getHeatTemplate();
864 template = template.replaceAll("\r\n", "\n");
866 boolean aic3template = false;
867 String aic3nw = AIC3_NW;
869 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
871 if (template.contains(aic3nw))
874 // Build the common set of HEAT template parameters
875 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
884 // Validate (and update) the input parameters against the DB definition
885 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
887 stackParams = heat.validateStackParams(stackParams, heatTemplate);
888 } catch (IllegalArgumentException e) {
889 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
890 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
891 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
894 if (subnets != null) {
897 template = mergeSubnetsAIC3(template, subnets, stackParams);
899 template = mergeSubnets(template, subnets);
901 } catch (MsoException me) {
902 me.addContext(UPDATE_NETWORK_CONTEXT);
903 logger.error("{} {} Exception - UpdateNetwork mergeSubnets for network type {} in {}/{} ",
904 MessageEnum.RA_UPDATE_NETWORK_ERR, ErrorCode.DataError.getValue(),
905 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
906 throw new NetworkException(me);
910 if (policyFqdns != null && aic3template) {
912 mergePolicyRefs(policyFqdns, stackParams);
913 } catch (MsoException me) {
914 me.addContext(UPDATE_NETWORK_CONTEXT);
915 logger.error("{} {} Exception - UpdateNetwork mergePolicyRefs type {} in {}/{} ",
916 MessageEnum.RA_UPDATE_NETWORK_ERR, ErrorCode.DataError.getValue(),
917 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
918 throw new NetworkException(me);
922 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
924 mergeRouteTableRefs(routeTableFqdns, stackParams);
925 } catch (MsoException me) {
926 me.addContext(UPDATE_NETWORK_CONTEXT);
927 logger.error("{} {} Exception - UpdateNetwork mergeRouteTableRefs type {} in {}/{} ",
928 MessageEnum.RA_UPDATE_NETWORK_ERR, ErrorCode.DataError.getValue(),
929 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
930 throw new NetworkException(me);
934 // Update the network stack
935 // Ignore MsoStackNotFound exception because we already checked.
936 long updateStackStarttime = System.currentTimeMillis();
938 heatStack = heatWithUpdate.updateStack(cloudSiteId,
945 heatTemplate.getTimeoutMinutes());
946 } catch (MsoException me) {
947 me.addContext(UPDATE_NETWORK_CONTEXT);
948 logger.error("{} {} Exception - update network {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
949 ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
950 throw new NetworkException(me);
953 Map<String, Object> outputs = heatStack.getOutputs();
954 Map<String, String> sMap = new HashMap<>();
955 if (outputs != null) {
956 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
957 String key=entry.getKey();
958 if (key != null && key.startsWith("subnet")) {
959 if (aic3template) //one subnet output expected
961 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
963 } else //multiples subnet_%aaid% outputs allowed
965 String subnetUUId = (String) outputs.get(key);
966 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
971 subnetIdMap.value = sMap;
973 // Reach this point if createStack is successful.
974 // Populate remaining rollback info and response parameters.
975 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
976 if(null != outputs) {
977 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
980 logger.debug("outputs is NULL");
982 networkRollback.setNetworkType(networkType);
983 // Save previous parameters
984 networkRollback.setNetworkName(previousNetworkName);
985 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
986 networkRollback.setVlans(previousVlans);
988 rollback.value = networkRollback;
990 logger.debug("Network {} successfully updated via HEAT", networkId);
996 private NetworkResource networkCheck (long startTime,
998 String modelCustomizationUuid,
1000 String physicalNetworkName,
1001 List <Integer> vlans,
1002 List <RouteTarget> routeTargets,
1004 CloudSite cloudSite) throws NetworkException {
1005 // Retrieve the Network Resource definition
1006 NetworkResource networkResource = null;
1007 NetworkResourceCustomization networkCust = null;
1008 CollectionNetworkResourceCustomization collectionNetworkCust = null;
1009 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1010 if (!commonUtils.isNullOrEmpty(networkType)) {
1011 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1014 networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1015 if (networkCust == null) {
1016 collectionNetworkCust = collectionNetworkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1019 if(networkCust != null){
1020 logger.debug("Got Network Customization definition from Catalog: {}", networkCust.toString());
1022 networkResource = networkCust.getNetworkResource();
1023 } else if (collectionNetworkCust != null) {
1024 logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}",
1025 collectionNetworkCust.toString());
1026 networkResource = collectionNetworkCust.getNetworkResource();
1028 if (networkResource == null) {
1029 String error = String.format(
1030 "Create/UpdateNetwork: Unable to get network resource with NetworkType: %s or ModelCustomizationUUID:%s",
1031 networkType, modelCustomizationUuid);
1032 logger.error("{} {} {} ", MessageEnum.RA_UNKOWN_PARAM, ErrorCode.DataError.getValue(), error);
1034 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1036 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1038 String mode = networkResource.getOrchestrationMode();
1039 NetworkType neutronNetworkType = NetworkType
1040 .valueOf(networkResource.getNeutronNetworkType());
1042 // All Networks are orchestrated via HEAT or Neutron
1043 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1044 String error = "CreateNetwork: Configuration Error: Network Type = " + networkType;
1045 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1046 ErrorCode.DataError.getValue(), error);
1047 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1050 MavenLikeVersioning aicV = new MavenLikeVersioning();
1051 aicV.setVersion(cloudSite.getCloudVersion());
1052 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1053 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1056 && (aicV.isTheSameVersion(networkResource
1057 .getAicVersionMax()) || !(aicV
1058 .isMoreRecentThan(networkResource
1059 .getAicVersionMax())))) // aic <= max
1061 logger.debug("Network Type:{} VersionMin:{} VersionMax:{} supported on Cloud:{} with AIC_Version:{}",
1062 networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId,
1063 cloudSite.getCloudVersion());
1065 String error = String
1066 .format("Network Type:%s Version_Min:%s Version_Max:%s not supported on Cloud:%s with AIC_Version:%s",
1067 networkType, networkType, networkResource.getAicVersionMin(),
1068 networkResource.getAicVersionMax(), cloudSiteId, cloudSite.getCloudVersion());
1069 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
1070 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1073 // Validate the Network parameters.
1074 String missing = validateNetworkParams(neutronNetworkType,
1075 networkName, physicalNetworkName, vlans, routeTargets);
1076 if (!missing.isEmpty()) {
1077 String error = "Create Network: Missing parameters: " + missing;
1078 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
1080 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1083 return networkResource;
1087 public void queryNetwork (String cloudSiteId,
1089 String networkNameOrId,
1090 MsoRequest msoRequest,
1091 Holder <Boolean> networkExists,
1092 Holder <String> networkId,
1093 Holder <String> neutronNetworkId,
1094 Holder <NetworkStatus> status,
1095 Holder <List <Integer>> vlans,
1096 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1097 queryNetwork (cloudSiteId,
1111 public void queryNetworkContrail (String cloudSiteId,
1113 String networkNameOrId,
1114 MsoRequest msoRequest,
1115 Holder <Boolean> networkExists,
1116 Holder <String> networkId,
1117 Holder <String> neutronNetworkId,
1118 Holder <NetworkStatus> status,
1119 Holder <List <RouteTarget>> routeTargets,
1120 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1121 queryNetwork (cloudSiteId,
1135 * This is the queryNetwork method. It returns the existence and status of
1136 * the specified network, along with its Neutron UUID and list of VLANs.
1137 * This method attempts to find the network using both Heat and Neutron.
1138 * Heat stacks are first searched based on the provided network name/id.
1139 * If none is found, the Neutron is directly queried.
1141 private void queryNetwork (String cloudSiteId,
1143 String networkNameOrId,
1144 MsoRequest msoRequest,
1145 Holder <Boolean> networkExists,
1146 Holder <String> networkId,
1147 Holder <String> neutronNetworkId,
1148 Holder <NetworkStatus> status,
1149 Holder <List <Integer>> vlans,
1150 Holder <List <RouteTarget>> routeTargets,
1151 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1153 logger.debug("*** QUERY Network with Network: {} in {}/{}", networkNameOrId, cloudSiteId, tenantId);
1155 // Will capture execution time for metrics
1156 long startTime = System.currentTimeMillis ();
1158 if (commonUtils.isNullOrEmpty (cloudSiteId)
1159 || commonUtils.isNullOrEmpty(tenantId)
1160 || commonUtils.isNullOrEmpty(networkNameOrId)) {
1162 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1163 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
1164 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1167 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1168 if (!cloudSiteOpt.isPresent())
1170 String error = String
1171 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
1172 networkNameOrId, cloudSiteId, tenantId);
1173 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error);
1174 // Set the detailed error as the Exception 'message'
1175 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1178 // Use MsoNeutronUtils for all NEUTRON commands
1182 // Try Heat first, since networks may be named the same as the Heat stack
1183 StackInfo heatStack = null;
1184 long queryStackStarttime = System.currentTimeMillis ();
1186 heatStack = heat.queryStack (cloudSiteId, "CloudOwner", tenantId, networkNameOrId);
1187 } catch (MsoException me) {
1188 me.addContext ("QueryNetwork");
1189 logger.error("{} {} Exception - Query Network (heat): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1190 ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1191 throw new NetworkException (me);
1194 // Populate the outputs based on the returned Stack information
1195 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1196 // Found it. Get the neutronNetworkId for further query
1197 Map <String, Object> outputs = heatStack.getOutputs ();
1198 neutronId = (String) outputs.get (NETWORK_ID);
1201 Map <String, String> sMap = new HashMap <> ();
1202 if (outputs != null) {
1203 for (String key : outputs.keySet ()) {
1204 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1206 String subnetUUId = (String) outputs.get(key);
1207 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1209 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1211 Map <String, String> map = getSubnetUUId(key, outputs, null);
1217 subnetIdMap.value = sMap;
1219 // Input ID was not a Heat stack ID. Try it directly in Neutron
1220 neutronId = networkNameOrId;
1221 mode = NEUTRON_MODE;
1224 // Query directly against the Neutron Network for the details
1225 // no RouteTargets available for ContrailV2 in neutron net-show
1226 // networkId is heatStackId
1227 long queryNetworkStarttime = System.currentTimeMillis ();
1229 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1230 if (netInfo != null) {
1231 // Found. Populate the output elements
1232 networkExists.value = Boolean.TRUE;
1233 if ("HEAT".equals (mode)) {
1234 networkId.value = heatStack.getCanonicalName ();
1236 networkId.value = netInfo.getId ();
1238 neutronNetworkId.value = netInfo.getId ();
1239 status.value = netInfo.getStatus ();
1241 vlans.value = netInfo.getVlans ();
1243 logger.debug("Network {} found({}), ID = {}{}", networkNameOrId, mode, networkId.value,
1244 ("HEAT".equals(mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1246 // Not found. Populate the status fields, leave the rest null
1247 networkExists.value = Boolean.FALSE;
1248 status.value = NetworkStatus.NOTFOUND;
1249 neutronNetworkId.value = null;
1251 vlans.value = new ArrayList<>();
1253 logger.debug("Network {} not found", networkNameOrId);
1255 } catch (MsoException me) {
1256 me.addContext ("QueryNetwork");
1257 logger.error("{} {} Exception - Query Network (neutron): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1258 ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1259 throw new NetworkException (me);
1265 * This is the "Delete Network" web service implementation.
1266 * It will delete a Network in the specified cloud and tenant.
1268 * If the network is not found, it is treated as a success.
1270 * This service supports two modes of Network creation/update/delete:
1271 * - via Heat Templates
1273 * The network orchestration mode for each network type is declared in its
1274 * catalog definition.
1276 * For Heat-based orchestration, the networkId should be the stack ID.
1277 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1279 * The method returns nothing on success. Rollback is not possible for delete
1280 * commands, so any failure on delete will require manual fallout in the client.
1283 public void deleteNetwork (String cloudSiteId,
1286 String modelCustomizationUuid,
1288 MsoRequest msoRequest,
1289 Holder <Boolean> networkDeleted) throws NetworkException {
1291 logger.debug("*** DELETE Network adapter with Network: {} in {}/{}", networkId, cloudSiteId, tenantId);
1293 // Will capture execution time for metrics
1294 long startTime = System.currentTimeMillis ();
1297 if (commonUtils.isNullOrEmpty (cloudSiteId)
1298 || commonUtils.isNullOrEmpty(tenantId)
1299 || commonUtils.isNullOrEmpty(networkId)) {
1300 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1301 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
1302 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1305 // Retrieve the Network Resource definition
1306 NetworkResource networkResource = null;
1308 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1309 if (!commonUtils.isNullOrEmpty(networkType)) {
1310 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1313 NetworkResourceCustomization nrc = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1315 networkResource = nrc.getNetworkResource();
1319 if (networkResource != null) {
1320 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1322 mode = networkResource.getOrchestrationMode ();
1325 if (NEUTRON_MODE.equals (mode)) {
1327 // Use MsoNeutronUtils for all NEUTRON commands
1328 long deleteNetworkStarttime = System.currentTimeMillis ();
1330 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1331 // was not found. So don't bother to query first.
1332 boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1333 networkDeleted.value = deleted;
1334 } catch (MsoException me) {
1335 me.addContext ("DeleteNetwork");
1336 logger.error("{} {} Delete Network (neutron): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1337 ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1338 throw new NetworkException (me);
1340 } else { // DEFAULT to ("HEAT".equals (mode))
1341 long deleteStackStarttime = System.currentTimeMillis ();
1344 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1345 // So query first to report back if stack WAS deleted or just NOTOFUND
1346 StackInfo heatStack = null;
1347 heatStack = heat.queryStack(cloudSiteId, "CloudOwner", tenantId, networkId);
1348 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND)
1350 heat.deleteStack (tenantId, "CloudOwner", cloudSiteId, networkId, true);
1351 networkDeleted.value = true;
1355 networkDeleted.value = false;
1357 } catch (MsoException me) {
1358 me.addContext ("DeleteNetwork");
1359 logger.error("{} {} Delete Network (heat): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1360 ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1361 throw new NetworkException (me);
1366 // On success, nothing is returned.
1371 * This web service endpoint will rollback a previous Create VNF operation.
1372 * A rollback object is returned to the client in a successful creation
1373 * response. The client can pass that object as-is back to the rollbackVnf
1374 * operation to undo the creation.
1376 * The rollback includes removing the VNF and deleting the tenant if the
1377 * tenant did not exist prior to the VNF creation.
1380 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1381 // Will capture execution time for metrics
1382 long startTime = System.currentTimeMillis ();
1384 if (rollback == null) {
1386 .error("{} {} rollback is null", MessageEnum.RA_ROLLBACK_NULL, ErrorCode.DataError.getValue());
1390 // Get the elements of the VnfRollback object for easier access
1391 String cloudSiteId = rollback.getCloudId ();
1392 String tenantId = rollback.getTenantId ();
1393 String networkId = rollback.getNetworkStackId ();
1394 String networkType = rollback.getNetworkType ();
1395 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1397 logger.debug("*** ROLLBACK Network {} in {}/{}", networkId, cloudSiteId, tenantId);
1400 // Retrieve the Network Resource definition
1401 NetworkResource networkResource = null;
1402 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1403 networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource();
1405 networkResource = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource();
1408 if (networkResource != null) {
1410 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1412 mode = networkResource.getOrchestrationMode ();
1415 if (rollback.getNetworkCreated ()) {
1416 // Rolling back a newly created network, so delete it.
1417 if (NEUTRON_MODE.equals (mode)) {
1418 // Use MsoNeutronUtils for all NEUTRON commands
1419 long deleteNetworkStarttime = System.currentTimeMillis ();
1421 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1422 // was not found. So don't bother to query first.
1423 neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1424 } catch (MsoException me) {
1425 me.addContext ("RollbackNetwork");
1426 logger.error("{} {} Exception - Rollback Network (neutron): {} in {}/{} ",
1427 MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcesssError.getValue(),
1428 networkId, cloudSiteId, tenantId, me);
1429 throw new NetworkException (me);
1431 } else { // DEFAULT to if ("HEAT".equals (mode))
1432 long deleteStackStarttime = System.currentTimeMillis ();
1434 // The deleteStack function in MsoHeatUtils returns success if the stack
1435 // was not found. So don't bother to query first.
1436 heat.deleteStack (tenantId, "CloudOwner", cloudSiteId, networkId, true);
1437 } catch (MsoException me) {
1438 me.addContext ("RollbackNetwork");
1439 logger.error("{} {} Exception - Rollback Network (heat): {} in {}/{} ",
1440 MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcesssError.getValue(),
1441 networkId, cloudSiteId, tenantId, me);
1442 throw new NetworkException (me);
1450 private String validateNetworkParams (NetworkType neutronNetworkType,
1452 String physicalNetwork,
1453 List <Integer> vlans,
1454 List <RouteTarget> routeTargets) {
1456 StringBuilder missing = new StringBuilder ();
1457 if (commonUtils.isNullOrEmpty(networkName)) {
1458 missing.append ("networkName");
1462 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1463 if (commonUtils.isNullOrEmpty(physicalNetwork)) {
1464 missing.append (sep).append ("physicalNetworkName");
1467 if (vlans == null || vlans.isEmpty ()) {
1468 missing.append (sep).append (VLANS);
1472 return missing.toString ();
1475 private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1477 String physicalNetwork,
1478 List <Integer> vlans,
1479 List <RouteTarget> routeTargets,
1482 boolean aic3template) {
1483 // Build the common set of HEAT template parameters
1484 Map <String, Object> stackParams = new HashMap <> ();
1485 stackParams.put ("network_name", networkName);
1487 if (neutronNetworkType == NetworkType.PROVIDER) {
1488 // For Provider type
1489 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1490 stackParams.put ("vlan", vlans.get (0).toString ());
1491 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1492 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1493 // It supports all ProviderNet properties except segmentation_id, and adds a
1494 // comma-separated-list of VLANs as a "segments" property.
1495 // Note that this does not match the Neutron definition of Multi-Provider network,
1496 // which contains a list of 'segments', each having physical_network, network_type,
1497 // and segmentation_id.
1498 StringBuilder buf = new StringBuilder ();
1500 for (Integer vlan : vlans) {
1501 buf.append (sep).append (vlan.toString ());
1504 String csl = buf.toString ();
1506 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1507 stackParams.put (VLANS, csl);
1509 if (routeTargets != null) {
1511 String rtGlobal = "";
1512 String rtImport = "";
1513 String rtExport = "";
1515 for (RouteTarget rt : routeTargets) {
1516 boolean rtIsNull = false;
1519 String routeTarget = rt.getRouteTarget();
1520 String routeTargetRole = rt.getRouteTargetRole();
1521 logger.debug("Checking for an actually null route target: {}", rt);
1522 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1524 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1530 logger.debug("Input RT:{}", rt);
1531 String role = rt.getRouteTargetRole();
1532 String rtValue = rt.getRouteTarget();
1534 if ("IMPORT".equalsIgnoreCase(role))
1536 sep = rtImport.isEmpty() ? "" : ",";
1537 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1539 else if ("EXPORT".equalsIgnoreCase(role))
1541 sep = rtExport.isEmpty() ? "" : ",";
1542 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1544 else // covers BOTH, empty etc
1546 sep = rtGlobal.isEmpty() ? "" : ",";
1547 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1553 if (!rtImport.isEmpty())
1555 stackParams.put ("route_targets_import", rtImport);
1557 if (!rtExport.isEmpty())
1559 stackParams.put ("route_targets_export", rtExport);
1561 if (!rtGlobal.isEmpty())
1563 stackParams.put ("route_targets", rtGlobal);
1566 if (commonUtils.isNullOrEmpty(shared)) {
1567 stackParams.put ("shared", "False");
1569 stackParams.put ("shared", shared);
1571 if (commonUtils.isNullOrEmpty(external)) {
1572 stackParams.put ("external", "False");
1574 stackParams.put ("external", external);
1581 /** policyRef_list structure in stackParams
1584 "network_policy_refs_data_sequence": {
1585 "network_policy_refs_data_sequence_major": "1",
1586 "network_policy_refs_data_sequence_minor": "0"
1590 "network_policy_refs_data_sequence": {
1591 "network_policy_refs_data_sequence_major": "2",
1592 "network_policy_refs_data_sequence_minor": "0"
1597 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1599 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1601 for (String pf : pFqdns) {
1602 if (!commonUtils.isNullOrEmpty(pf))
1604 ContrailPolicyRef pr = new ContrailPolicyRef();
1605 ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0");
1608 logger.debug("Contrail PolicyRefs Data:{}", pr);
1613 JsonNode node = null;
1616 ObjectMapper mapper = new ObjectMapper();
1617 node = mapper.convertValue(prlist, JsonNode.class);
1618 String jsonString = mapper.writeValueAsString(prlist);
1619 logger.debug("Json PolicyRefs Data:{}", jsonString);
1623 String error = "Error creating JsonNode for policyRefs Data";
1624 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcesssError.getValue(),
1626 throw new MsoAdapterException (error);
1629 if (pFqdns != null && node != null)
1631 StringBuilder buf = new StringBuilder ();
1633 for (String pf : pFqdns) {
1634 if (!commonUtils.isNullOrEmpty(pf))
1636 buf.append (sep).append (pf);
1640 String csl = buf.toString ();
1641 stackParams.put ("policy_refs", csl);
1642 stackParams.put ("policy_refsdata", node);
1645 logger.debug("StackParams updated with policy refs");
1649 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1652 if (rtFqdns != null)
1654 StringBuilder buf = new StringBuilder ();
1656 for (String rtf : rtFqdns) {
1657 if (!commonUtils.isNullOrEmpty(rtf))
1659 buf.append (sep).append (rtf);
1663 String csl = buf.toString ();
1664 stackParams.put ("route_table_refs", csl);
1667 logger.debug("StackParams updated with route_table refs");
1672 /*** Subnet Output structure from Juniper
1677 "ip_prefix": "10.100.1.0",
1680 "addr_from_start": null,
1681 "enable_dhcp": false,
1682 "default_gateway": "10.100.1.1",
1683 "dns_nameservers": [],
1684 "dhcp_option_list": null,
1685 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
1686 "allocation_pools": [
1688 "start": "10.100.1.3",
1692 "start": "10.100.1.6",
1696 "host_routes": null,
1697 "dns_server_address": "10.100.1.13",
1698 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
1702 "ip_prefix": "10.100.2.16",
1705 "addr_from_start": null,
1706 "enable_dhcp": true,
1707 "default_gateway": "10.100.2.17",
1708 "dns_nameservers": [],
1709 "dhcp_option_list": null,
1710 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
1711 "allocation_pools": [
1713 "start": "10.100.2.18",
1714 "end": "10.100.2.20"
1717 "host_routes": null,
1718 "dns_server_address": "10.100.2.29",
1719 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
1725 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
1728 List<ContrailSubnet> cslist = new ArrayList <> ();
1729 for (Subnet subnet : subnets) {
1730 logger.debug("Input Subnet:{}", subnet.toString());
1731 ContrailSubnet cs = new ContrailSubnetMapper(subnet).map();
1732 logger.debug("Contrail Subnet:{}", cs.toString());
1736 JsonNode node = null;
1739 ObjectMapper mapper = new ObjectMapper();
1740 node = mapper.convertValue(cslist, JsonNode.class);
1741 String jsonString = mapper.writeValueAsString(cslist);
1742 logger.debug("Json Subnet List:{}", jsonString);
1746 String error = "Error creating JsonNode from input subnets";
1747 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, ErrorCode.DataError.getValue(), error, e);
1748 throw new MsoAdapterException (error);
1753 stackParams.put ("subnet_list", node);
1755 //Outputs - All subnets are in one ipam_subnets structure
1756 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
1757 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
1759 // append outputs in heatTemplate
1760 int outputsIdx = heatTemplate.indexOf ("outputs:");
1761 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
1762 logger.debug("Template updated with all AIC3.0 subnets:{}", heatTemplate);
1763 return heatTemplate;
1767 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
1769 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
1772 + " network_id: { get_resource: network }\n"
1773 + " cidr: %cidr%\n";
1775 /* make these optional
1776 + " ip_version: %ipversion%\n"
1777 + " enable_dhcp: %enabledhcp%\n"
1778 + " gateway_ip: %gatewayip%\n"
1779 + " allocation_pools:\n"
1780 + " - start: %poolstart%\n"
1781 + " end: %poolend%\n";
1785 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
1786 + " value: {get_resource: subnet_%subnetId%}\n";
1790 StringBuilder resourcesBuf = new StringBuilder ();
1791 StringBuilder outputsBuf = new StringBuilder ();
1792 for (Subnet subnet : subnets) {
1794 // build template for each subnet
1795 curR = resourceTempl;
1796 if (subnet.getSubnetId () != null) {
1797 curR = curR.replace ("%subnetId%", subnet.getSubnetId ());
1799 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
1800 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
1801 throw new MsoAdapterException (error);
1804 if (subnet.getSubnetName () != null) {
1805 curR = curR.replace ("%name%", subnet.getSubnetName ());
1807 curR = curR.replace ("%name%", subnet.getSubnetId ());
1810 if (subnet.getCidr () != null) {
1811 curR = curR.replace ("%cidr%", subnet.getCidr ());
1813 String error = "Missing Required cidr for subnet in HEAT Template";
1814 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, ErrorCode.DataError.getValue(), error);
1815 throw new MsoAdapterException (error);
1818 if (subnet.getIpVersion () != null) {
1819 curR = curR + " ip_version: " + subnet.getIpVersion () + "\n";
1821 if (subnet.getEnableDHCP () != null) {
1822 curR = curR + " enable_dhcp: " + Boolean.toString (subnet.getEnableDHCP ()) + "\n";
1824 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
1825 curR = curR + " gateway_ip: " + subnet.getGatewayIp () + "\n";
1828 if (subnet.getAllocationPools() != null) {
1829 curR = curR + " allocation_pools:\n";
1830 for (Pool pool : subnet.getAllocationPools())
1832 if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd()))
1834 curR = curR + " - start: " + pool.getStart () + "\n";
1835 curR = curR + " end: " + pool.getEnd () + "\n";
1840 resourcesBuf.append (curR);
1843 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
1845 outputsBuf.append (curO);
1848 // append resources and outputs in heatTemplate
1849 logger.debug("Tempate initial:{}", heatTemplate);
1850 int outputsIdx = heatTemplate.indexOf ("outputs:");
1851 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
1852 int resourcesIdx = heatTemplate.indexOf ("resources:");
1853 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
1855 logger.debug("Template updated with all subnets:{}", heatTemplate);
1856 return heatTemplate;
1859 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
1861 Map <String, String> sMap = new HashMap <> ();
1864 Object obj = outputs.get(key);
1865 ObjectMapper mapper = new ObjectMapper();
1866 String jStr = mapper.writeValueAsString(obj);
1867 logger.debug("Subnet_Ipam Output JSON String:{} {}", obj.getClass(), jStr);
1869 JsonNode rootNode = mapper.readTree(jStr);
1870 for (JsonNode sNode : rootNode.path("ipam_subnets"))
1872 logger.debug("Output Subnet Node {}", sNode.toString());
1873 String name = sNode.path("subnet_name").textValue();
1874 String uuid = sNode.path("subnet_uuid").textValue();
1875 String aaiId = name; // default
1876 // try to find aaiId for name in input subnetList
1877 if (subnets != null)
1879 for (Subnet subnet : subnets)
1881 if ( subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName()))
1883 if (subnet.getSubnetName().equals(name))
1885 aaiId = subnet.getSubnetId();
1891 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
1896 logger.error("{} {} Exception getting subnet-uuids ", MessageEnum.RA_MARSHING_ERROR,
1897 ErrorCode.DataError.getValue(), e);
1900 logger.debug("Return sMap {}", sMap.toString());
1904 private static String insertStr (String template, String snippet, int index) {
1906 String updatedTemplate;
1908 logger.debug("Index:{} Snippet:{}", index, snippet);
1910 String templateBeg = template.substring (0, index);
1911 String templateEnd = template.substring (index);
1913 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
1915 logger.debug("Template updated with a subnet:{}", updatedTemplate);
1916 return updatedTemplate;