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 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, MsoLogger.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, MsoLogger.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 MsoLogger.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, MsoLogger.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 MsoLogger.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, MsoLogger.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, 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, MsoLogger.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 MsoLogger.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, MsoLogger.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 MsoLogger.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, MsoLogger.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, MsoLogger.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, MsoLogger.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,
542 heatTemplate.getTimeoutMinutes (),
546 backout.booleanValue());
547 } catch (MsoException me) {
548 me.addContext (CREATE_NETWORK_CONTEXT);
550 .error("{} {} Exception creating network type {} in {}/{} ", MessageEnum.RA_CREATE_NETWORK_EXC,
551 MsoLogger.ErrorCode.DataError.getValue(), networkName, cloudSiteId, tenantId, me);
552 throw new NetworkException (me);
555 // Reach this point if createStack is successful.
557 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
558 // and the neutronNetworkId is the network UUID returned in stack outputs.
559 networkId.value = heatStack.getCanonicalName ();
560 neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
563 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
565 Map <String, Object> outputs = heatStack.getOutputs ();
566 Map <String, String> sMap = new HashMap <> ();
567 if (outputs != null) {
568 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
569 String key = entry.getKey();
570 if (key != null && key.startsWith ("subnet")) {
571 if (aic3template) //one subnet output expected
573 Map <String, String> map = getSubnetUUId(key, outputs, subnets);
576 else //multiples subnet_%aaid% outputs allowed
578 String subnetUUId = (String) outputs.get(key);
579 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
584 subnetIdMap.value = sMap;
586 rollback.value = networkRollback;
587 // Populate remaining rollback info and response parameters.
588 networkRollback.setNetworkStackId (heatStack.getCanonicalName ());
589 networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID));
590 networkRollback.setNetworkCreated (true);
591 networkRollback.setNetworkType (networkType);
593 logger.debug("Network {} successfully created via HEAT", networkName);
600 public void updateNetwork (String cloudSiteId,
603 String modelCustomizationUuid,
606 String physicalNetworkName,
607 List <Integer> vlans,
610 List <Subnet> subnets,
611 Map<String,String> networkParams,
612 MsoRequest msoRequest,
613 Holder <Map <String, String>> subnetIdMap,
614 Holder <NetworkRollback> rollback) throws NetworkException {
615 updateNetwork (cloudSiteId,
618 modelCustomizationUuid,
636 public void updateNetworkContrail (String cloudSiteId,
639 String modelCustomizationUuid,
642 List <RouteTarget> routeTargets,
645 List <Subnet> subnets,
646 Map<String, String> networkParams,
647 List <String> policyFqdns,
648 List<String> routeTableFqdns,
649 MsoRequest msoRequest,
650 Holder <Map <String, String>> subnetIdMap,
651 Holder <NetworkRollback> rollback) throws NetworkException {
652 updateNetwork (cloudSiteId,
655 modelCustomizationUuid,
672 * This is the "Update Network" web service implementation.
673 * It will update an existing Network of the requested type in the specified cloud
674 * and tenant. The typical use will be to replace the VLANs with the supplied
675 * list (to add or remove a VLAN), but other properties may be updated as well.
677 * There will be a pre-defined set of network types defined in the MSO Catalog.
678 * All such networks will have a similar configuration, based on the allowable
679 * Openstack networking definitions. This includes basic networks, provider
680 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
682 * Initially, all provider networks must currently be "vlan" type, and multi-provider
683 * networks must be multiple VLANs on the same physical network.
685 * This service supports two modes of Network update:
686 * - via Heat Templates
688 * The network orchestration mode for each network type is declared in its
689 * catalog definition. All Heat-based templates must support some subset of
690 * the same input parameters: network_name, physical_network, vlan, segments.
692 * The method returns a NetworkRollback object. This object can be passed
693 * as-is to the rollbackNetwork operation to undo everything that was updated.
694 * This is useful if a network is successfully updated but orchestration
695 * fails on a subsequent operation.
697 private void updateNetwork (String cloudSiteId,
700 String modelCustomizationUuid,
703 String physicalNetworkName,
704 List <Integer> vlans,
705 List <RouteTarget> routeTargets,
708 List <Subnet> subnets,
709 List <String> policyFqdns,
710 List<String> routeTableFqdns,
711 MsoRequest msoRequest,
712 Holder <Map <String, String>> subnetIdMap,
713 Holder <NetworkRollback> rollback) throws NetworkException {
715 logger.debug("***UPDATE Network adapter with Network: {} of type {} in {}/{}", networkName, networkType,
716 cloudSiteId, tenantId);
718 // Will capture execution time for metrics
719 long startTime = System.currentTimeMillis ();
721 // Build a default rollback object (no actions performed)
722 NetworkRollback networkRollback = new NetworkRollback ();
723 networkRollback.setCloudId (cloudSiteId);
724 networkRollback.setTenantId (tenantId);
725 networkRollback.setMsoRequest (msoRequest);
727 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
728 if (!cloudSiteOpt.isPresent()) {
729 String error = String.format(
730 "UpdateNetwork: Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
731 networkName, cloudSiteId, tenantId);
732 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
733 // Set the detailed error as the Exception 'message'
734 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
740 NetworkResource networkResource = networkCheck(
743 modelCustomizationUuid,
750 String mode = networkResource.getOrchestrationMode();
751 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
753 // Use an MsoNeutronUtils for all Neutron commands
755 if (NEUTRON_MODE.equals(mode)) {
757 // Verify that the Network exists
758 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
759 NetworkInfo netInfo = null;
760 long queryNetworkStarttime = System.currentTimeMillis();
762 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
763 } catch (MsoException me) {
764 me.addContext(UPDATE_NETWORK_CONTEXT);
765 logger.error("{} {} Exception - queryNetwork query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
766 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), networkId, cloudSiteId, tenantId, me);
767 throw new NetworkException(me);
770 if (netInfo == null) {
771 String error = String
772 .format("Update Nework: Network %s does not exist in %s/%s", networkId, cloudSiteId, tenantId);
773 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND,
774 MsoLogger.ErrorCode.BusinessProcesssError.getValue(), error);
775 // Does not exist. Throw an exception (can't update a non-existent network)
776 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
778 long updateNetworkStarttime = System.currentTimeMillis();
780 netInfo = neutron.updateNetwork(cloudSiteId,
786 } catch (MsoException me) {
787 me.addContext(UPDATE_NETWORK_CONTEXT);
788 logger.error("{} {} Exception - updateNetwork {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
789 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
790 throw new NetworkException(me);
793 // Add the network ID and previously queried vlans to the rollback object
794 networkRollback.setNetworkId(netInfo.getId());
795 networkRollback.setNeutronNetworkId(netInfo.getId());
796 networkRollback.setNetworkType(networkType);
797 // Save previous parameters
798 networkRollback.setNetworkName(netInfo.getName());
799 networkRollback.setPhysicalNetwork(netInfo.getProvider());
800 networkRollback.setVlans(netInfo.getVlans());
802 logger.debug("Network {} updated, id = {}", networkId, netInfo.getId());
803 } else if ("HEAT".equals(mode)) {
805 // First, look up to see that the Network already exists.
806 // For Heat-based orchestration, the networkId is the network Stack ID.
807 StackInfo heatStack = null;
808 long queryStackStarttime = System.currentTimeMillis();
810 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
811 } catch (MsoException me) {
812 me.addContext(UPDATE_NETWORK_CONTEXT);
813 logger.error("{} {} Exception - QueryStack query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
814 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
815 throw new NetworkException(me);
818 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
819 String error = String
820 .format("UpdateNetwork: Stack %s does not exist in %s/%s", networkName, cloudSiteId, tenantId);
821 logger.error("{} {} {}", MessageEnum.RA_NETWORK_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
823 // Network stack does not exist. Return an error
824 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
827 // Get the previous parameters for rollback
828 Map<String, Object> heatParams = heatStack.getParameters();
830 String previousNetworkName = (String) heatParams.get("network_name");
831 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
833 List<Integer> previousVlans = new ArrayList<>();
834 String vlansParam = (String) heatParams.get(VLANS);
835 if (vlansParam != null) {
836 for (String vlan : vlansParam.split(",")) {
838 previousVlans.add(Integer.parseInt(vlan));
839 } catch (NumberFormatException e) {
840 logger.warn("{} {} Exception - VLAN parse for params {} ", MessageEnum.RA_VLAN_PARSE,
841 MsoLogger.ErrorCode.DataError.getValue(), vlansParam, e);
845 logger.debug("Update Stack: Previous VLANS: {}", previousVlans);
847 // Ready to deploy the updated Network via Heat
850 HeatTemplate heatTemplate = networkResource.getHeatTemplate();
851 if (heatTemplate == null) {
852 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
853 logger.error("{} {} {}", MessageEnum.RA_PARAM_NOT_FOUND, MsoLogger.ErrorCode.DataError.getValue(),
855 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
858 logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString());
860 // "Fix" the template if it has CR/LF (getting this from Oracle)
861 String template = heatTemplate.getHeatTemplate();
862 template = template.replaceAll("\r\n", "\n");
864 boolean aic3template = false;
865 String aic3nw = AIC3_NW;
867 aic3nw = environment.getProperty(AIC3_NW_PROPERTY, AIC3_NW);
869 if (template.contains(aic3nw))
872 // Build the common set of HEAT template parameters
873 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
882 // Validate (and update) the input parameters against the DB definition
883 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
885 stackParams = heat.validateStackParams(stackParams, heatTemplate);
886 } catch (IllegalArgumentException e) {
887 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
888 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
889 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
892 if (subnets != null) {
895 template = mergeSubnetsAIC3(template, subnets, stackParams);
897 template = mergeSubnets(template, subnets);
899 } catch (MsoException me) {
900 me.addContext(UPDATE_NETWORK_CONTEXT);
901 logger.error("{} {} Exception - UpdateNetwork mergeSubnets for network type {} in {}/{} ",
902 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
903 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
904 throw new NetworkException(me);
908 if (policyFqdns != null && aic3template) {
910 mergePolicyRefs(policyFqdns, stackParams);
911 } catch (MsoException me) {
912 me.addContext(UPDATE_NETWORK_CONTEXT);
913 logger.error("{} {} Exception - UpdateNetwork mergePolicyRefs type {} in {}/{} ",
914 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
915 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
916 throw new NetworkException(me);
920 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
922 mergeRouteTableRefs(routeTableFqdns, stackParams);
923 } catch (MsoException me) {
924 me.addContext(UPDATE_NETWORK_CONTEXT);
925 logger.error("{} {} Exception - UpdateNetwork mergeRouteTableRefs type {} in {}/{} ",
926 MessageEnum.RA_UPDATE_NETWORK_ERR, MsoLogger.ErrorCode.DataError.getValue(),
927 neutronNetworkType.toString(), cloudSiteId, tenantId, me);
928 throw new NetworkException(me);
932 // Update the network stack
933 // Ignore MsoStackNotFound exception because we already checked.
934 long updateStackStarttime = System.currentTimeMillis();
936 heatStack = heatWithUpdate.updateStack(cloudSiteId,
942 heatTemplate.getTimeoutMinutes());
943 } catch (MsoException me) {
944 me.addContext(UPDATE_NETWORK_CONTEXT);
945 logger.error("{} {} Exception - update network {} in {}/{} ", MessageEnum.RA_UPDATE_NETWORK_ERR,
946 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
947 throw new NetworkException(me);
950 Map<String, Object> outputs = heatStack.getOutputs();
951 Map<String, String> sMap = new HashMap<>();
952 if (outputs != null) {
953 for (Map.Entry<String, Object> entry : outputs.entrySet()) {
954 String key=entry.getKey();
955 if (key != null && key.startsWith("subnet")) {
956 if (aic3template) //one subnet output expected
958 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
960 } else //multiples subnet_%aaid% outputs allowed
962 String subnetUUId = (String) outputs.get(key);
963 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
968 subnetIdMap.value = sMap;
970 // Reach this point if createStack is successful.
971 // Populate remaining rollback info and response parameters.
972 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
973 if(null != outputs) {
974 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
977 logger.debug("outputs is NULL");
979 networkRollback.setNetworkType(networkType);
980 // Save previous parameters
981 networkRollback.setNetworkName(previousNetworkName);
982 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
983 networkRollback.setVlans(previousVlans);
985 rollback.value = networkRollback;
987 logger.debug("Network {} successfully updated via HEAT", networkId);
993 private NetworkResource networkCheck (long startTime,
995 String modelCustomizationUuid,
997 String physicalNetworkName,
998 List <Integer> vlans,
999 List <RouteTarget> routeTargets,
1001 CloudSite cloudSite) throws NetworkException {
1002 // Retrieve the Network Resource definition
1003 NetworkResource networkResource = null;
1004 NetworkResourceCustomization networkCust = null;
1005 CollectionNetworkResourceCustomization collectionNetworkCust = null;
1006 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1007 if (!commonUtils.isNullOrEmpty(networkType)) {
1008 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1011 networkCust = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1012 if (networkCust == null) {
1013 collectionNetworkCust = collectionNetworkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1016 if(networkCust != null){
1017 logger.debug("Got Network Customization definition from Catalog: {}", networkCust.toString());
1019 networkResource = networkCust.getNetworkResource();
1020 } else if (collectionNetworkCust != null) {
1021 logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}",
1022 collectionNetworkCust.toString());
1023 networkResource = collectionNetworkCust.getNetworkResource();
1025 if (networkResource == null) {
1026 String error = String.format(
1027 "Create/UpdateNetwork: Unable to get network resource with NetworkType: %s or ModelCustomizationUUID:%s",
1028 networkType, modelCustomizationUuid);
1029 logger.error("{} {} {} ", MessageEnum.RA_UNKOWN_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1031 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1033 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1035 String mode = networkResource.getOrchestrationMode();
1036 NetworkType neutronNetworkType = NetworkType
1037 .valueOf(networkResource.getNeutronNetworkType());
1039 // All Networks are orchestrated via HEAT or Neutron
1040 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1041 String error = "CreateNetwork: Configuration Error: Network Type = " + networkType;
1042 logger.error("{} {} {}", MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1043 MsoLogger.ErrorCode.DataError.getValue(), error);
1044 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1047 MavenLikeVersioning aicV = new MavenLikeVersioning();
1048 aicV.setVersion(cloudSite.getCloudVersion());
1049 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1050 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1053 && (aicV.isTheSameVersion(networkResource
1054 .getAicVersionMax()) || !(aicV
1055 .isMoreRecentThan(networkResource
1056 .getAicVersionMax())))) // aic <= max
1058 logger.debug("Network Type:{} VersionMin:{} VersionMax:{} supported on Cloud:{} with AIC_Version:{}",
1059 networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId,
1060 cloudSite.getCloudVersion());
1062 String error = String
1063 .format("Network Type:%s Version_Min:%s Version_Max:%s not supported on Cloud:%s with AIC_Version:%s",
1064 networkType, networkType, networkResource.getAicVersionMin(),
1065 networkResource.getAicVersionMax(), cloudSiteId, cloudSite.getCloudVersion());
1066 logger.error("{} {} {} ", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
1067 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1070 // Validate the Network parameters.
1071 String missing = validateNetworkParams(neutronNetworkType,
1072 networkName, physicalNetworkName, vlans, routeTargets);
1073 if (!missing.isEmpty()) {
1074 String error = "Create Network: Missing parameters: " + missing;
1075 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1077 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1080 return networkResource;
1084 public void queryNetwork (String cloudSiteId,
1086 String networkNameOrId,
1087 MsoRequest msoRequest,
1088 Holder <Boolean> networkExists,
1089 Holder <String> networkId,
1090 Holder <String> neutronNetworkId,
1091 Holder <NetworkStatus> status,
1092 Holder <List <Integer>> vlans,
1093 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1094 queryNetwork (cloudSiteId,
1108 public void queryNetworkContrail (String cloudSiteId,
1110 String networkNameOrId,
1111 MsoRequest msoRequest,
1112 Holder <Boolean> networkExists,
1113 Holder <String> networkId,
1114 Holder <String> neutronNetworkId,
1115 Holder <NetworkStatus> status,
1116 Holder <List <RouteTarget>> routeTargets,
1117 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1118 queryNetwork (cloudSiteId,
1132 * This is the queryNetwork method. It returns the existence and status of
1133 * the specified network, along with its Neutron UUID and list of VLANs.
1134 * This method attempts to find the network using both Heat and Neutron.
1135 * Heat stacks are first searched based on the provided network name/id.
1136 * If none is found, the Neutron is directly queried.
1138 private void queryNetwork (String cloudSiteId,
1140 String networkNameOrId,
1141 MsoRequest msoRequest,
1142 Holder <Boolean> networkExists,
1143 Holder <String> networkId,
1144 Holder <String> neutronNetworkId,
1145 Holder <NetworkStatus> status,
1146 Holder <List <Integer>> vlans,
1147 Holder <List <RouteTarget>> routeTargets,
1148 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1150 logger.debug("*** QUERY Network with Network: {} in {}/{}", networkNameOrId, cloudSiteId, tenantId);
1152 // Will capture execution time for metrics
1153 long startTime = System.currentTimeMillis ();
1155 if (commonUtils.isNullOrEmpty (cloudSiteId)
1156 || commonUtils.isNullOrEmpty(tenantId)
1157 || commonUtils.isNullOrEmpty(networkNameOrId)) {
1159 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1160 logger.error("{} {} {}", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1161 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1164 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1165 if (!cloudSiteOpt.isPresent())
1167 String error = String
1168 .format("Configuration Error. Stack %s in %s/%s: CloudSite does not exist in MSO Configuration",
1169 networkNameOrId, cloudSiteId, tenantId);
1170 logger.error("{} {} {}", MessageEnum.RA_CONFIG_EXC, MsoLogger.ErrorCode.DataError.getValue(), error);
1171 // Set the detailed error as the Exception 'message'
1172 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1175 // Use MsoNeutronUtils for all NEUTRON commands
1179 // Try Heat first, since networks may be named the same as the Heat stack
1180 StackInfo heatStack = null;
1181 long queryStackStarttime = System.currentTimeMillis ();
1183 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1184 } catch (MsoException me) {
1185 me.addContext ("QueryNetwork");
1186 logger.error("{} {} Exception - Query Network (heat): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1187 MsoLogger.ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1188 throw new NetworkException (me);
1191 // Populate the outputs based on the returned Stack information
1192 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1193 // Found it. Get the neutronNetworkId for further query
1194 Map <String, Object> outputs = heatStack.getOutputs ();
1195 neutronId = (String) outputs.get (NETWORK_ID);
1198 Map <String, String> sMap = new HashMap <> ();
1199 if (outputs != null) {
1200 for (String key : outputs.keySet ()) {
1201 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1203 String subnetUUId = (String) outputs.get(key);
1204 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1206 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1208 Map <String, String> map = getSubnetUUId(key, outputs, null);
1214 subnetIdMap.value = sMap;
1216 // Input ID was not a Heat stack ID. Try it directly in Neutron
1217 neutronId = networkNameOrId;
1218 mode = NEUTRON_MODE;
1221 // Query directly against the Neutron Network for the details
1222 // no RouteTargets available for ContrailV2 in neutron net-show
1223 // networkId is heatStackId
1224 long queryNetworkStarttime = System.currentTimeMillis ();
1226 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1227 if (netInfo != null) {
1228 // Found. Populate the output elements
1229 networkExists.value = Boolean.TRUE;
1230 if ("HEAT".equals (mode)) {
1231 networkId.value = heatStack.getCanonicalName ();
1233 networkId.value = netInfo.getId ();
1235 neutronNetworkId.value = netInfo.getId ();
1236 status.value = netInfo.getStatus ();
1238 vlans.value = netInfo.getVlans ();
1240 logger.debug("Network {} found({}), ID = {}{}", networkNameOrId, mode, networkId.value,
1241 ("HEAT".equals(mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1243 // Not found. Populate the status fields, leave the rest null
1244 networkExists.value = Boolean.FALSE;
1245 status.value = NetworkStatus.NOTFOUND;
1246 neutronNetworkId.value = null;
1248 vlans.value = new ArrayList<>();
1250 logger.debug("Network {} not found", networkNameOrId);
1252 } catch (MsoException me) {
1253 me.addContext ("QueryNetwork");
1254 logger.error("{} {} Exception - Query Network (neutron): {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC,
1255 MsoLogger.ErrorCode.DataError.getValue(), networkNameOrId, cloudSiteId, tenantId, me);
1256 throw new NetworkException (me);
1262 * This is the "Delete Network" web service implementation.
1263 * It will delete a Network in the specified cloud and tenant.
1265 * If the network is not found, it is treated as a success.
1267 * This service supports two modes of Network creation/update/delete:
1268 * - via Heat Templates
1270 * The network orchestration mode for each network type is declared in its
1271 * catalog definition.
1273 * For Heat-based orchestration, the networkId should be the stack ID.
1274 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1276 * The method returns nothing on success. Rollback is not possible for delete
1277 * commands, so any failure on delete will require manual fallout in the client.
1280 public void deleteNetwork (String cloudSiteId,
1283 String modelCustomizationUuid,
1285 MsoRequest msoRequest,
1286 Holder <Boolean> networkDeleted) throws NetworkException {
1288 logger.debug("*** DELETE Network adapter with Network: {} in {}/{}", networkId, cloudSiteId, tenantId);
1290 // Will capture execution time for metrics
1291 long startTime = System.currentTimeMillis ();
1294 if (commonUtils.isNullOrEmpty (cloudSiteId)
1295 || commonUtils.isNullOrEmpty(tenantId)
1296 || commonUtils.isNullOrEmpty(networkId)) {
1297 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1298 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1299 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1302 // Retrieve the Network Resource definition
1303 NetworkResource networkResource = null;
1305 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1306 if (!commonUtils.isNullOrEmpty(networkType)) {
1307 networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType);
1310 NetworkResourceCustomization nrc = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid);
1312 networkResource = nrc.getNetworkResource();
1317 if (networkResource != null) {
1318 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1320 mode = networkResource.getOrchestrationMode ();
1323 if (NEUTRON_MODE.equals (mode)) {
1325 // Use MsoNeutronUtils for all NEUTRON commands
1326 long deleteNetworkStarttime = System.currentTimeMillis ();
1328 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1329 // was not found. So don't bother to query first.
1330 boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1331 networkDeleted.value = deleted;
1332 } catch (MsoException me) {
1333 me.addContext ("DeleteNetwork");
1334 logger.error("{} {} Delete Network (neutron): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1335 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1336 throw new NetworkException (me);
1338 } else { // DEFAULT to ("HEAT".equals (mode))
1339 long deleteStackStarttime = System.currentTimeMillis ();
1342 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1343 // So query first to report back if stack WAS deleted or just NOTOFUND
1344 StackInfo heatStack = null;
1345 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1346 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND)
1348 heat.deleteStack (tenantId, cloudSiteId, networkId, true);
1349 networkDeleted.value = true;
1353 networkDeleted.value = false;
1355 } catch (MsoException me) {
1356 me.addContext ("DeleteNetwork");
1357 logger.error("{} {} Delete Network (heat): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC,
1358 MsoLogger.ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me);
1359 throw new NetworkException (me);
1364 // On success, nothing is returned.
1369 * This web service endpoint will rollback a previous Create VNF operation.
1370 * A rollback object is returned to the client in a successful creation
1371 * response. The client can pass that object as-is back to the rollbackVnf
1372 * operation to undo the creation.
1374 * The rollback includes removing the VNF and deleting the tenant if the
1375 * tenant did not exist prior to the VNF creation.
1378 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1379 // Will capture execution time for metrics
1380 long startTime = System.currentTimeMillis ();
1382 if (rollback == null) {
1384 .error("{} {} rollback is null", MessageEnum.RA_ROLLBACK_NULL, MsoLogger.ErrorCode.DataError.getValue());
1388 // Get the elements of the VnfRollback object for easier access
1389 String cloudSiteId = rollback.getCloudId ();
1390 String tenantId = rollback.getTenantId ();
1391 String networkId = rollback.getNetworkStackId ();
1392 String networkType = rollback.getNetworkType ();
1393 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1395 logger.debug("*** ROLLBACK Network {} in {}/{}", networkId, cloudSiteId, tenantId);
1398 // Retrieve the Network Resource definition
1399 NetworkResource networkResource = null;
1400 if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) {
1401 networkResource = networkCustomRepo.findOneByNetworkType(networkType).getNetworkResource();
1403 networkResource = networkCustomRepo.findOneByModelCustomizationUUID(modelCustomizationUuid).getNetworkResource();
1406 if (networkResource != null) {
1408 logger.debug("Got Network definition from Catalog: {}", networkResource.toString());
1410 mode = networkResource.getOrchestrationMode ();
1413 if (rollback.getNetworkCreated ()) {
1414 // Rolling back a newly created network, so delete it.
1415 if (NEUTRON_MODE.equals (mode)) {
1416 // Use MsoNeutronUtils for all NEUTRON commands
1417 long deleteNetworkStarttime = System.currentTimeMillis ();
1419 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1420 // was not found. So don't bother to query first.
1421 neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
1422 } catch (MsoException me) {
1423 me.addContext ("RollbackNetwork");
1424 logger.error("{} {} Exception - Rollback Network (neutron): {} in {}/{} ",
1425 MessageEnum.RA_DELETE_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1426 networkId, cloudSiteId, tenantId, me);
1427 throw new NetworkException (me);
1429 } else { // DEFAULT to if ("HEAT".equals (mode))
1430 long deleteStackStarttime = System.currentTimeMillis ();
1432 // The deleteStack function in MsoHeatUtils returns success if the stack
1433 // was not found. So don't bother to query first.
1434 heat.deleteStack (tenantId, cloudSiteId, networkId, true);
1435 } catch (MsoException me) {
1436 me.addContext ("RollbackNetwork");
1437 logger.error("{} {} Exception - Rollback Network (heat): {} in {}/{} ",
1438 MessageEnum.RA_DELETE_NETWORK_EXC, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1439 networkId, cloudSiteId, tenantId, me);
1440 throw new NetworkException (me);
1448 private String validateNetworkParams (NetworkType neutronNetworkType,
1450 String physicalNetwork,
1451 List <Integer> vlans,
1452 List <RouteTarget> routeTargets) {
1454 StringBuilder missing = new StringBuilder ();
1455 if (commonUtils.isNullOrEmpty(networkName)) {
1456 missing.append ("networkName");
1460 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1461 if (commonUtils.isNullOrEmpty(physicalNetwork)) {
1462 missing.append (sep).append ("physicalNetworkName");
1465 if (vlans == null || vlans.isEmpty ()) {
1466 missing.append (sep).append (VLANS);
1470 return missing.toString ();
1473 private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1475 String physicalNetwork,
1476 List <Integer> vlans,
1477 List <RouteTarget> routeTargets,
1480 boolean aic3template) {
1481 // Build the common set of HEAT template parameters
1482 Map <String, Object> stackParams = new HashMap <> ();
1483 stackParams.put ("network_name", networkName);
1485 if (neutronNetworkType == NetworkType.PROVIDER) {
1486 // For Provider type
1487 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1488 stackParams.put ("vlan", vlans.get (0).toString ());
1489 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1490 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1491 // It supports all ProviderNet properties except segmentation_id, and adds a
1492 // comma-separated-list of VLANs as a "segments" property.
1493 // Note that this does not match the Neutron definition of Multi-Provider network,
1494 // which contains a list of 'segments', each having physical_network, network_type,
1495 // and segmentation_id.
1496 StringBuilder buf = new StringBuilder ();
1498 for (Integer vlan : vlans) {
1499 buf.append (sep).append (vlan.toString ());
1502 String csl = buf.toString ();
1504 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1505 stackParams.put (VLANS, csl);
1507 if (routeTargets != null) {
1509 String rtGlobal = "";
1510 String rtImport = "";
1511 String rtExport = "";
1513 for (RouteTarget rt : routeTargets) {
1514 boolean rtIsNull = false;
1517 String routeTarget = rt.getRouteTarget();
1518 String routeTargetRole = rt.getRouteTargetRole();
1519 logger.debug("Checking for an actually null route target: {}", rt);
1520 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1522 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1528 logger.debug("Input RT:{}", rt);
1529 String role = rt.getRouteTargetRole();
1530 String rtValue = rt.getRouteTarget();
1532 if ("IMPORT".equalsIgnoreCase(role))
1534 sep = rtImport.isEmpty() ? "" : ",";
1535 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1537 else if ("EXPORT".equalsIgnoreCase(role))
1539 sep = rtExport.isEmpty() ? "" : ",";
1540 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1542 else // covers BOTH, empty etc
1544 sep = rtGlobal.isEmpty() ? "" : ",";
1545 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1551 if (!rtImport.isEmpty())
1553 stackParams.put ("route_targets_import", rtImport);
1555 if (!rtExport.isEmpty())
1557 stackParams.put ("route_targets_export", rtExport);
1559 if (!rtGlobal.isEmpty())
1561 stackParams.put ("route_targets", rtGlobal);
1564 if (commonUtils.isNullOrEmpty(shared)) {
1565 stackParams.put ("shared", "False");
1567 stackParams.put ("shared", shared);
1569 if (commonUtils.isNullOrEmpty(external)) {
1570 stackParams.put ("external", "False");
1572 stackParams.put ("external", external);
1579 /** policyRef_list structure in stackParams
1582 "network_policy_refs_data_sequence": {
1583 "network_policy_refs_data_sequence_major": "1",
1584 "network_policy_refs_data_sequence_minor": "0"
1588 "network_policy_refs_data_sequence": {
1589 "network_policy_refs_data_sequence_major": "2",
1590 "network_policy_refs_data_sequence_minor": "0"
1595 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1597 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1599 for (String pf : pFqdns) {
1600 if (!commonUtils.isNullOrEmpty(pf))
1602 ContrailPolicyRef pr = new ContrailPolicyRef();
1603 ContrailPolicyRefSeq refSeq = new ContrailPolicyRefSeq(String.valueOf(index), "0");
1606 logger.debug("Contrail PolicyRefs Data:{}", pr);
1611 JsonNode node = null;
1614 ObjectMapper mapper = new ObjectMapper();
1615 node = mapper.convertValue(prlist, JsonNode.class);
1616 String jsonString = mapper.writeValueAsString(prlist);
1617 logger.debug("Json PolicyRefs Data:{}", jsonString);
1621 String error = "Error creating JsonNode for policyRefs Data";
1622 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, MsoLogger.ErrorCode.BusinessProcesssError.getValue(),
1624 throw new MsoAdapterException (error);
1627 if (pFqdns != null && node != null)
1629 StringBuilder buf = new StringBuilder ();
1631 for (String pf : pFqdns) {
1632 if (!commonUtils.isNullOrEmpty(pf))
1634 buf.append (sep).append (pf);
1638 String csl = buf.toString ();
1639 stackParams.put ("policy_refs", csl);
1640 stackParams.put ("policy_refsdata", node);
1643 logger.debug("StackParams updated with policy refs");
1647 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1650 if (rtFqdns != null)
1652 StringBuilder buf = new StringBuilder ();
1654 for (String rtf : rtFqdns) {
1655 if (!commonUtils.isNullOrEmpty(rtf))
1657 buf.append (sep).append (rtf);
1661 String csl = buf.toString ();
1662 stackParams.put ("route_table_refs", csl);
1665 logger.debug("StackParams updated with route_table refs");
1670 /*** Subnet Output structure from Juniper
1675 "ip_prefix": "10.100.1.0",
1678 "addr_from_start": null,
1679 "enable_dhcp": false,
1680 "default_gateway": "10.100.1.1",
1681 "dns_nameservers": [],
1682 "dhcp_option_list": null,
1683 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
1684 "allocation_pools": [
1686 "start": "10.100.1.3",
1690 "start": "10.100.1.6",
1694 "host_routes": null,
1695 "dns_server_address": "10.100.1.13",
1696 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
1700 "ip_prefix": "10.100.2.16",
1703 "addr_from_start": null,
1704 "enable_dhcp": true,
1705 "default_gateway": "10.100.2.17",
1706 "dns_nameservers": [],
1707 "dhcp_option_list": null,
1708 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
1709 "allocation_pools": [
1711 "start": "10.100.2.18",
1712 "end": "10.100.2.20"
1715 "host_routes": null,
1716 "dns_server_address": "10.100.2.29",
1717 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
1723 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
1726 List<ContrailSubnet> cslist = new ArrayList <> ();
1727 for (Subnet subnet : subnets) {
1728 logger.debug("Input Subnet:{}", subnet.toString());
1729 ContrailSubnet cs = new ContrailSubnetMapper(subnet).map();
1730 logger.debug("Contrail Subnet:{}", cs.toString());
1734 JsonNode node = null;
1737 ObjectMapper mapper = new ObjectMapper();
1738 node = mapper.convertValue(cslist, JsonNode.class);
1739 String jsonString = mapper.writeValueAsString(cslist);
1740 logger.debug("Json Subnet List:{}", jsonString);
1744 String error = "Error creating JsonNode from input subnets";
1745 logger.error("{} {} {} ", MessageEnum.RA_MARSHING_ERROR, MsoLogger.ErrorCode.DataError.getValue(), error, e);
1746 throw new MsoAdapterException (error);
1751 stackParams.put ("subnet_list", node);
1753 //Outputs - All subnets are in one ipam_subnets structure
1754 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
1755 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
1757 // append outputs in heatTemplate
1758 int outputsIdx = heatTemplate.indexOf ("outputs:");
1759 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
1760 logger.debug("Template updated with all AIC3.0 subnets:{}", heatTemplate);
1761 return heatTemplate;
1765 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
1767 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
1770 + " network_id: { get_resource: network }\n"
1771 + " cidr: %cidr%\n";
1773 /* make these optional
1774 + " ip_version: %ipversion%\n"
1775 + " enable_dhcp: %enabledhcp%\n"
1776 + " gateway_ip: %gatewayip%\n"
1777 + " allocation_pools:\n"
1778 + " - start: %poolstart%\n"
1779 + " end: %poolend%\n";
1783 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
1784 + " value: {get_resource: subnet_%subnetId%}\n";
1788 StringBuilder resourcesBuf = new StringBuilder ();
1789 StringBuilder outputsBuf = new StringBuilder ();
1790 for (Subnet subnet : subnets) {
1792 // build template for each subnet
1793 curR = resourceTempl;
1794 if (subnet.getSubnetId () != null) {
1795 curR = curR.replace ("%subnetId%", subnet.getSubnetId ());
1797 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
1798 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1799 throw new MsoAdapterException (error);
1802 if (subnet.getSubnetName () != null) {
1803 curR = curR.replace ("%name%", subnet.getSubnetName ());
1805 curR = curR.replace ("%name%", subnet.getSubnetId ());
1808 if (subnet.getCidr () != null) {
1809 curR = curR.replace ("%cidr%", subnet.getCidr ());
1811 String error = "Missing Required cidr for subnet in HEAT Template";
1812 logger.error("{} {} {} ", MessageEnum.RA_MISSING_PARAM, MsoLogger.ErrorCode.DataError.getValue(), error);
1813 throw new MsoAdapterException (error);
1816 if (subnet.getIpVersion () != null) {
1817 curR = curR + " ip_version: " + subnet.getIpVersion () + "\n";
1819 if (subnet.getEnableDHCP () != null) {
1820 curR = curR + " enable_dhcp: " + Boolean.toString (subnet.getEnableDHCP ()) + "\n";
1822 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
1823 curR = curR + " gateway_ip: " + subnet.getGatewayIp () + "\n";
1826 if (subnet.getAllocationPools() != null) {
1827 curR = curR + " allocation_pools:\n";
1828 for (Pool pool : subnet.getAllocationPools())
1830 if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd()))
1832 curR = curR + " - start: " + pool.getStart () + "\n";
1833 curR = curR + " end: " + pool.getEnd () + "\n";
1838 resourcesBuf.append (curR);
1841 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
1843 outputsBuf.append (curO);
1846 // append resources and outputs in heatTemplate
1847 logger.debug("Tempate initial:{}", heatTemplate);
1848 int outputsIdx = heatTemplate.indexOf ("outputs:");
1849 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
1850 int resourcesIdx = heatTemplate.indexOf ("resources:");
1851 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
1853 logger.debug("Template updated with all subnets:{}", heatTemplate);
1854 return heatTemplate;
1857 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
1859 Map <String, String> sMap = new HashMap <> ();
1862 Object obj = outputs.get(key);
1863 ObjectMapper mapper = new ObjectMapper();
1864 String jStr = mapper.writeValueAsString(obj);
1865 logger.debug("Subnet_Ipam Output JSON String:{} {}", obj.getClass(), jStr);
1867 JsonNode rootNode = mapper.readTree(jStr);
1868 for (JsonNode sNode : rootNode.path("ipam_subnets"))
1870 logger.debug("Output Subnet Node {}", sNode.toString());
1871 String name = sNode.path("subnet_name").textValue();
1872 String uuid = sNode.path("subnet_uuid").textValue();
1873 String aaiId = name; // default
1874 // try to find aaiId for name in input subnetList
1875 if (subnets != null)
1877 for (Subnet subnet : subnets)
1879 if ( subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName()))
1881 if (subnet.getSubnetName().equals(name))
1883 aaiId = subnet.getSubnetId();
1889 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
1894 logger.error("{} {} Exception getting subnet-uuids ", MessageEnum.RA_MARSHING_ERROR,
1895 MsoLogger.ErrorCode.DataError.getValue(), e);
1898 logger.debug("Return sMap {}", sMap.toString());
1902 private static String insertStr (String template, String snippet, int index) {
1904 String updatedTemplate;
1906 logger.debug("Index:{} Snippet:{}", index, snippet);
1908 String templateBeg = template.substring (0, index);
1909 String templateEnd = template.substring (index);
1911 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
1913 logger.debug("Template updated with a subnet:{}", updatedTemplate);
1914 return updatedTemplate;