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 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.mso.adapters.network;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
29 import java.util.Optional;
30 import javax.jws.WebService;
31 import javax.xml.ws.Holder;
33 import org.codehaus.jackson.JsonNode;
34 import org.codehaus.jackson.map.ObjectMapper;
36 import org.openecomp.mso.adapters.network.exceptions.NetworkException;
37 import org.openecomp.mso.cloud.CloudConfig;
38 import org.openecomp.mso.cloud.CloudConfigFactory;
39 import org.openecomp.mso.cloud.CloudSite;
40 import org.openecomp.mso.db.catalog.CatalogDatabase;
41 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
42 import org.openecomp.mso.db.catalog.beans.NetworkResource;
43 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
44 import org.openecomp.mso.entity.MsoRequest;
45 import org.openecomp.mso.logger.MessageEnum;
46 import org.openecomp.mso.logger.MsoAlarmLogger;
47 import org.openecomp.mso.logger.MsoLogger;
48 import org.openecomp.mso.openstack.beans.HeatStatus;
49 import org.openecomp.mso.openstack.beans.NetworkInfo;
50 import org.openecomp.mso.openstack.beans.NetworkRollback;
51 import org.openecomp.mso.openstack.beans.NetworkStatus;
52 import org.openecomp.mso.openstack.beans.Pool;
53 import org.openecomp.mso.openstack.beans.StackInfo;
54 import org.openecomp.mso.openstack.beans.Subnet;
55 import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
56 import org.openecomp.mso.openstack.exceptions.MsoException;
57 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
58 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
59 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
60 import org.openecomp.mso.openstack.utils.MsoNeutronUtils;
61 import org.openecomp.mso.openstack.utils.MsoNeutronUtils.NetworkType;
62 import org.openecomp.mso.properties.MsoPropertiesException;
63 import org.openecomp.mso.properties.MsoPropertiesFactory;
65 import static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty;
67 @WebService(serviceName = "NetworkAdapter", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapter", targetNamespace = "http://org.openecomp.mso/network")
68 public class MsoNetworkAdapterImpl implements MsoNetworkAdapter {
70 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
72 CloudConfigFactory cloudConfigFactory=new CloudConfigFactory();
74 private static final String AIC3_NW_PROPERTY= "org.openecomp.mso.adapters.network.aic3nw";
75 private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork";
76 public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER";
77 private static final String VLANS = "vlans";
78 private static final String PHYSICAL_NETWORK = "physical_network";
79 private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork";
80 private static final String NETWORK_ID = "network_id";
81 private static final String NETWORK_FQDN = "network_fqdn";
82 private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork";
83 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
84 private static final String NEUTRON_MODE = "NEUTRON";
85 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
86 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
87 protected CloudConfig cloudConfig;
90 * Health Check web method. Does nothing but return to show the adapter is deployed.
93 public void healthCheck () {
94 LOGGER.debug ("Health check call in Network Adapter");
98 * Do not use this constructor or the msoPropertiesFactory will be NULL.
100 * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
102 public MsoNetworkAdapterImpl() {
106 * This constructor MUST be used if this class if called with the new operator.
107 * @param msoPropFactory
110 public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) {
111 this.msoPropertiesFactory = msoPropFactory;
112 this.cloudConfigFactory=cloudConfigFact;
113 cloudConfig = cloudConfigFactory.getCloudConfig ();
117 public void createNetwork (String cloudSiteId,
120 String modelCustomizationUuid,
122 String physicalNetworkName,
123 List <Integer> vlans,
124 Boolean failIfExists,
126 List <Subnet> subnets,
127 MsoRequest msoRequest,
128 Holder <String> networkId,
129 Holder <String> neutronNetworkId,
130 Holder <Map <String, String>> subnetIdMap,
131 Holder <NetworkRollback> rollback) throws NetworkException {
132 Holder <String> networkFqdn = new Holder <> ();
133 createNetwork (cloudSiteId,
136 modelCustomizationUuid,
157 public void createNetworkContrail (String cloudSiteId,
160 String modelCustomizationUuid,
162 List <String> routeTargets,
165 Boolean failIfExists,
167 List <Subnet> subnets,
168 List <String> policyFqdns,
169 List<String> routeTableFqdns,
170 MsoRequest msoRequest,
171 Holder <String> networkId,
172 Holder <String> neutronNetworkId,
173 Holder <String> networkFqdn,
174 Holder <Map <String, String>> subnetIdMap,
175 Holder <NetworkRollback> rollback) throws NetworkException {
176 createNetwork (cloudSiteId,
179 modelCustomizationUuid,
200 * This is the "Create Network" web service implementation.
201 * It will create a new Network of the requested type in the specified cloud
202 * and tenant. The tenant must exist at the time this service is called.
204 * If a network with the same name already exists, this can be considered a
205 * success or failure, depending on the value of the 'failIfExists' parameter.
207 * There will be a pre-defined set of network types defined in the MSO Catalog.
208 * All such networks will have a similar configuration, based on the allowable
209 * Openstack networking definitions. This includes basic networks, provider
210 * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
212 * Initially, all provider networks must be "vlan" type, and multiple segments in
213 * a multi-provider network must be multiple VLANs on the same physical network.
215 * This service supports two modes of Network creation/update:
216 * - via Heat Templates
218 * The network orchestration mode for each network type is declared in its
219 * catalog definition. All Heat-based templates must support some subset of
220 * the same input parameters: network_name, physical_network, vlan(s).
222 * The method returns the network ID and a NetworkRollback object. This latter
223 * object can be passed as-is to the rollbackNetwork operation to undo everything
224 * that was created. This is useful if a network is successfully created but
225 * the orchestration fails on a subsequent operation.
228 private void createNetwork (String cloudSiteId,
231 String modelCustomizationUuid,
233 String physicalNetworkName,
234 List <Integer> vlans,
235 List <String> routeTargets,
238 Boolean failIfExists,
240 List <Subnet> subnets,
241 List <String> policyFqdns,
242 List <String> routeTableFqdns,
243 MsoRequest msoRequest,
244 Holder <String> networkId,
245 Holder <String> neutronNetworkId,
246 Holder <String> networkFqdn,
247 Holder <Map <String, String>> subnetIdMap,
248 Holder <NetworkRollback> rollback) throws NetworkException {
249 MsoLogger.setLogContext (msoRequest);
250 MsoLogger.setServiceName ("CreateNetwork");
252 LOGGER.debug ("*** CREATE Network: " + networkName
260 // Will capture execution time for metrics
261 long startTime = System.currentTimeMillis ();
263 // Build a default rollback object (no actions performed)
264 NetworkRollback networkRollback = new NetworkRollback ();
265 networkRollback.setCloudId (cloudSiteId);
266 networkRollback.setTenantId (tenantId);
267 networkRollback.setMsoRequest (msoRequest);
268 networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
270 // tenant query is not required here.
271 // If the tenant doesn’t exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
272 // So this is just catching that error in a bit more obvious way up front.
274 cloudConfig = cloudConfigFactory.getCloudConfig ();
275 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
276 if (!cloudSiteOpt.isPresent())
278 String error = "Configuration Error. Stack " + networkName + " in "
283 + " CloudSite does not exist in MSO Configuration";
284 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
285 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
286 // Set the detailed error as the Exception 'message'
287 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
290 // Get a handle to the Catalog Database
292 // Make sure DB connection is always closed
293 try (CatalogDatabase db = getCatalogDB()) {
294 NetworkResource networkResource = networkCheck(db,
297 modelCustomizationUuid,
303 String mode = networkResource.getOrchestrationMode();
304 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
306 if (NEUTRON_MODE.equals(mode)) {
308 // Use an MsoNeutronUtils for all neutron commands
309 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
311 // See if the Network already exists (by name)
312 NetworkInfo netInfo = null;
313 long queryNetworkStarttime = System.currentTimeMillis();
315 netInfo = neutron.queryNetwork(networkName, tenantId, cloudSiteId);
316 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
317 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
318 "QueryNetwork", null);
319 } catch (MsoException me) {
320 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
321 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack",
322 "OpenStack", "QueryNetwork", null);
323 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
324 MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack",
326 me.addContext(CREATE_NETWORK_CONTEXT);
327 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
328 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack");
329 throw new NetworkException(me);
332 if (netInfo != null) {
333 // Exists. If that's OK, return success with the network ID.
334 // Otherwise, return an exception.
335 if (failIfExists != null && failIfExists) {
336 String error = "Create Nework: Network " + networkName
337 + " already exists in "
341 + " with ID " + netInfo.getId();
342 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId,
343 "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
344 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
346 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
348 // Populate the outputs from the existing network.
349 networkId.value = netInfo.getId();
350 neutronNetworkId.value = netInfo.getId();
351 rollback.value = networkRollback; // Default rollback - no updates performed
352 String msg = "Found Existing network, status=" + netInfo.getStatus() + " for Neutron mode";
353 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
354 MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus());
355 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
361 long createNetworkStarttime = System.currentTimeMillis();
363 netInfo = neutron.createNetwork(cloudSiteId,
369 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
370 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
371 "CreateNetwork", null);
372 } catch (MsoException me) {
373 me.addContext(CREATE_NETWORK_CONTEXT);
374 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.ERROR,
375 MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack",
376 "OpenStack", "CreateNetwork", null);
377 String error = "Create Network: type " + neutronNetworkType
384 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
385 MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me);
386 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
387 MsoLogger.ResponseCode.CommunicationError, error);
389 throw new NetworkException(me);
392 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
394 // If reach this point, network creation is successful.
395 // Since directly created via Neutron, networkId tracked by MSO is the same
396 // as the neutron network ID.
397 networkId.value = netInfo.getId();
398 neutronNetworkId.value = netInfo.getId();
400 networkRollback.setNetworkCreated(true);
401 networkRollback.setNetworkId(netInfo.getId());
402 networkRollback.setNeutronNetworkId(netInfo.getId());
403 networkRollback.setNetworkType(networkType);
405 LOGGER.debug("Network " + networkName + " created, id = " + netInfo.getId());
406 } else if ("HEAT".equals(mode)) {
408 // Use an MsoHeatUtils for all Heat commands
409 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
412 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
413 HeatTemplate heatTemplate = db
414 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
415 if (heatTemplate == null) {
416 String error = "Network error - undefined Heat Template. Network Type = " + networkType;
417 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
418 "Openstack", "", MsoLogger.ErrorCode.DataError,
419 "Network error - undefined Heat Template. Network Type = " + networkType);
420 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
424 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
426 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
429 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
431 // "Fix" the template if it has CR/LF (getting this from Oracle)
432 String template = heatTemplate.getHeatTemplate();
433 template = template.replaceAll("\r\n", "\n");
435 boolean aic3template = false;
436 String aic3nw = AIC3_NW;
438 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
439 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
440 } catch (MsoPropertiesException e) {
441 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
442 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError,
443 "Exception - Unable to get properties", e);
446 if (template.contains(aic3nw))
449 // First, look up to see if the Network already exists (by name).
450 // For HEAT orchestration of networks, the stack name will always match the network name
451 StackInfo heatStack = null;
452 long queryNetworkStarttime = System.currentTimeMillis();
454 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
455 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
456 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
457 "QueryNetwork", null);
458 } catch (MsoException me) {
459 me.addContext(CREATE_NETWORK_CONTEXT);
460 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
461 MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack",
462 "OpenStack", "QueryNetwork", null);
463 String error = "Create Network (heat): query network " + networkName
470 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
471 MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me);
472 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
473 MsoLogger.ResponseCode.CommunicationError, error);
474 throw new NetworkException(me);
477 if (heatStack != null && (heatStack.getStatus() != HeatStatus.NOTFOUND)) {
478 // Stack exists. Return success or error depending on input directive
479 if (failIfExists != null && failIfExists) {
480 String error = "CreateNetwork: Stack " + networkName
481 + " already exists in "
485 + " as " + heatStack.getCanonicalName();
486 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
487 MsoLogger.ErrorCode.DataError, "Network already exists");
488 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
490 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
492 // Populate the outputs from the existing stack.
493 networkId.value = heatStack.getCanonicalName();
494 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
495 rollback.value = networkRollback; // Default rollback - no updates performed
497 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
499 Map<String, Object> outputs = heatStack.getOutputs();
500 Map<String, String> sMap = new HashMap<>();
501 if (outputs != null) {
502 for (String key : outputs.keySet()) {
503 if (key != null && key.startsWith("subnet")) {
504 if (aic3template) //one subnet_id output
506 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
508 } else //multiples subnet_%aaid% outputs
510 String subnetUUId = (String) outputs.get(key);
511 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
516 subnetIdMap.value = sMap;
517 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
518 MsoLogger.ErrorCode.DataError,
519 "Found Existing network stack, status=" + heatStack.getStatus());
520 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc,
521 "Found Existing network stack");
526 // Ready to deploy the new Network
527 // Build the common set of HEAT template parameters
528 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
537 // Validate (and update) the input parameters against the DB definition
538 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
539 // and inputs were already validated.
541 stackParams = heat.validateStackParams(stackParams, heatTemplate);
542 } catch (IllegalArgumentException e) {
543 String error = "Create Network: Configuration Error: " + e.getMessage();
544 LOGGER.error(MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "",
545 MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e);
546 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
550 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError,
552 // Input parameters were not valid
553 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
556 if (subnets != null) {
559 template = mergeSubnetsAIC3(template, subnets, stackParams);
561 template = mergeSubnets(template, subnets);
563 } catch (MsoException me) {
564 me.addContext(CREATE_NETWORK_CONTEXT);
565 String error = "Create Network (heat): type " + neutronNetworkType
572 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
573 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
574 "Exception Create Network, merging subnets", me);
575 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
576 MsoLogger.ResponseCode.InternalError, error);
577 throw new NetworkException(me);
581 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
583 mergePolicyRefs(policyFqdns, stackParams);
584 } catch (MsoException me) {
585 me.addContext(CREATE_NETWORK_CONTEXT);
586 String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType
593 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
594 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
595 "Exception Create Network, merging policyRefs", me);
596 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
597 MsoLogger.ResponseCode.InternalError, error);
598 throw new NetworkException(me);
602 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
604 mergeRouteTableRefs(routeTableFqdns, stackParams);
605 } catch (MsoException me) {
606 me.addContext(CREATE_NETWORK_CONTEXT);
607 String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType
614 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
615 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
616 "Exception Create Network, merging routeTableRefs", me);
617 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
618 MsoLogger.ResponseCode.InternalError, error);
619 throw new NetworkException(me);
623 // Deploy the network stack
624 // Ignore MsoStackAlreadyExists exception because we already checked.
628 heatStack = heat.createStack(cloudSiteId,
634 heatTemplate.getTimeoutMinutes(),
638 backout.booleanValue());
639 } catch (MsoException me) {
640 me.addContext(CREATE_NETWORK_CONTEXT);
641 String error = "Create Network (heat): type " + neutronNetworkType
648 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "",
649 MsoLogger.ErrorCode.DataError, "Exception creating network", me);
650 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
651 MsoLogger.ResponseCode.CommunicationError, error);
652 throw new NetworkException(me);
655 // Reach this point if createStack is successful.
657 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
658 // and the neutronNetworkId is the network UUID returned in stack outputs.
659 networkId.value = heatStack.getCanonicalName();
660 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
662 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
664 Map<String, Object> outputs = heatStack.getOutputs();
665 Map<String, String> sMap = new HashMap<>();
666 if (outputs != null) {
667 for (String key : outputs.keySet()) {
668 if (key != null && key.startsWith("subnet")) {
669 if (aic3template) //one subnet output expected
671 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
673 } else //multiples subnet_%aaid% outputs allowed
675 String subnetUUId = (String) outputs.get(key);
676 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
681 subnetIdMap.value = sMap;
683 rollback.value = networkRollback;
684 // Populate remaining rollback info and response parameters.
685 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
686 networkRollback.setNeutronNetworkId((String) heatStack.getOutputs().get(NETWORK_ID));
687 networkRollback.setNetworkCreated(true);
688 networkRollback.setNetworkType(networkType);
690 LOGGER.debug("Network " + networkName + " successfully created via HEAT");
693 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network");
698 public void updateNetwork (String cloudSiteId,
701 String modelCustomizationUuid,
704 String physicalNetworkName,
705 List <Integer> vlans,
706 List <Subnet> subnets,
707 MsoRequest msoRequest,
708 Holder <Map <String, String>> subnetIdMap,
709 Holder <NetworkRollback> rollback) throws NetworkException {
710 updateNetwork (cloudSiteId,
713 modelCustomizationUuid,
731 public void updateNetworkContrail (String cloudSiteId,
734 String modelCustomizationUuid,
737 List <String> routeTargets,
740 List <Subnet> subnets,
741 List <String> policyFqdns,
742 List<String> routeTableFqdns,
743 MsoRequest msoRequest,
744 Holder <Map <String, String>> subnetIdMap,
745 Holder <NetworkRollback> rollback) throws NetworkException {
746 updateNetwork (cloudSiteId,
749 modelCustomizationUuid,
766 * This is the "Update Network" web service implementation.
767 * It will update an existing Network of the requested type in the specified cloud
768 * and tenant. The typical use will be to replace the VLANs with the supplied
769 * list (to add or remove a VLAN), but other properties may be updated as well.
771 * There will be a pre-defined set of network types defined in the MSO Catalog.
772 * All such networks will have a similar configuration, based on the allowable
773 * Openstack networking definitions. This includes basic networks, provider
774 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
776 * Initially, all provider networks must currently be "vlan" type, and multi-provider
777 * networks must be multiple VLANs on the same physical network.
779 * This service supports two modes of Network update:
780 * - via Heat Templates
782 * The network orchestration mode for each network type is declared in its
783 * catalog definition. All Heat-based templates must support some subset of
784 * the same input parameters: network_name, physical_network, vlan, segments.
786 * The method returns a NetworkRollback object. This object can be passed
787 * as-is to the rollbackNetwork operation to undo everything that was updated.
788 * This is useful if a network is successfully updated but orchestration
789 * fails on a subsequent operation.
791 private void updateNetwork (String cloudSiteId,
794 String modelCustomizationUuid,
797 String physicalNetworkName,
798 List <Integer> vlans,
799 List <String> routeTargets,
802 List <Subnet> subnets,
803 List <String> policyFqdns,
804 List<String> routeTableFqdns,
805 MsoRequest msoRequest,
806 Holder <Map <String, String>> subnetIdMap,
807 Holder <NetworkRollback> rollback) throws NetworkException {
808 MsoLogger.setLogContext (msoRequest);
809 MsoLogger.setServiceName ("UpdateNetwork");
810 LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName
819 // Will capture execution time for metrics
820 long startTime = System.currentTimeMillis ();
822 // Build a default rollback object (no actions performed)
823 NetworkRollback networkRollback = new NetworkRollback ();
824 networkRollback.setCloudId (cloudSiteId);
825 networkRollback.setTenantId (tenantId);
826 networkRollback.setMsoRequest (msoRequest);
828 cloudConfig = cloudConfigFactory.getCloudConfig ();
829 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
830 if (!cloudSiteOpt.isPresent()) {
831 String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in "
836 + " CloudSite does not exist in MSO Configuration";
837 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration");
838 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
839 // Set the detailed error as the Exception 'message'
840 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
843 // Get a handle to the Catalog Database
845 // Make sure DB connection is always closed
846 try (CatalogDatabase db = getCatalogDB()) {
847 NetworkResource networkResource = networkCheck(db,
850 modelCustomizationUuid,
856 String mode = networkResource.getOrchestrationMode();
857 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
859 // Use an MsoNeutronUtils for all Neutron commands
860 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
862 if (NEUTRON_MODE.equals(mode)) {
864 // Verify that the Network exists
865 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
866 NetworkInfo netInfo = null;
867 long queryNetworkStarttime = System.currentTimeMillis();
869 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
870 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
871 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
872 "QueryNetwork", null);
873 } catch (MsoException me) {
874 me.addContext(UPDATE_NETWORK_CONTEXT);
875 String error = "Update Network (neutron): query " + networkId
882 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
883 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
884 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
885 "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me);
886 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
887 MsoLogger.ResponseCode.CommunicationError, error);
888 throw new NetworkException(me);
891 if (netInfo == null) {
892 String error = "Update Nework: Network " + networkId
893 + " does not exist in "
897 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "",
898 MsoLogger.ErrorCode.BusinessProcesssError, "Network not found");
899 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
901 // Does not exist. Throw an exception (can't update a non-existent network)
902 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
904 long updateNetworkStarttime = System.currentTimeMillis();
906 netInfo = neutron.updateNetwork(cloudSiteId,
912 LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
913 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
914 "UpdateNetwork", null);
915 } catch (MsoException me) {
916 me.addContext(UPDATE_NETWORK_CONTEXT);
917 String error = "Update Network (neutron): " + networkId
924 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack",
925 "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me);
926 LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.ERROR,
927 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null);
928 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
929 MsoLogger.ResponseCode.CommunicationError, error);
930 throw new NetworkException(me);
933 // Add the network ID and previously queried vlans to the rollback object
934 networkRollback.setNetworkId(netInfo.getId());
935 networkRollback.setNeutronNetworkId(netInfo.getId());
936 networkRollback.setNetworkType(networkType);
937 // Save previous parameters
938 networkRollback.setNetworkName(netInfo.getName());
939 networkRollback.setPhysicalNetwork(netInfo.getProvider());
940 networkRollback.setVlans(netInfo.getVlans());
942 LOGGER.debug("Network " + networkId + " updated, id = " + netInfo.getId());
943 } else if ("HEAT".equals(mode)) {
945 // Use an MsoHeatUtils for all Heat commands
946 MsoHeatUtilsWithUpdate heat = new MsoHeatUtilsWithUpdate(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
949 // First, look up to see that the Network already exists.
950 // For Heat-based orchestration, the networkId is the network Stack ID.
951 StackInfo heatStack = null;
952 long queryStackStarttime = System.currentTimeMillis();
954 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
955 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE,
956 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
958 } catch (MsoException me) {
959 me.addContext(UPDATE_NETWORK_CONTEXT);
960 String error = "UpdateNetwork (heat): query " + networkName
967 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR,
968 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
969 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
970 "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
971 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
972 MsoLogger.ResponseCode.CommunicationError, error);
973 throw new NetworkException(me);
976 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
977 String error = "UpdateNetwork: Stack " + networkName
978 + " does not exist in "
982 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack",
983 "queryStack", MsoLogger.ErrorCode.DataError, "Network not found");
984 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
986 // Network stack does not exist. Return an error
987 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
990 // Get the previous parameters for rollback
991 Map<String, Object> heatParams = heatStack.getParameters();
993 String previousNetworkName = (String) heatParams.get("network_name");
994 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
996 List<Integer> previousVlans = new ArrayList<>();
997 String vlansParam = (String) heatParams.get(VLANS);
998 if (vlansParam != null) {
999 for (String vlan : vlansParam.split(",")) {
1001 previousVlans.add(Integer.parseInt(vlan));
1002 } catch (NumberFormatException e) {
1003 LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", "",
1004 MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e);
1008 LOGGER.debug("Update Stack: Previous VLANS: " + previousVlans);
1010 // Ready to deploy the updated Network via Heat
1012 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
1013 HeatTemplate heatTemplate = db
1014 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
1015 if (heatTemplate == null) {
1016 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
1017 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
1018 "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError,
1019 "Network error - undefined Heat Template. Network Type=" + networkType);
1020 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1021 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1023 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1026 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1028 // "Fix" the template if it has CR/LF (getting this from Oracle)
1029 String template = heatTemplate.getHeatTemplate();
1030 template = template.replaceAll("\r\n", "\n");
1032 boolean aic3template = false;
1033 String aic3nw = AIC3_NW;
1035 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
1036 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
1037 } catch (MsoPropertiesException e) {
1038 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
1039 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1040 "Exception - Unable to get properties", e);
1042 if (template.contains(aic3nw))
1043 aic3template = true;
1045 // Build the common set of HEAT template parameters
1046 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
1048 physicalNetworkName,
1055 // Validate (and update) the input parameters against the DB definition
1056 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
1058 stackParams = heat.validateStackParams(stackParams, heatTemplate);
1059 } catch (IllegalArgumentException e) {
1060 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
1061 LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "",
1062 MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error");
1063 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1064 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError,
1066 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
1069 if (subnets != null) {
1072 template = mergeSubnetsAIC3(template, subnets, stackParams);
1074 template = mergeSubnets(template, subnets);
1076 } catch (MsoException me) {
1077 me.addContext(UPDATE_NETWORK_CONTEXT);
1078 String error = "Update Network (heat): type " + neutronNetworkType
1085 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1086 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1087 "Exception - UpdateNetwork mergeSubnets ", me);
1088 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1089 MsoLogger.ResponseCode.InternalError, error);
1090 throw new NetworkException(me);
1094 if (policyFqdns != null && aic3template) {
1096 mergePolicyRefs(policyFqdns, stackParams);
1097 } catch (MsoException me) {
1098 me.addContext(UPDATE_NETWORK_CONTEXT);
1099 String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType
1106 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1107 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1108 "Exception - UpdateNetwork mergePolicyRefs", me);
1109 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1110 MsoLogger.ResponseCode.InternalError, error);
1111 throw new NetworkException(me);
1115 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
1117 mergeRouteTableRefs(routeTableFqdns, stackParams);
1118 } catch (MsoException me) {
1119 me.addContext(UPDATE_NETWORK_CONTEXT);
1120 String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType
1127 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1128 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
1129 "Exception - UpdateNetwork mergeRouteTableRefs", me);
1130 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1131 MsoLogger.ResponseCode.InternalError, error);
1132 throw new NetworkException(me);
1136 // Update the network stack
1137 // Ignore MsoStackNotFound exception because we already checked.
1138 long updateStackStarttime = System.currentTimeMillis();
1140 heatStack = heat.updateStack(cloudSiteId,
1146 heatTemplate.getTimeoutMinutes());
1147 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1148 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1149 "UpdateStack", null);
1150 } catch (MsoException me) {
1151 me.addContext(UPDATE_NETWORK_CONTEXT);
1152 String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1153 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1154 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
1155 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "",
1156 MsoLogger.ErrorCode.DataError, "Exception - update network", me);
1157 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1158 MsoLogger.ResponseCode.CommunicationError, error);
1159 throw new NetworkException(me);
1162 Map<String, Object> outputs = heatStack.getOutputs();
1163 Map<String, String> sMap = new HashMap<>();
1164 if (outputs != null) {
1165 for (String key : outputs.keySet()) {
1166 if (key != null && key.startsWith("subnet")) {
1167 if (aic3template) //one subnet output expected
1169 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
1171 } else //multiples subnet_%aaid% outputs allowed
1173 String subnetUUId = (String) outputs.get(key);
1174 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
1179 subnetIdMap.value = sMap;
1181 // Reach this point if createStack is successful.
1182 // Populate remaining rollback info and response parameters.
1183 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
1184 if (null != outputs) {
1185 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
1187 LOGGER.debug("outputs is NULL");
1189 networkRollback.setNetworkType(networkType);
1190 // Save previous parameters
1191 networkRollback.setNetworkName(previousNetworkName);
1192 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
1193 networkRollback.setVlans(previousVlans);
1195 rollback.value = networkRollback;
1197 LOGGER.debug("Network " + networkId + " successfully updated via HEAT");
1200 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network");
1204 private NetworkResource networkCheck (CatalogDatabase db,
1207 String modelCustomizationUuid,
1209 String physicalNetworkName,
1210 List <Integer> vlans,
1211 List <String> routeTargets,
1212 CloudSite cloudSite) throws NetworkException {
1213 // Retrieve the Network Resource definition
1214 NetworkResource networkResource = null;
1216 if (isNullOrEmpty(modelCustomizationUuid)) {
1217 networkResource = db.getNetworkResource(networkType);
1219 networkResource = db
1220 .getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1222 if (networkResource == null) {
1223 String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:"
1225 + " or ModelCustomizationUUID:"
1226 + modelCustomizationUuid;
1227 LOGGER.error(MessageEnum.RA_UNKOWN_PARAM,
1228 "NetworkType/ModelCustomizationUUID", networkType + "/"
1229 + modelCustomizationUuid, "OpenStack", "",
1230 MsoLogger.ErrorCode.DataError,
1231 "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID");
1233 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1235 LOGGER.debug("Got Network definition from Catalog: "
1236 + networkResource.toString());
1238 String mode = networkResource.getOrchestrationMode();
1239 NetworkType neutronNetworkType = NetworkType
1240 .valueOf(networkResource.getNeutronNetworkType());
1242 // All Networks are orchestrated via HEAT or Neutron
1243 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1244 String error = "CreateNetwork: Configuration Error: Network Type = "
1246 LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1247 mode, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1248 "CreateNetwork: Configuration Error");
1249 // Alarm on this error, configuration must be fixed
1250 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1251 MsoAlarmLogger.CRITICAL, error);
1253 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1256 MavenLikeVersioning aicV = new MavenLikeVersioning();
1257 aicV.setVersion(cloudSite.getAic_version());
1258 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1259 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1262 && (aicV.isTheSameVersion(networkResource
1263 .getAicVersionMax()) || !(aicV
1264 .isMoreRecentThan(networkResource
1265 .getAicVersionMax())))) // aic <= max
1267 LOGGER.debug("Network Type:" + networkType + " VersionMin:"
1268 + networkResource.getAicVersionMin() + " VersionMax:"
1269 + networkResource.getAicVersionMax()
1270 + " supported on Cloud:" + cloudSite.getId()
1271 + " with AIC_Version:" + cloudSite.getAic_version());
1273 String error = "Network Type:" + networkType + " Version_Min:"
1274 + networkResource.getAicVersionMin() + " Version_Max:"
1275 + networkResource.getAicVersionMax()
1276 + " not supported on Cloud:" + cloudSite.getId()
1277 + " with AIC_Version:" + cloudSite.getAic_version();
1278 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1279 MsoLogger.ErrorCode.DataError,
1280 "Network Type not supported on Cloud");
1281 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1282 MsoLogger.ResponseCode.DataError, error);
1283 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1286 // Validate the Network parameters.
1287 String missing = validateNetworkParams(neutronNetworkType,
1288 networkName, physicalNetworkName, vlans, routeTargets);
1289 if (!missing.isEmpty()) {
1290 String error = "Create Network: Missing parameters: " + missing;
1291 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing,
1292 "OpenStack", "", MsoLogger.ErrorCode.DataError,
1293 "Create Network: Missing parameters");
1295 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1300 return networkResource;
1304 public void queryNetwork (String cloudSiteId,
1306 String networkNameOrId,
1307 MsoRequest msoRequest,
1308 Holder <Boolean> networkExists,
1309 Holder <String> networkId,
1310 Holder <String> neutronNetworkId,
1311 Holder <NetworkStatus> status,
1312 Holder <List <Integer>> vlans,
1313 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1314 queryNetworkInfo(cloudSiteId,
1327 public void queryNetworkContrail (String cloudSiteId,
1329 String networkNameOrId,
1330 MsoRequest msoRequest,
1331 Holder <Boolean> networkExists,
1332 Holder <String> networkId,
1333 Holder <String> neutronNetworkId,
1334 Holder <NetworkStatus> status,
1335 Holder <List <String>> routeTargets,
1336 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1337 queryNetworkInfo(cloudSiteId,
1350 * This is the queryNetworkInfo method. It returns the existence and status of
1351 * the specified network, along with its Neutron UUID and list of VLANs.
1352 * This method attempts to find the network using both Heat and Neutron.
1353 * Heat stacks are first searched based on the provided network name/id.
1354 * If none is found, the Neutron is directly queried.
1356 private void queryNetworkInfo(String cloudSiteId,
1358 String networkNameOrId,
1359 MsoRequest msoRequest,
1360 Holder <Boolean> networkExists,
1361 Holder <String> networkId,
1362 Holder <String> neutronNetworkId,
1363 Holder <NetworkStatus> status,
1364 Holder <List <Integer>> vlans,
1365 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1366 MsoLogger.setLogContext (msoRequest);
1367 MsoLogger.setServiceName ("QueryNetwork");
1368 LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId
1374 // Will capture execution time for metrics
1375 long startTime = System.currentTimeMillis ();
1377 if (isNullOrEmpty (cloudSiteId)
1378 || isNullOrEmpty(tenantId)
1379 || isNullOrEmpty(networkNameOrId)) {
1381 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1382 LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1383 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1384 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1387 cloudConfig = cloudConfigFactory.getCloudConfig();
1388 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1389 if (!cloudSiteOpt.isPresent())
1391 String error = "Configuration Error. Stack " + networkNameOrId + " in "
1396 + " CloudSite does not exist in MSO Configuration";
1397 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
1398 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1399 // Set the detailed error as the Exception 'message'
1400 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1403 // Use MsoNeutronUtils for all NEUTRON commands
1404 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER,msoPropertiesFactory,cloudConfigFactory);
1405 MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1409 // Try Heat first, since networks may be named the same as the Heat stack
1410 StackInfo heatStack = null;
1411 long queryStackStarttime = System.currentTimeMillis ();
1413 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1414 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
1415 } catch (MsoException me) {
1416 me.addContext ("QueryNetwork");
1417 String error = "Query Network (heat): " + networkNameOrId
1424 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null);
1425 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me);
1426 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1427 throw new NetworkException (me);
1430 // Populate the outputs based on the returned Stack information
1431 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1432 // Found it. Get the neutronNetworkId for further query
1433 Map <String, Object> outputs = heatStack.getOutputs ();
1434 neutronId = (String) outputs.get (NETWORK_ID);
1437 Map <String, String> sMap = new HashMap <> ();
1438 if (outputs != null) {
1439 for (String key : outputs.keySet ()) {
1440 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1442 String subnetUUId = (String) outputs.get(key);
1443 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1445 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1447 Map <String, String> map = getSubnetUUId(key, outputs, null);
1453 subnetIdMap.value = sMap;
1455 // Input ID was not a Heat stack ID. Try it directly in Neutron
1456 neutronId = networkNameOrId;
1457 mode = NEUTRON_MODE;
1460 // Query directly against the Neutron Network for the details
1461 // no RouteTargets available for ContrailV2 in neutron net-show
1462 // networkId is heatStackId
1463 long queryNetworkStarttime = System.currentTimeMillis ();
1465 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1466 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
1467 if (netInfo != null) {
1468 // Found. Populate the output elements
1469 networkExists.value = Boolean.TRUE;
1470 if ("HEAT".equals (mode)) {
1471 networkId.value = heatStack.getCanonicalName ();
1473 networkId.value = netInfo.getId ();
1475 neutronNetworkId.value = netInfo.getId ();
1476 status.value = netInfo.getStatus ();
1478 vlans.value = netInfo.getVlans ();
1480 LOGGER.debug ("Network " + networkNameOrId
1485 + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1487 // Not found. Populate the status fields, leave the rest null
1488 networkExists.value = Boolean.FALSE;
1489 status.value = NetworkStatus.NOTFOUND;
1490 neutronNetworkId.value = null;
1492 vlans.value = new ArrayList<>();
1494 LOGGER.debug ("Network " + networkNameOrId + " not found");
1496 } catch (MsoException me) {
1497 me.addContext ("QueryNetwork");
1498 String error = "Query Network (neutron): " + networkNameOrId
1505 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
1506 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me);
1507 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1508 throw new NetworkException (me);
1510 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network");
1515 * This is the "Delete Network" web service implementation.
1516 * It will delete a Network in the specified cloud and tenant.
1518 * If the network is not found, it is treated as a success.
1520 * This service supports two modes of Network creation/update/delete:
1521 * - via Heat Templates
1523 * The network orchestration mode for each network type is declared in its
1524 * catalog definition.
1526 * For Heat-based orchestration, the networkId should be the stack ID.
1527 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1529 * The method returns nothing on success. Rollback is not possible for delete
1530 * commands, so any failure on delete will require manual fallout in the client.
1533 public void deleteNetwork (String cloudSiteId,
1536 String modelCustomizationUuid,
1538 MsoRequest msoRequest,
1539 Holder <Boolean> networkDeleted) throws NetworkException {
1540 MsoLogger.setLogContext (msoRequest);
1541 MsoLogger.setServiceName ("DeleteNetwork");
1542 LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId
1548 // Will capture execution time for metrics
1549 long startTime = System.currentTimeMillis ();
1551 // Get a handle to the Catalog Database
1553 // Make sure DB connection is always closed
1554 try (CatalogDatabase db = getCatalogDB()) {
1555 if (isNullOrEmpty(cloudSiteId)
1556 || isNullOrEmpty(tenantId)
1557 || isNullOrEmpty(networkId)) {
1558 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1559 LOGGER.error(MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "",
1560 MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1562 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1563 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1566 // Retrieve the Network Resource definition
1567 NetworkResource networkResource = null;
1568 if (isNullOrEmpty(modelCustomizationUuid)) {
1569 networkResource = db.getNetworkResource(networkType);
1570 } else if (!isNullOrEmpty(networkType)) {
1571 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1574 if (networkResource != null) {
1575 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1577 mode = networkResource.getOrchestrationMode();
1580 if (NEUTRON_MODE.equals(mode)) {
1582 // Use MsoNeutronUtils for all NEUTRON commands
1583 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1584 long deleteNetworkStarttime = System.currentTimeMillis();
1586 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1587 // was not found. So don't bother to query first.
1588 boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1589 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1590 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1591 "DeleteNetwork", null);
1592 networkDeleted.value = deleted;
1593 } catch (MsoException me) {
1594 me.addContext("DeleteNetwork");
1595 String error = "Delete Network (neutron): " + networkId
1602 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1603 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1604 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1605 MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me);
1606 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1607 MsoLogger.ResponseCode.CommunicationError, error);
1608 throw new NetworkException(me);
1610 } else { // DEFAULT to ("HEAT".equals (mode))
1611 long deleteStackStarttime = System.currentTimeMillis();
1612 // Use MsoHeatUtils for all HEAT commands
1613 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1614 cloudConfigFactory);
1617 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1618 // So query first to report back if stack WAS deleted or just NOTOFUND
1619 StackInfo heatStack = null;
1620 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1621 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
1622 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1623 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1624 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1625 "DeleteStack", null);
1626 networkDeleted.value = true;
1628 networkDeleted.value = false;
1630 } catch (MsoException me) {
1631 me.addContext("DeleteNetwork");
1632 String error = "Delete Network (heat): " + networkId
1639 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1640 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1641 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1642 MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me);
1643 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1644 MsoLogger.ResponseCode.CommunicationError, error);
1645 throw new NetworkException(me);
1650 // On success, nothing is returned.
1651 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network");
1655 public CatalogDatabase getCatalogDB() {
1656 return CatalogDatabase.getInstance();
1660 * This web service endpoint will rollback a previous Create VNF operation.
1661 * A rollback object is returned to the client in a successful creation
1662 * response. The client can pass that object as-is back to the rollbackVnf
1663 * operation to undo the creation.
1665 * The rollback includes removing the VNF and deleting the tenant if the
1666 * tenant did not exist prior to the VNF creation.
1669 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1670 MsoLogger.setServiceName ("RollbackNetwork");
1671 // Will capture execution time for metrics
1672 long startTime = System.currentTimeMillis ();
1674 if (rollback == null) {
1675 LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null");
1676 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform");
1680 MsoLogger.setLogContext (rollback.getMsoRequest());
1682 // Get the elements of the VnfRollback object for easier access
1683 String cloudSiteId = rollback.getCloudId ();
1684 String tenantId = rollback.getTenantId ();
1685 String networkId = rollback.getNetworkStackId ();
1686 String networkType = rollback.getNetworkType ();
1687 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1689 LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
1691 // rollback may be null (e.g. if network already existed when Create was called)
1692 // Get a handle to the Catalog Database
1694 // Make sure DB connection is always closed
1695 try (CatalogDatabase db = getCatalogDB()) {
1697 // Retrieve the Network Resource definition
1698 NetworkResource networkResource = null;
1699 if (isNullOrEmpty(modelCustomizationUuid)) {
1700 networkResource = db.getNetworkResource(networkType);
1702 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1705 if (networkResource != null) {
1707 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1709 mode = networkResource.getOrchestrationMode();
1712 if (rollback.getNetworkCreated()) {
1713 // Rolling back a newly created network, so delete it.
1714 if (NEUTRON_MODE.equals(mode)) {
1715 // Use MsoNeutronUtils for all NEUTRON commands
1716 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1717 long deleteNetworkStarttime = System.currentTimeMillis();
1719 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1720 // was not found. So don't bother to query first.
1721 neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1722 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1723 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1724 "DeleteNetwork", null);
1725 } catch (MsoException me) {
1726 me.addContext("RollbackNetwork");
1727 String error = "Rollback Network (neutron): " + networkId
1734 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1735 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1737 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1738 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)",
1740 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1741 MsoLogger.ResponseCode.CommunicationError, error);
1742 throw new NetworkException(me);
1744 } else { // DEFAULT to if ("HEAT".equals (mode))
1745 // Use MsoHeatUtils for all HEAT commands
1746 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1747 cloudConfigFactory);
1748 long deleteStackStarttime = System.currentTimeMillis();
1750 // The deleteStack function in MsoHeatUtils returns success if the stack
1751 // was not found. So don't bother to query first.
1752 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1753 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1754 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1755 "DeleteStack", null);
1756 } catch (MsoException me) {
1757 me.addContext("RollbackNetwork");
1758 String error = "Rollback Network (heat): " + networkId
1765 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1766 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1768 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1769 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me);
1770 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1771 MsoLogger.ResponseCode.CommunicationError, error);
1772 throw new NetworkException(me);
1777 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network");
1781 private String validateNetworkParams (NetworkType neutronNetworkType,
1783 String physicalNetwork,
1784 List <Integer> vlans,
1785 List <String> routeTargets) {
1787 StringBuilder missing = new StringBuilder ();
1788 if (isNullOrEmpty(networkName)) {
1789 missing.append ("networkName");
1793 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1794 if (isNullOrEmpty(physicalNetwork)) {
1795 missing.append (sep).append ("physicalNetworkName");
1798 if (vlans == null || vlans.isEmpty ()) {
1799 missing.append (sep).append (VLANS);
1803 return missing.toString ();
1806 private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1808 String physicalNetwork,
1809 List <Integer> vlans,
1810 List <String> routeTargets,
1813 boolean aic3template) {
1814 // Build the common set of HEAT template parameters
1815 Map <String, Object> stackParams = new HashMap <> ();
1816 stackParams.put ("network_name", networkName);
1818 if (neutronNetworkType == NetworkType.PROVIDER) {
1819 // For Provider type
1820 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1821 stackParams.put ("vlan", vlans.get (0).toString ());
1822 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1823 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1824 // It supports all ProviderNet properties except segmentation_id, and adds a
1825 // comma-separated-list of VLANs as a "segments" property.
1826 // Note that this does not match the Neutron definition of Multi-Provider network,
1827 // which contains a list of 'segments', each having physical_network, network_type,
1828 // and segmentation_id.
1829 StringBuilder buf = new StringBuilder ();
1831 for (Integer vlan : vlans) {
1832 buf.append (sep).append (vlan.toString ());
1835 String csl = buf.toString ();
1837 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1838 stackParams.put (VLANS, csl);
1840 if (routeTargets != null && !routeTargets.isEmpty()) {
1841 StringBuilder sb = new StringBuilder ();
1843 for (String rt : routeTargets) {
1844 if (!isNullOrEmpty(rt))
1847 sb.append(sep).append("target:").append(rt);
1849 sb.append (sep).append (rt);
1854 String csl = sb.toString ();
1856 stackParams.put ("route_targets", csl);
1858 if (isNullOrEmpty(shared)) {
1859 stackParams.put ("shared", "False");
1861 stackParams.put ("shared", shared);
1863 if (isNullOrEmpty(external)) {
1864 stackParams.put ("external", "False");
1866 stackParams.put ("external", external);
1873 /** policyRef_list structure in stackParams
1876 "network_policy_refs_data_sequence": {
1877 "network_policy_refs_data_sequence_major": "1",
1878 "network_policy_refs_data_sequence_minor": "0"
1882 "network_policy_refs_data_sequence": {
1883 "network_policy_refs_data_sequence_major": "2",
1884 "network_policy_refs_data_sequence_minor": "0"
1889 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1891 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1893 for (String pf : pFqdns) {
1894 if (!isNullOrEmpty(pf))
1896 ContrailPolicyRef pr = new ContrailPolicyRef();
1897 pr.populate(String.valueOf(index), "0");
1899 LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString());
1904 JsonNode node = null;
1907 ObjectMapper mapper = new ObjectMapper();
1908 node = mapper.convertValue(prlist, JsonNode.class);
1909 String jsonString = mapper.writeValueAsString(prlist);
1910 LOGGER.debug("Json PolicyRefs Data:" + jsonString);
1914 String error = "Error creating JsonNode for policyRefs Data";
1915 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e);
1916 throw new MsoAdapterException (error);
1919 if (pFqdns != null && node != null)
1921 StringBuilder buf = new StringBuilder ();
1923 for (String pf : pFqdns) {
1924 if (!isNullOrEmpty(pf))
1926 buf.append (sep).append (pf);
1930 String csl = buf.toString ();
1931 stackParams.put ("policy_refs", csl);
1932 stackParams.put ("policy_refsdata", node);
1935 LOGGER.debug ("StackParams updated with policy refs");
1939 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1942 if (rtFqdns != null)
1944 StringBuilder buf = new StringBuilder ();
1946 for (String rtf : rtFqdns) {
1947 if (!isNullOrEmpty(rtf))
1949 buf.append (sep).append (rtf);
1953 String csl = buf.toString ();
1954 stackParams.put ("route_table_refs", csl);
1957 LOGGER.debug ("StackParams updated with route_table refs");
1962 /*** Subnet Output structure from Juniper
1967 "ip_prefix": "10.100.1.0",
1970 "addr_from_start": null,
1971 "enable_dhcp": false,
1972 "default_gateway": "10.100.1.1",
1973 "dns_nameservers": [],
1974 "dhcp_option_list": null,
1975 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
1976 "allocation_pools": [
1978 "start": "10.100.1.3",
1982 "start": "10.100.1.6",
1986 "host_routes": null,
1987 "dns_server_address": "10.100.1.13",
1988 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
1992 "ip_prefix": "10.100.2.16",
1995 "addr_from_start": null,
1996 "enable_dhcp": true,
1997 "default_gateway": "10.100.2.17",
1998 "dns_nameservers": [],
1999 "dhcp_option_list": null,
2000 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
2001 "allocation_pools": [
2003 "start": "10.100.2.18",
2004 "end": "10.100.2.20"
2007 "host_routes": null,
2008 "dns_server_address": "10.100.2.29",
2009 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
2015 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
2018 List<ContrailSubnet> cslist = new ArrayList <> ();
2019 for (Subnet subnet : subnets) {
2020 ContrailSubnet cs = new ContrailSubnet();
2021 LOGGER.debug("Input Subnet:" + subnet.toString());
2022 cs.populateWith(subnet);
2023 LOGGER.debug("Contrail Subnet:" + cs.toString());
2027 JsonNode node = null;
2030 ObjectMapper mapper = new ObjectMapper();
2031 node = mapper.convertValue(cslist, JsonNode.class);
2032 String jsonString = mapper.writeValueAsString(cslist);
2033 LOGGER.debug("Json Subnet List:" + jsonString);
2037 String error = "Error creating JsonNode from input subnets";
2038 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e);
2039 throw new MsoAdapterException (error);
2044 stackParams.put ("subnet_list", node);
2046 //Outputs - All subnets are in one ipam_subnets structure
2047 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
2048 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
2050 // append outputs in heatTemplate
2051 int outputsIdx = heatTemplate.indexOf ("outputs:");
2052 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
2053 LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate);
2054 return heatTemplate;
2058 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
2060 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
2063 + " network_id: { get_resource: network }\n"
2064 + " cidr: %cidr%\n";
2066 /* make these optional
2067 + " ip_version: %ipversion%\n"
2068 + " enable_dhcp: %enabledhcp%\n"
2069 + " gateway_ip: %gatewayip%\n"
2070 + " allocation_pools:\n"
2071 + " - start: %poolstart%\n"
2072 + " end: %poolend%\n";
2076 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
2077 + " value: {get_resource: subnet_%subnetId%}\n";
2081 StringBuilder resourcesBuf = new StringBuilder ();
2082 StringBuilder outputsBuf = new StringBuilder ();
2083 for (Subnet subnet : subnets) {
2085 // build template for each subnet
2086 curR = new StringBuilder(resourceTempl);
2087 if (subnet.getSubnetId () != null) {
2088 curR = new StringBuilder(curR.toString().replace("%subnetId%", subnet.getSubnetId()));
2090 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
2091 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID for subnet in HEAT Template");
2092 throw new MsoAdapterException (error);
2095 if (subnet.getSubnetName () != null) {
2096 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetName()));
2098 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetId()));
2101 if (subnet.getCidr () != null) {
2102 curR = new StringBuilder(curR.toString().replace("%cidr%", subnet.getCidr()));
2104 String error = "Missing Required cidr for subnet in HEAT Template";
2105 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template");
2106 throw new MsoAdapterException (error);
2109 if (subnet.getIpVersion () != null) {
2110 curR.append(" ip_version: " + subnet.getIpVersion() + "\n");
2112 if (subnet.getEnableDHCP () != null) {
2113 curR.append(" enable_dhcp: ").append(Boolean.toString(subnet.getEnableDHCP())).append("\n");
2115 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
2116 curR.append(" gateway_ip: " + subnet.getGatewayIp() + "\n");
2119 if (subnet.getAllocationPools() != null) {
2120 curR.append(" allocation_pools:\n");
2121 for (Pool pool : subnet.getAllocationPools())
2123 if (!isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()))
2125 curR.append(" - start: " + pool.getStart() + "\n");
2126 curR.append(" end: " + pool.getEnd() + "\n");
2131 resourcesBuf.append (curR);
2134 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
2136 outputsBuf.append (curO);
2139 // append resources and outputs in heatTemplate
2140 LOGGER.debug ("Tempate initial:" + heatTemplate);
2141 int outputsIdx = heatTemplate.indexOf ("outputs:");
2142 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
2143 int resourcesIdx = heatTemplate.indexOf ("resources:");
2144 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
2146 LOGGER.debug ("Template updated with all subnets:" + heatTemplate);
2147 return heatTemplate;
2150 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
2152 Map <String, String> sMap = new HashMap <> ();
2155 Object obj = outputs.get(key);
2156 ObjectMapper mapper = new ObjectMapper();
2157 String jStr = mapper.writeValueAsString(obj);
2158 LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr);
2160 JsonNode rootNode = mapper.readTree(jStr);
2161 for (JsonNode sNode : rootNode.path("ipam_subnets"))
2163 LOGGER.debug("Output Subnet Node" + sNode.toString());
2164 String name = sNode.path("subnet_name").getTextValue();
2165 String uuid = sNode.path("subnet_uuid").getTextValue();
2166 String aaiId = name; // default
2167 // try to find aaiId for name in input subnetList
2168 if (subnets != null)
2170 for (Subnet subnet : subnets)
2172 if ( subnet != null && !isNullOrEmpty(subnet.getSubnetName()))
2174 if (subnet.getSubnetName().equals(name))
2176 aaiId = subnet.getSubnetId();
2182 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
2187 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e);
2190 LOGGER.debug ("Return sMap" + sMap.toString());
2194 private static String insertStr (String template, String snippet, int index) {
2196 String updatedTemplate;
2198 LOGGER.debug ("Index:" + index + " Snippet:" + snippet);
2200 String templateBeg = template.substring (0, index);
2201 String templateEnd = template.substring (index);
2203 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
2205 LOGGER.debug ("Template updated with a subnet:" + updatedTemplate);
2206 return updatedTemplate;