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 static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
31 import java.util.Optional;
32 import javax.jws.WebService;
33 import javax.xml.ws.Holder;
35 import org.openecomp.mso.adapters.network.exceptions.NetworkException;
36 import org.openecomp.mso.cloud.CloudConfig;
37 import org.openecomp.mso.cloud.CloudConfigFactory;
38 import org.openecomp.mso.cloud.CloudSite;
39 import org.openecomp.mso.db.catalog.CatalogDatabase;
40 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
41 import org.openecomp.mso.db.catalog.beans.NetworkResource;
42 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
43 import org.openecomp.mso.entity.MsoRequest;
44 import org.openecomp.mso.logger.MessageEnum;
45 import org.openecomp.mso.logger.MsoAlarmLogger;
46 import org.openecomp.mso.logger.MsoLogger;
47 import org.openecomp.mso.openstack.beans.HeatStatus;
48 import org.openecomp.mso.openstack.beans.NetworkInfo;
49 import org.openecomp.mso.openstack.beans.NetworkRollback;
50 import org.openecomp.mso.openstack.beans.NetworkStatus;
51 import org.openecomp.mso.openstack.beans.Pool;
52 import org.openecomp.mso.openstack.beans.RouteTarget;
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 com.fasterxml.jackson.databind.JsonNode;
66 import com.fasterxml.jackson.databind.ObjectMapper;
68 @WebService(serviceName = "NetworkAdapter", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapter", targetNamespace = "http://org.openecomp.mso/network")
69 public class MsoNetworkAdapterImpl implements MsoNetworkAdapter {
71 MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
73 CloudConfigFactory cloudConfigFactory=new CloudConfigFactory();
75 protected MsoNeutronUtils neutron;
77 protected MsoHeatUtils heat;
79 protected MsoHeatUtilsWithUpdate heatWithUpdate;
81 private static final String AIC3_NW_PROPERTY= "org.openecomp.mso.adapters.network.aic3nw";
82 private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork";
83 public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER";
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";
92 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
93 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
94 protected CloudConfig cloudConfig;
97 * Health Check web method. Does nothing but return to show the adapter is deployed.
100 public void healthCheck () {
101 LOGGER.debug ("Health check call in Network Adapter");
105 * Do not use this constructor or the msoPropertiesFactory will be NULL.
107 * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
109 public MsoNetworkAdapterImpl() {
113 * This constructor MUST be used if this class if called with the new operator.
114 * @param msoPropFactory
117 public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) {
118 this.msoPropertiesFactory = msoPropFactory;
119 this.cloudConfigFactory=cloudConfigFact;
120 cloudConfig = cloudConfigFactory.getCloudConfig ();
121 neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
122 heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
123 heatWithUpdate = new MsoHeatUtilsWithUpdate(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
128 public void createNetwork (String cloudSiteId,
131 String modelCustomizationUuid,
133 String physicalNetworkName,
134 List <Integer> vlans,
135 Boolean failIfExists,
137 List <Subnet> subnets,
138 MsoRequest msoRequest,
139 Holder <String> networkId,
140 Holder <String> neutronNetworkId,
141 Holder <Map <String, String>> subnetIdMap,
142 Holder <NetworkRollback> rollback) throws NetworkException {
143 Holder <String> networkFqdn = new Holder <> ();
144 createNetwork (cloudSiteId,
147 modelCustomizationUuid,
168 public void createNetworkContrail (String cloudSiteId,
171 String modelCustomizationUuid,
173 List <RouteTarget> routeTargets,
176 Boolean failIfExists,
178 List <Subnet> subnets,
179 List <String> policyFqdns,
180 List<String> routeTableFqdns,
181 MsoRequest msoRequest,
182 Holder <String> networkId,
183 Holder <String> neutronNetworkId,
184 Holder <String> networkFqdn,
185 Holder <Map <String, String>> subnetIdMap,
186 Holder <NetworkRollback> rollback) throws NetworkException {
187 createNetwork (cloudSiteId,
190 modelCustomizationUuid,
211 * This is the "Create Network" web service implementation.
212 * It will create a new Network of the requested type in the specified cloud
213 * and tenant. The tenant must exist at the time this service is called.
215 * If a network with the same name already exists, this can be considered a
216 * success or failure, depending on the value of the 'failIfExists' parameter.
218 * There will be a pre-defined set of network types defined in the MSO Catalog.
219 * All such networks will have a similar configuration, based on the allowable
220 * Openstack networking definitions. This includes basic networks, provider
221 * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
223 * Initially, all provider networks must be "vlan" type, and multiple segments in
224 * a multi-provider network must be multiple VLANs on the same physical network.
226 * This service supports two modes of Network creation/update:
227 * - via Heat Templates
229 * The network orchestration mode for each network type is declared in its
230 * catalog definition. All Heat-based templates must support some subset of
231 * the same input parameters: network_name, physical_network, vlan(s).
233 * The method returns the network ID and a NetworkRollback object. This latter
234 * object can be passed as-is to the rollbackNetwork operation to undo everything
235 * that was created. This is useful if a network is successfully created but
236 * the orchestration fails on a subsequent operation.
239 protected void createNetwork (String cloudSiteId,
242 String modelCustomizationUuid,
244 String physicalNetworkName,
245 List <Integer> vlans,
246 List <RouteTarget> routeTargets,
249 Boolean failIfExists,
251 List <Subnet> subnets,
252 List <String> policyFqdns,
253 List <String> routeTableFqdns,
254 MsoRequest msoRequest,
255 Holder <String> networkId,
256 Holder <String> neutronNetworkId,
257 Holder <String> networkFqdn,
258 Holder <Map <String, String>> subnetIdMap,
259 Holder <NetworkRollback> rollback) throws NetworkException {
260 MsoLogger.setLogContext (msoRequest);
261 MsoLogger.setServiceName ("CreateNetwork");
263 LOGGER.debug ("*** CREATE Network: " + networkName
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 cloudConfig = cloudConfigFactory.getCloudConfig ();
286 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
287 if (!cloudSiteOpt.isPresent())
289 String error = "Configuration Error. Stack " + networkName + " in "
294 + " CloudSite does not exist in MSO Configuration";
295 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
296 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
297 // Set the detailed error as the Exception 'message'
298 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
301 // Get a handle to the Catalog Database
303 // Make sure DB connection is always closed
304 try (CatalogDatabase db = getCatalogDB()) {
305 NetworkResource networkResource = networkCheck(db,
308 modelCustomizationUuid,
314 String mode = networkResource.getOrchestrationMode();
315 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
317 if (NEUTRON_MODE.equals(mode)) {
319 // See if the Network already exists (by name)
320 NetworkInfo netInfo = null;
321 long queryNetworkStarttime = System.currentTimeMillis();
323 netInfo = neutron.queryNetwork(networkName, tenantId, cloudSiteId);
324 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
325 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
326 "QueryNetwork", null);
327 } catch (MsoException me) {
328 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
329 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack",
330 "OpenStack", "QueryNetwork", null);
331 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
332 MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack",
334 me.addContext(CREATE_NETWORK_CONTEXT);
335 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
336 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack");
337 throw new NetworkException(me);
340 if (netInfo != null) {
341 // Exists. If that's OK, return success with the network ID.
342 // Otherwise, return an exception.
343 if (failIfExists != null && failIfExists) {
344 String error = "Create Nework: Network " + networkName
345 + " already exists in "
349 + " with ID " + netInfo.getId();
350 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId,
351 "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
352 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
354 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
356 // Populate the outputs from the existing network.
357 networkId.value = netInfo.getId();
358 neutronNetworkId.value = netInfo.getId();
359 rollback.value = networkRollback; // Default rollback - no updates performed
360 String msg = "Found Existing network, status=" + netInfo.getStatus() + " for Neutron mode";
361 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
362 MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus());
363 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
369 long createNetworkStarttime = System.currentTimeMillis();
371 netInfo = neutron.createNetwork(cloudSiteId,
377 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
378 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
379 "CreateNetwork", null);
380 } catch (MsoException me) {
381 me.addContext(CREATE_NETWORK_CONTEXT);
382 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.ERROR,
383 MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack",
384 "OpenStack", "CreateNetwork", null);
385 String error = "Create Network: type " + neutronNetworkType
392 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
393 MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me);
394 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
395 MsoLogger.ResponseCode.CommunicationError, error);
397 throw new NetworkException(me);
400 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
402 // If reach this point, network creation is successful.
403 // Since directly created via Neutron, networkId tracked by MSO is the same
404 // as the neutron network ID.
405 networkId.value = netInfo.getId();
406 neutronNetworkId.value = netInfo.getId();
408 networkRollback.setNetworkCreated(true);
409 networkRollback.setNetworkId(netInfo.getId());
410 networkRollback.setNeutronNetworkId(netInfo.getId());
411 networkRollback.setNetworkType(networkType);
413 LOGGER.debug("Network " + networkName + " created, id = " + netInfo.getId());
414 } else if ("HEAT".equals(mode)) {
416 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
417 HeatTemplate heatTemplate = db
418 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
419 if (heatTemplate == null) {
420 String error = "Network error - undefined Heat Template. Network Type = " + networkType;
421 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
422 "Openstack", "", MsoLogger.ErrorCode.DataError,
423 "Network error - undefined Heat Template. Network Type = " + networkType);
424 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
428 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
430 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
433 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
435 // "Fix" the template if it has CR/LF (getting this from Oracle)
436 String template = heatTemplate.getHeatTemplate();
437 template = template.replaceAll("\r\n", "\n");
439 boolean aic3template = false;
440 String aic3nw = AIC3_NW;
442 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
443 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
444 } catch (MsoPropertiesException e) {
445 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
446 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError,
447 "Exception - Unable to get properties", e);
450 if (template.contains(aic3nw))
453 // First, look up to see if the Network already exists (by name).
454 // For HEAT orchestration of networks, the stack name will always match the network name
455 StackInfo heatStack = null;
456 long queryNetworkStarttime = System.currentTimeMillis();
458 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
459 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
460 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
461 "QueryNetwork", null);
462 } catch (MsoException me) {
463 me.addContext(CREATE_NETWORK_CONTEXT);
464 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
465 MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack",
466 "OpenStack", "QueryNetwork", null);
467 String error = "Create Network (heat): query network " + networkName
474 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
475 MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me);
476 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
477 MsoLogger.ResponseCode.CommunicationError, error);
478 throw new NetworkException(me);
481 if (heatStack != null && (heatStack.getStatus() != HeatStatus.NOTFOUND)) {
482 // Stack exists. Return success or error depending on input directive
483 if (failIfExists != null && failIfExists) {
484 String error = "CreateNetwork: Stack " + networkName
485 + " already exists in "
489 + " as " + heatStack.getCanonicalName();
490 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
491 MsoLogger.ErrorCode.DataError, "Network already exists");
492 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
494 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
496 // Populate the outputs from the existing stack.
497 networkId.value = heatStack.getCanonicalName();
498 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
499 rollback.value = networkRollback; // Default rollback - no updates performed
501 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
503 Map<String, Object> outputs = heatStack.getOutputs();
504 Map<String, String> sMap = new HashMap<>();
505 if (outputs != null) {
506 for (String key : outputs.keySet()) {
507 if (key != null && key.startsWith("subnet")) {
508 if (aic3template) //one subnet_id output
510 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
512 } else //multiples subnet_%aaid% outputs
514 String subnetUUId = (String) outputs.get(key);
515 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
520 subnetIdMap.value = sMap;
521 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
522 MsoLogger.ErrorCode.DataError,
523 "Found Existing network stack, status=" + heatStack.getStatus());
524 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc,
525 "Found Existing network stack");
530 // Ready to deploy the new Network
531 // Build the common set of HEAT template parameters
532 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
541 // Validate (and update) the input parameters against the DB definition
542 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
543 // and inputs were already validated.
545 stackParams = heat.validateStackParams(stackParams, heatTemplate);
546 } catch (IllegalArgumentException e) {
547 String error = "Create Network: Configuration Error: " + e.getMessage();
548 LOGGER.error(MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "",
549 MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e);
550 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
554 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError,
556 // Input parameters were not valid
557 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
560 if (subnets != null) {
563 template = mergeSubnetsAIC3(template, subnets, stackParams);
565 template = mergeSubnets(template, subnets);
567 } catch (MsoException me) {
568 me.addContext(CREATE_NETWORK_CONTEXT);
569 String error = "Create Network (heat): type " + neutronNetworkType
576 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
577 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
578 "Exception Create Network, merging subnets", me);
579 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
580 MsoLogger.ResponseCode.InternalError, error);
581 throw new NetworkException(me);
585 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
587 mergePolicyRefs(policyFqdns, stackParams);
588 } catch (MsoException me) {
589 me.addContext(CREATE_NETWORK_CONTEXT);
590 String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType
597 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
598 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
599 "Exception Create Network, merging policyRefs", me);
600 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
601 MsoLogger.ResponseCode.InternalError, error);
602 throw new NetworkException(me);
606 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
608 mergeRouteTableRefs(routeTableFqdns, stackParams);
609 } catch (MsoException me) {
610 me.addContext(CREATE_NETWORK_CONTEXT);
611 String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType
618 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
619 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
620 "Exception Create Network, merging routeTableRefs", me);
621 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
622 MsoLogger.ResponseCode.InternalError, error);
623 throw new NetworkException(me);
627 // Deploy the network stack
628 // Ignore MsoStackAlreadyExists exception because we already checked.
632 heatStack = heat.createStack(cloudSiteId,
638 heatTemplate.getTimeoutMinutes(),
642 backout.booleanValue());
643 } catch (MsoException me) {
644 me.addContext(CREATE_NETWORK_CONTEXT);
645 String error = "Create Network (heat): type " + neutronNetworkType
652 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "",
653 MsoLogger.ErrorCode.DataError, "Exception creating network", me);
654 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
655 MsoLogger.ResponseCode.CommunicationError, error);
656 throw new NetworkException(me);
659 // Reach this point if createStack is successful.
661 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
662 // and the neutronNetworkId is the network UUID returned in stack outputs.
663 networkId.value = heatStack.getCanonicalName();
664 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
666 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
668 Map<String, Object> outputs = heatStack.getOutputs();
669 Map<String, String> sMap = new HashMap<>();
670 if (outputs != null) {
671 for (String key : outputs.keySet()) {
672 if (key != null && key.startsWith("subnet")) {
673 if (aic3template) //one subnet output expected
675 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
677 } else //multiples subnet_%aaid% outputs allowed
679 String subnetUUId = (String) outputs.get(key);
680 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
685 subnetIdMap.value = sMap;
687 rollback.value = networkRollback;
688 // Populate remaining rollback info and response parameters.
689 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
690 networkRollback.setNeutronNetworkId((String) heatStack.getOutputs().get(NETWORK_ID));
691 networkRollback.setNetworkCreated(true);
692 networkRollback.setNetworkType(networkType);
694 LOGGER.debug("Network " + networkName + " successfully created via HEAT");
697 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network");
702 public void updateNetwork (String cloudSiteId,
705 String modelCustomizationUuid,
708 String physicalNetworkName,
709 List <Integer> vlans,
710 List <Subnet> subnets,
711 MsoRequest msoRequest,
712 Holder <Map <String, String>> subnetIdMap,
713 Holder <NetworkRollback> rollback) throws NetworkException {
714 updateNetwork (cloudSiteId,
717 modelCustomizationUuid,
735 public void updateNetworkContrail (String cloudSiteId,
738 String modelCustomizationUuid,
741 List <RouteTarget> routeTargets,
744 List <Subnet> subnets,
745 List <String> policyFqdns,
746 List<String> routeTableFqdns,
747 MsoRequest msoRequest,
748 Holder <Map <String, String>> subnetIdMap,
749 Holder <NetworkRollback> rollback) throws NetworkException {
750 updateNetwork (cloudSiteId,
753 modelCustomizationUuid,
770 * This is the "Update Network" web service implementation.
771 * It will update an existing Network of the requested type in the specified cloud
772 * and tenant. The typical use will be to replace the VLANs with the supplied
773 * list (to add or remove a VLAN), but other properties may be updated as well.
775 * There will be a pre-defined set of network types defined in the MSO Catalog.
776 * All such networks will have a similar configuration, based on the allowable
777 * Openstack networking definitions. This includes basic networks, provider
778 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
780 * Initially, all provider networks must currently be "vlan" type, and multi-provider
781 * networks must be multiple VLANs on the same physical network.
783 * This service supports two modes of Network update:
784 * - via Heat Templates
786 * The network orchestration mode for each network type is declared in its
787 * catalog definition. All Heat-based templates must support some subset of
788 * the same input parameters: network_name, physical_network, vlan, segments.
790 * The method returns a NetworkRollback object. This object can be passed
791 * as-is to the rollbackNetwork operation to undo everything that was updated.
792 * This is useful if a network is successfully updated but orchestration
793 * fails on a subsequent operation.
795 private void updateNetwork (String cloudSiteId,
798 String modelCustomizationUuid,
801 String physicalNetworkName,
802 List <Integer> vlans,
803 List <RouteTarget> routeTargets,
806 List <Subnet> subnets,
807 List <String> policyFqdns,
808 List<String> routeTableFqdns,
809 MsoRequest msoRequest,
810 Holder <Map <String, String>> subnetIdMap,
811 Holder <NetworkRollback> rollback) throws NetworkException {
812 MsoLogger.setLogContext (msoRequest);
813 MsoLogger.setServiceName ("UpdateNetwork");
814 LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName
823 // Will capture execution time for metrics
824 long startTime = System.currentTimeMillis ();
826 // Build a default rollback object (no actions performed)
827 NetworkRollback networkRollback = new NetworkRollback ();
828 networkRollback.setCloudId (cloudSiteId);
829 networkRollback.setTenantId (tenantId);
830 networkRollback.setMsoRequest (msoRequest);
832 cloudConfig = cloudConfigFactory.getCloudConfig ();
833 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
834 if (!cloudSiteOpt.isPresent()) {
835 String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in "
840 + " CloudSite does not exist in MSO Configuration";
841 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration");
842 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
843 // Set the detailed error as the Exception 'message'
844 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
847 // Get a handle to the Catalog Database
849 // Make sure DB connection is always closed
850 try (CatalogDatabase db = getCatalogDB()) {
851 NetworkResource networkResource = networkCheck(db,
854 modelCustomizationUuid,
860 String mode = networkResource.getOrchestrationMode();
861 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
863 if (NEUTRON_MODE.equals(mode)) {
865 // Verify that the Network exists
866 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
867 NetworkInfo netInfo = null;
868 long queryNetworkStarttime = System.currentTimeMillis();
870 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
871 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
872 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
873 "QueryNetwork", null);
874 } catch (MsoException me) {
875 me.addContext(UPDATE_NETWORK_CONTEXT);
876 String error = "Update Network (neutron): query " + networkId
883 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
884 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
885 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
886 "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me);
887 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
888 MsoLogger.ResponseCode.CommunicationError, error);
889 throw new NetworkException(me);
892 if (netInfo == null) {
893 String error = "Update Nework: Network " + networkId
894 + " does not exist in "
898 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "",
899 MsoLogger.ErrorCode.BusinessProcesssError, "Network not found");
900 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
902 // Does not exist. Throw an exception (can't update a non-existent network)
903 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
905 long updateNetworkStarttime = System.currentTimeMillis();
907 netInfo = neutron.updateNetwork(cloudSiteId,
913 LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
914 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
915 "UpdateNetwork", null);
916 } catch (MsoException me) {
917 me.addContext(UPDATE_NETWORK_CONTEXT);
918 String error = "Update Network (neutron): " + networkId
925 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack",
926 "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me);
927 LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.ERROR,
928 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null);
929 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
930 MsoLogger.ResponseCode.CommunicationError, error);
931 throw new NetworkException(me);
934 // Add the network ID and previously queried vlans to the rollback object
935 networkRollback.setNetworkId(netInfo.getId());
936 networkRollback.setNeutronNetworkId(netInfo.getId());
937 networkRollback.setNetworkType(networkType);
938 // Save previous parameters
939 networkRollback.setNetworkName(netInfo.getName());
940 networkRollback.setPhysicalNetwork(netInfo.getProvider());
941 networkRollback.setVlans(netInfo.getVlans());
943 LOGGER.debug("Network " + networkId + " updated, id = " + netInfo.getId());
944 } else if ("HEAT".equals(mode)) {
946 // First, look up to see that the Network already exists.
947 // For Heat-based orchestration, the networkId is the network Stack ID.
948 StackInfo heatStack = null;
949 long queryStackStarttime = System.currentTimeMillis();
951 heatStack = heatWithUpdate.queryStack(cloudSiteId, tenantId, networkName);
952 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE,
953 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
955 } catch (MsoException me) {
956 me.addContext(UPDATE_NETWORK_CONTEXT);
957 String error = "UpdateNetwork (heat): query " + networkName
964 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR,
965 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
966 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
967 "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
968 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
969 MsoLogger.ResponseCode.CommunicationError, error);
970 throw new NetworkException(me);
973 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
974 String error = "UpdateNetwork: Stack " + networkName
975 + " does not exist in "
979 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack",
980 "queryStack", MsoLogger.ErrorCode.DataError, "Network not found");
981 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
983 // Network stack does not exist. Return an error
984 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
987 // Get the previous parameters for rollback
988 Map<String, Object> heatParams = heatStack.getParameters();
990 String previousNetworkName = (String) heatParams.get("network_name");
991 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
993 List<Integer> previousVlans = new ArrayList<>();
994 String vlansParam = (String) heatParams.get(VLANS);
995 if (vlansParam != null) {
996 for (String vlan : vlansParam.split(",")) {
998 previousVlans.add(Integer.parseInt(vlan));
999 } catch (NumberFormatException e) {
1000 LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", "",
1001 MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e);
1005 LOGGER.debug("Update Stack: Previous VLANS: " + previousVlans);
1007 // Ready to deploy the updated Network via Heat
1009 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
1010 HeatTemplate heatTemplate = db
1011 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
1012 if (heatTemplate == null) {
1013 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
1014 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
1015 "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError,
1016 "Network error - undefined Heat Template. Network Type=" + networkType);
1017 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1018 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1020 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1023 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1025 // "Fix" the template if it has CR/LF (getting this from Oracle)
1026 String template = heatTemplate.getHeatTemplate();
1027 template = template.replaceAll("\r\n", "\n");
1029 boolean aic3template = false;
1030 String aic3nw = AIC3_NW;
1032 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
1033 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
1034 } catch (MsoPropertiesException e) {
1035 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
1036 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1037 "Exception - Unable to get properties", e);
1039 if (template.contains(aic3nw))
1040 aic3template = true;
1042 // Build the common set of HEAT template parameters
1043 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
1045 physicalNetworkName,
1052 // Validate (and update) the input parameters against the DB definition
1053 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
1055 stackParams = heatWithUpdate.validateStackParams(stackParams, heatTemplate);
1056 } catch (IllegalArgumentException e) {
1057 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
1058 LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "",
1059 MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error");
1060 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1061 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError,
1063 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
1066 if (subnets != null) {
1069 template = mergeSubnetsAIC3(template, subnets, stackParams);
1071 template = mergeSubnets(template, subnets);
1073 } catch (MsoException me) {
1074 me.addContext(UPDATE_NETWORK_CONTEXT);
1075 String error = "Update Network (heat): type " + neutronNetworkType
1082 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1083 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1084 "Exception - UpdateNetwork mergeSubnets ", me);
1085 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1086 MsoLogger.ResponseCode.InternalError, error);
1087 throw new NetworkException(me);
1091 if (policyFqdns != null && aic3template) {
1093 mergePolicyRefs(policyFqdns, stackParams);
1094 } catch (MsoException me) {
1095 me.addContext(UPDATE_NETWORK_CONTEXT);
1096 String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType
1103 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1104 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1105 "Exception - UpdateNetwork mergePolicyRefs", me);
1106 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1107 MsoLogger.ResponseCode.InternalError, error);
1108 throw new NetworkException(me);
1112 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
1114 mergeRouteTableRefs(routeTableFqdns, stackParams);
1115 } catch (MsoException me) {
1116 me.addContext(UPDATE_NETWORK_CONTEXT);
1117 String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType
1124 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1125 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
1126 "Exception - UpdateNetwork mergeRouteTableRefs", me);
1127 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1128 MsoLogger.ResponseCode.InternalError, error);
1129 throw new NetworkException(me);
1133 // Update the network stack
1134 // Ignore MsoStackNotFound exception because we already checked.
1135 long updateStackStarttime = System.currentTimeMillis();
1137 heatStack = heatWithUpdate.updateStack(cloudSiteId,
1143 heatTemplate.getTimeoutMinutes());
1144 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1145 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1146 "UpdateStack", null);
1147 } catch (MsoException me) {
1148 me.addContext(UPDATE_NETWORK_CONTEXT);
1149 String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1150 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1151 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
1152 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "",
1153 MsoLogger.ErrorCode.DataError, "Exception - update network", me);
1154 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1155 MsoLogger.ResponseCode.CommunicationError, error);
1156 throw new NetworkException(me);
1159 Map<String, Object> outputs = heatStack.getOutputs();
1160 Map<String, String> sMap = new HashMap<>();
1161 if (outputs != null) {
1162 for (String key : outputs.keySet()) {
1163 if (key != null && key.startsWith("subnet")) {
1164 if (aic3template) //one subnet output expected
1166 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
1168 } else //multiples subnet_%aaid% outputs allowed
1170 String subnetUUId = (String) outputs.get(key);
1171 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
1176 subnetIdMap.value = sMap;
1178 // Reach this point if createStack is successful.
1179 // Populate remaining rollback info and response parameters.
1180 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
1181 if (null != outputs) {
1182 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
1184 LOGGER.debug("outputs is NULL");
1186 networkRollback.setNetworkType(networkType);
1187 // Save previous parameters
1188 networkRollback.setNetworkName(previousNetworkName);
1189 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
1190 networkRollback.setVlans(previousVlans);
1192 rollback.value = networkRollback;
1194 LOGGER.debug("Network " + networkId + " successfully updated via HEAT");
1197 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network");
1201 protected NetworkResource networkCheck (CatalogDatabase db,
1204 String modelCustomizationUuid,
1206 String physicalNetworkName,
1207 List <Integer> vlans,
1208 List <RouteTarget> routeTargets,
1209 CloudSite cloudSite) throws NetworkException {
1210 // Retrieve the Network Resource definition
1211 NetworkResource networkResource = null;
1213 if (isNullOrEmpty(modelCustomizationUuid)) {
1214 networkResource = db.getNetworkResource(networkType);
1216 networkResource = db
1217 .getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1219 if (networkResource == null) {
1220 String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:"
1222 + " or ModelCustomizationUUID:"
1223 + modelCustomizationUuid;
1224 LOGGER.error(MessageEnum.RA_UNKOWN_PARAM,
1225 "NetworkType/ModelCustomizationUUID", networkType + "/"
1226 + modelCustomizationUuid, "OpenStack", "",
1227 MsoLogger.ErrorCode.DataError,
1228 "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID");
1230 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1232 LOGGER.debug("Got Network definition from Catalog: "
1233 + networkResource.toString());
1235 String mode = networkResource.getOrchestrationMode();
1236 NetworkType neutronNetworkType = NetworkType
1237 .valueOf(networkResource.getNeutronNetworkType());
1239 // All Networks are orchestrated via HEAT or Neutron
1240 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1241 String error = "CreateNetwork: Configuration Error: Network Type = "
1243 LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1244 mode, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1245 "CreateNetwork: Configuration Error");
1246 // Alarm on this error, configuration must be fixed
1247 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1248 MsoAlarmLogger.CRITICAL, error);
1250 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1253 MavenLikeVersioning aicV = new MavenLikeVersioning();
1254 aicV.setVersion(cloudSite.getAic_version());
1255 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1256 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1259 && (aicV.isTheSameVersion(networkResource
1260 .getAicVersionMax()) || !(aicV
1261 .isMoreRecentThan(networkResource
1262 .getAicVersionMax())))) // aic <= max
1264 LOGGER.debug("Network Type:" + networkType + " VersionMin:"
1265 + networkResource.getAicVersionMin() + " VersionMax:"
1266 + networkResource.getAicVersionMax()
1267 + " supported on Cloud:" + cloudSite.getId()
1268 + " with AIC_Version:" + cloudSite.getAic_version());
1270 String error = "Network Type:" + networkType + " Version_Min:"
1271 + networkResource.getAicVersionMin() + " Version_Max:"
1272 + networkResource.getAicVersionMax()
1273 + " not supported on Cloud:" + cloudSite.getId()
1274 + " with AIC_Version:" + cloudSite.getAic_version();
1275 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1276 MsoLogger.ErrorCode.DataError,
1277 "Network Type not supported on Cloud");
1278 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1279 MsoLogger.ResponseCode.DataError, error);
1280 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1283 // Validate the Network parameters.
1284 String missing = validateNetworkParams(neutronNetworkType,
1285 networkName, physicalNetworkName, vlans, routeTargets);
1286 if (!missing.isEmpty()) {
1287 String error = "Create Network: Missing parameters: " + missing;
1288 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing,
1289 "OpenStack", "", MsoLogger.ErrorCode.DataError,
1290 "Create Network: Missing parameters");
1292 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1297 return networkResource;
1301 public void queryNetwork (String cloudSiteId,
1303 String networkNameOrId,
1304 MsoRequest msoRequest,
1305 Holder <Boolean> networkExists,
1306 Holder <String> networkId,
1307 Holder <String> neutronNetworkId,
1308 Holder <NetworkStatus> status,
1309 Holder <List <Integer>> vlans,
1310 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1311 queryNetworkInfo(cloudSiteId,
1325 public void queryNetworkContrail (String cloudSiteId,
1327 String networkNameOrId,
1328 MsoRequest msoRequest,
1329 Holder <Boolean> networkExists,
1330 Holder <String> networkId,
1331 Holder <String> neutronNetworkId,
1332 Holder <NetworkStatus> status,
1333 Holder <List <RouteTarget>> routeTargets,
1334 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1335 queryNetworkInfo(cloudSiteId,
1349 * This is the queryNetworkInfo method. It returns the existence and status of
1350 * the specified network, along with its Neutron UUID and list of VLANs.
1351 * This method attempts to find the network using both Heat and Neutron.
1352 * Heat stacks are first searched based on the provided network name/id.
1353 * If none is found, the Neutron is directly queried.
1355 private void queryNetworkInfo(String cloudSiteId,
1357 String networkNameOrId,
1358 MsoRequest msoRequest,
1359 Holder <Boolean> networkExists,
1360 Holder <String> networkId,
1361 Holder <String> neutronNetworkId,
1362 Holder <NetworkStatus> status,
1363 Holder <List <Integer>> vlans,
1364 Holder <List <RouteTarget>> routeTargets,
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);
1405 // Try Heat first, since networks may be named the same as the Heat stack
1406 StackInfo heatStack = null;
1407 long queryStackStarttime = System.currentTimeMillis ();
1409 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1410 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
1411 } catch (MsoException me) {
1412 me.addContext ("QueryNetwork");
1413 String error = "Query Network (heat): " + networkNameOrId
1420 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null);
1421 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me);
1422 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1423 throw new NetworkException (me);
1426 // Populate the outputs based on the returned Stack information
1427 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1428 // Found it. Get the neutronNetworkId for further query
1429 Map <String, Object> outputs = heatStack.getOutputs ();
1430 neutronId = (String) outputs.get (NETWORK_ID);
1433 Map <String, String> sMap = new HashMap <> ();
1434 if (outputs != null) {
1435 for (String key : outputs.keySet ()) {
1436 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1438 String subnetUUId = (String) outputs.get(key);
1439 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1441 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1443 Map <String, String> map = getSubnetUUId(key, outputs, null);
1449 subnetIdMap.value = sMap;
1451 // Input ID was not a Heat stack ID. Try it directly in Neutron
1452 neutronId = networkNameOrId;
1453 mode = NEUTRON_MODE;
1456 // Query directly against the Neutron Network for the details
1457 // no RouteTargets available for ContrailV2 in neutron net-show
1458 // networkId is heatStackId
1459 long queryNetworkStarttime = System.currentTimeMillis ();
1461 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1462 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
1463 if (netInfo != null) {
1464 // Found. Populate the output elements
1465 networkExists.value = Boolean.TRUE;
1466 if ("HEAT".equals (mode)) {
1467 networkId.value = heatStack.getCanonicalName ();
1469 networkId.value = netInfo.getId ();
1471 neutronNetworkId.value = netInfo.getId ();
1472 status.value = netInfo.getStatus ();
1474 vlans.value = netInfo.getVlans ();
1476 LOGGER.debug ("Network " + networkNameOrId
1481 + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1483 // Not found. Populate the status fields, leave the rest null
1484 networkExists.value = Boolean.FALSE;
1485 status.value = NetworkStatus.NOTFOUND;
1486 neutronNetworkId.value = null;
1488 vlans.value = new ArrayList<>();
1490 LOGGER.debug ("Network " + networkNameOrId + " not found");
1492 } catch (MsoException me) {
1493 me.addContext ("QueryNetwork");
1494 String error = "Query Network (neutron): " + networkNameOrId
1501 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
1502 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me);
1503 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1504 throw new NetworkException (me);
1506 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network");
1511 * This is the "Delete Network" web service implementation.
1512 * It will delete a Network in the specified cloud and tenant.
1514 * If the network is not found, it is treated as a success.
1516 * This service supports two modes of Network creation/update/delete:
1517 * - via Heat Templates
1519 * The network orchestration mode for each network type is declared in its
1520 * catalog definition.
1522 * For Heat-based orchestration, the networkId should be the stack ID.
1523 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1525 * The method returns nothing on success. Rollback is not possible for delete
1526 * commands, so any failure on delete will require manual fallout in the client.
1529 public void deleteNetwork (String cloudSiteId,
1532 String modelCustomizationUuid,
1534 MsoRequest msoRequest,
1535 Holder <Boolean> networkDeleted) throws NetworkException {
1536 MsoLogger.setLogContext (msoRequest);
1537 MsoLogger.setServiceName ("DeleteNetwork");
1538 LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId
1544 // Will capture execution time for metrics
1545 long startTime = System.currentTimeMillis ();
1547 // Get a handle to the Catalog Database
1549 // Make sure DB connection is always closed
1550 try (CatalogDatabase db = getCatalogDB()) {
1551 if (isNullOrEmpty(cloudSiteId)
1552 || isNullOrEmpty(tenantId)
1553 || isNullOrEmpty(networkId)) {
1554 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1555 LOGGER.error(MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "",
1556 MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1558 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1559 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1562 // Retrieve the Network Resource definition
1563 NetworkResource networkResource = null;
1564 if (isNullOrEmpty(modelCustomizationUuid)) {
1565 networkResource = db.getNetworkResource(networkType);
1566 } else if (!isNullOrEmpty(networkType)) {
1567 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1570 if (networkResource != null) {
1571 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1573 mode = networkResource.getOrchestrationMode();
1576 if (NEUTRON_MODE.equals(mode)) {
1578 // Use MsoNeutronUtils for all NEUTRON commands
1579 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1580 long deleteNetworkStarttime = System.currentTimeMillis();
1582 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1583 // was not found. So don't bother to query first.
1584 boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1585 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1586 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1587 "DeleteNetwork", null);
1588 networkDeleted.value = deleted;
1589 } catch (MsoException me) {
1590 me.addContext("DeleteNetwork");
1591 String error = "Delete Network (neutron): " + networkId
1598 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1599 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1600 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1601 MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me);
1602 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1603 MsoLogger.ResponseCode.CommunicationError, error);
1604 throw new NetworkException(me);
1606 } else { // DEFAULT to ("HEAT".equals (mode))
1607 long deleteStackStarttime = System.currentTimeMillis();
1608 // Use MsoHeatUtils for all HEAT commands
1609 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1610 cloudConfigFactory);
1613 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1614 // So query first to report back if stack WAS deleted or just NOTOFUND
1615 StackInfo heatStack = null;
1616 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1617 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
1618 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1619 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1620 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1621 "DeleteStack", null);
1622 networkDeleted.value = true;
1624 networkDeleted.value = false;
1626 } catch (MsoException me) {
1627 me.addContext("DeleteNetwork");
1628 String error = "Delete Network (heat): " + networkId
1635 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1636 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1637 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1638 MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me);
1639 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1640 MsoLogger.ResponseCode.CommunicationError, error);
1641 throw new NetworkException(me);
1646 // On success, nothing is returned.
1647 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network");
1651 public CatalogDatabase getCatalogDB() {
1652 return CatalogDatabase.getInstance();
1656 * This web service endpoint will rollback a previous Create VNF operation.
1657 * A rollback object is returned to the client in a successful creation
1658 * response. The client can pass that object as-is back to the rollbackVnf
1659 * operation to undo the creation.
1661 * The rollback includes removing the VNF and deleting the tenant if the
1662 * tenant did not exist prior to the VNF creation.
1665 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1666 MsoLogger.setServiceName ("RollbackNetwork");
1667 // Will capture execution time for metrics
1668 long startTime = System.currentTimeMillis ();
1670 if (rollback == null) {
1671 LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null");
1672 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform");
1676 MsoLogger.setLogContext (rollback.getMsoRequest());
1678 // Get the elements of the VnfRollback object for easier access
1679 String cloudSiteId = rollback.getCloudId ();
1680 String tenantId = rollback.getTenantId ();
1681 String networkId = rollback.getNetworkStackId ();
1682 String networkType = rollback.getNetworkType ();
1683 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1685 LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
1687 // rollback may be null (e.g. if network already existed when Create was called)
1688 // Get a handle to the Catalog Database
1690 // Make sure DB connection is always closed
1691 try (CatalogDatabase db = getCatalogDB()) {
1693 // Retrieve the Network Resource definition
1694 NetworkResource networkResource = null;
1695 if (isNullOrEmpty(modelCustomizationUuid)) {
1696 networkResource = db.getNetworkResource(networkType);
1698 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1701 if (networkResource != null) {
1703 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1705 mode = networkResource.getOrchestrationMode();
1708 if (rollback.getNetworkCreated()) {
1709 // Rolling back a newly created network, so delete it.
1710 if (NEUTRON_MODE.equals(mode)) {
1711 // Use MsoNeutronUtils for all NEUTRON commands
1712 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1713 long deleteNetworkStarttime = System.currentTimeMillis();
1715 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1716 // was not found. So don't bother to query first.
1717 neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1718 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1719 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1720 "DeleteNetwork", null);
1721 } catch (MsoException me) {
1722 me.addContext("RollbackNetwork");
1723 String error = "Rollback Network (neutron): " + networkId
1730 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1731 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1733 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1734 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)",
1736 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1737 MsoLogger.ResponseCode.CommunicationError, error);
1738 throw new NetworkException(me);
1740 } else { // DEFAULT to if ("HEAT".equals (mode))
1741 // Use MsoHeatUtils for all HEAT commands
1742 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1743 cloudConfigFactory);
1744 long deleteStackStarttime = System.currentTimeMillis();
1746 // The deleteStack function in MsoHeatUtils returns success if the stack
1747 // was not found. So don't bother to query first.
1748 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1749 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1750 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1751 "DeleteStack", null);
1752 } catch (MsoException me) {
1753 me.addContext("RollbackNetwork");
1754 String error = "Rollback Network (heat): " + networkId
1761 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1762 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1764 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1765 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me);
1766 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1767 MsoLogger.ResponseCode.CommunicationError, error);
1768 throw new NetworkException(me);
1773 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network");
1777 private String validateNetworkParams (NetworkType neutronNetworkType,
1779 String physicalNetwork,
1780 List <Integer> vlans,
1781 List <RouteTarget> routeTargets) {
1783 StringBuilder missing = new StringBuilder ();
1784 if (isNullOrEmpty(networkName)) {
1785 missing.append ("networkName");
1789 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1790 if (isNullOrEmpty(physicalNetwork)) {
1791 missing.append (sep).append ("physicalNetworkName");
1794 if (vlans == null || vlans.isEmpty ()) {
1795 missing.append (sep).append (VLANS);
1799 return missing.toString ();
1802 protected Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1804 String physicalNetwork,
1805 List <Integer> vlans,
1806 List <RouteTarget> routeTargets,
1809 boolean aic3template) {
1810 // Build the common set of HEAT template parameters
1811 Map <String, Object> stackParams = new HashMap <> ();
1812 stackParams.put ("network_name", networkName);
1814 if (neutronNetworkType == NetworkType.PROVIDER) {
1815 // For Provider type
1816 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1817 stackParams.put ("vlan", vlans.get (0).toString ());
1818 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1819 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1820 // It supports all ProviderNet properties except segmentation_id, and adds a
1821 // comma-separated-list of VLANs as a "segments" property.
1822 // Note that this does not match the Neutron definition of Multi-Provider network,
1823 // which contains a list of 'segments', each having physical_network, network_type,
1824 // and segmentation_id.
1825 StringBuilder buf = new StringBuilder ();
1827 for (Integer vlan : vlans) {
1828 buf.append (sep).append (vlan.toString ());
1831 String csl = buf.toString ();
1833 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1834 stackParams.put (VLANS, csl);
1837 if (routeTargets != null) {
1839 String rtGlobal = "";
1840 String rtImport = "";
1841 String rtExport = "";
1843 for (RouteTarget rt : routeTargets) {
1844 boolean rtIsNull = false;
1846 String routeTarget = rt.getRouteTarget();
1847 String routeTargetRole = rt.getRouteTargetRole();
1848 LOGGER.debug("Checking for an actually null route target: " + rt.toString());
1849 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1851 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1858 LOGGER.debug("Input RT:" + rt.toString());
1859 String role = rt.getRouteTargetRole();
1860 String rtValue = rt.getRouteTarget();
1862 if ("IMPORT".equalsIgnoreCase(role))
1864 sep = rtImport.isEmpty() ? "" : ",";
1865 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1867 else if ("EXPORT".equalsIgnoreCase(role))
1869 sep = rtExport.isEmpty() ? "" : ",";
1870 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1872 else // covers BOTH, empty etc
1874 sep = rtGlobal.isEmpty() ? "" : ",";
1875 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1880 if (!rtImport.isEmpty())
1882 stackParams.put ("route_targets_import", rtImport);
1884 if (!rtExport.isEmpty())
1886 stackParams.put ("route_targets_export", rtExport);
1888 if (!rtGlobal.isEmpty())
1890 stackParams.put ("route_targets", rtGlobal);
1893 if (isNullOrEmpty(shared)) {
1894 stackParams.put ("shared", "False");
1896 stackParams.put ("shared", shared);
1898 if (isNullOrEmpty(external)) {
1899 stackParams.put ("external", "False");
1901 stackParams.put ("external", external);
1908 /** policyRef_list structure in stackParams
1911 "network_policy_refs_data_sequence": {
1912 "network_policy_refs_data_sequence_major": "1",
1913 "network_policy_refs_data_sequence_minor": "0"
1917 "network_policy_refs_data_sequence": {
1918 "network_policy_refs_data_sequence_major": "2",
1919 "network_policy_refs_data_sequence_minor": "0"
1924 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1926 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1928 for (String pf : pFqdns) {
1929 if (!isNullOrEmpty(pf))
1931 ContrailPolicyRef pr = new ContrailPolicyRef();
1932 pr.populate(String.valueOf(index), "0");
1934 LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString());
1939 String jsonString = null;
1940 if (!prlist.isEmpty())
1944 ObjectMapper mapper = new ObjectMapper();
1945 jsonString = mapper.writeValueAsString(prlist);
1946 LOGGER.debug("Json PolicyRefs Data:" + jsonString);
1950 String error = "Error creating JsonNode for policyRefs Data";
1951 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e);
1952 throw new MsoAdapterException (error);
1956 if (pFqdns != null && !isNullOrEmpty(jsonString))
1958 StringBuilder buf = new StringBuilder ();
1960 for (String pf : pFqdns) {
1961 if (!isNullOrEmpty(pf))
1963 buf.append (sep).append (pf);
1967 String csl = buf.toString ();
1968 stackParams.put ("policy_refs", csl);
1969 stackParams.put ("policy_refsdata", jsonString);
1970 LOGGER.debug ("StackParams updated with policy refs:" + csl + " refs data:" + jsonString);
1975 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1978 if (rtFqdns != null)
1980 StringBuilder buf = new StringBuilder ();
1982 for (String rtf : rtFqdns) {
1983 if (!isNullOrEmpty(rtf))
1985 buf.append (sep).append (rtf);
1989 String csl = buf.toString ();
1990 stackParams.put ("route_table_refs", csl);
1993 LOGGER.debug ("StackParams updated with route_table refs");
1998 /*** Subnet Output structure from Juniper
2003 "ip_prefix": "10.100.1.0",
2006 "addr_from_start": null,
2007 "enable_dhcp": false,
2008 "default_gateway": "10.100.1.1",
2009 "dns_nameservers": [],
2010 "dhcp_option_list": null,
2011 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
2012 "allocation_pools": [
2014 "start": "10.100.1.3",
2018 "start": "10.100.1.6",
2022 "host_routes": null,
2023 "dns_server_address": "10.100.1.13",
2024 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
2028 "ip_prefix": "10.100.2.16",
2031 "addr_from_start": null,
2032 "enable_dhcp": true,
2033 "default_gateway": "10.100.2.17",
2034 "dns_nameservers": [],
2035 "dhcp_option_list": null,
2036 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
2037 "allocation_pools": [
2039 "start": "10.100.2.18",
2040 "end": "10.100.2.20"
2043 "host_routes": null,
2044 "dns_server_address": "10.100.2.29",
2045 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
2051 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
2054 List<ContrailSubnet> cslist = new ArrayList <> ();
2055 for (Subnet subnet : subnets) {
2056 ContrailSubnet cs = new ContrailSubnet();
2057 LOGGER.debug("Input Subnet:" + subnet.toString());
2058 cs.populateWith(subnet);
2059 LOGGER.debug("Contrail Subnet:" + cs.toString());
2063 String jsonString = null;
2064 if (!cslist.isEmpty())
2068 ObjectMapper mapper = new ObjectMapper();
2069 jsonString = mapper.writeValueAsString(cslist);
2070 LOGGER.debug("Json Subnet List:" + jsonString);
2074 String error = "Error creating JsonNode from input subnets";
2075 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e);
2076 throw new MsoAdapterException (error);
2080 if (!isNullOrEmpty(jsonString))
2082 stackParams.put ("subnet_list", jsonString);
2084 //Outputs - All subnets are in one ipam_subnets structure
2085 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
2086 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
2088 // append outputs in heatTemplate
2089 int outputsIdx = heatTemplate.indexOf ("outputs:");
2090 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
2091 LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate);
2092 return heatTemplate;
2096 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
2098 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
2101 + " network_id: { get_resource: network }\n"
2102 + " cidr: %cidr%\n";
2104 /* make these optional
2105 + " ip_version: %ipversion%\n"
2106 + " enable_dhcp: %enabledhcp%\n"
2107 + " gateway_ip: %gatewayip%\n"
2108 + " allocation_pools:\n"
2109 + " - start: %poolstart%\n"
2110 + " end: %poolend%\n";
2114 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
2115 + " value: {get_resource: subnet_%subnetId%}\n";
2119 StringBuilder resourcesBuf = new StringBuilder ();
2120 StringBuilder outputsBuf = new StringBuilder ();
2121 for (Subnet subnet : subnets) {
2123 // build template for each subnet
2124 curR = new StringBuilder(resourceTempl);
2125 if (subnet.getSubnetId () != null) {
2126 curR = new StringBuilder(curR.toString().replace("%subnetId%", subnet.getSubnetId()));
2128 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
2129 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID for subnet in HEAT Template");
2130 throw new MsoAdapterException (error);
2133 if (subnet.getSubnetName () != null) {
2134 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetName()));
2136 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetId()));
2139 if (subnet.getCidr () != null) {
2140 curR = new StringBuilder(curR.toString().replace("%cidr%", subnet.getCidr()));
2142 String error = "Missing Required cidr for subnet in HEAT Template";
2143 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template");
2144 throw new MsoAdapterException (error);
2147 if (subnet.getIpVersion () != null) {
2148 curR.append(" ip_version: " + subnet.getIpVersion() + "\n");
2150 if (subnet.getEnableDHCP () != null) {
2151 curR.append(" enable_dhcp: ").append(Boolean.toString(subnet.getEnableDHCP())).append("\n");
2153 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
2154 curR.append(" gateway_ip: " + subnet.getGatewayIp() + "\n");
2157 if (subnet.getAllocationPools() != null) {
2158 curR.append(" allocation_pools:\n");
2159 for (Pool pool : subnet.getAllocationPools())
2161 if (!isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()))
2163 curR.append(" - start: " + pool.getStart() + "\n");
2164 curR.append(" end: " + pool.getEnd() + "\n");
2169 resourcesBuf.append (curR);
2172 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
2174 outputsBuf.append (curO);
2177 // append resources and outputs in heatTemplate
2178 LOGGER.debug ("Tempate initial:" + heatTemplate);
2179 int outputsIdx = heatTemplate.indexOf ("outputs:");
2180 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
2181 int resourcesIdx = heatTemplate.indexOf ("resources:");
2182 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
2184 LOGGER.debug ("Template updated with all subnets:" + heatTemplate);
2185 return heatTemplate;
2188 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
2190 Map <String, String> sMap = new HashMap <> ();
2193 Object obj = outputs.get(key);
2194 ObjectMapper mapper = new ObjectMapper();
2195 String jStr = mapper.writeValueAsString(obj);
2196 LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr);
2198 JsonNode rootNode = mapper.readTree(jStr);
2199 for (JsonNode sNode : rootNode.path("ipam_subnets"))
2201 LOGGER.debug("Output Subnet Node" + sNode.toString());
2202 String name = sNode.path("subnet_name").textValue();
2203 String uuid = sNode.path("subnet_uuid").textValue();
2204 String aaiId = name; // default
2205 // try to find aaiId for name in input subnetList
2206 if (subnets != null)
2208 for (Subnet subnet : subnets)
2210 if ( subnet != null && !isNullOrEmpty(subnet.getSubnetName()))
2212 if (subnet.getSubnetName().equals(name))
2214 aaiId = subnet.getSubnetId();
2220 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
2225 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e);
2228 LOGGER.debug ("Return sMap" + sMap.toString());
2232 private static String insertStr (String template, String snippet, int index) {
2234 String updatedTemplate;
2236 LOGGER.debug ("Index:" + index + " Snippet:" + snippet);
2238 String templateBeg = template.substring (0, index);
2239 String templateEnd = template.substring (index);
2241 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
2243 LOGGER.debug ("Template updated with a subnet:" + updatedTemplate);
2244 return updatedTemplate;