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 ();
96 * Health Check web method. Does nothing but return to show the adapter is deployed.
99 public void healthCheck () {
100 LOGGER.debug ("Health check call in Network Adapter");
104 * Do not use this constructor or the msoPropertiesFactory will be NULL.
106 * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
108 public MsoNetworkAdapterImpl() {
112 * This constructor MUST be used if this class if called with the new operator.
113 * @param msoPropFactory
116 public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) {
117 this.msoPropertiesFactory = msoPropFactory;
118 this.cloudConfigFactory=cloudConfigFact;
119 neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
120 heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory, cloudConfigFactory);
121 heatWithUpdate = new MsoHeatUtilsWithUpdate(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
126 public void createNetwork (String cloudSiteId,
129 String modelCustomizationUuid,
131 String physicalNetworkName,
132 List <Integer> vlans,
133 Boolean failIfExists,
135 List <Subnet> subnets,
136 MsoRequest msoRequest,
137 Holder <String> networkId,
138 Holder <String> neutronNetworkId,
139 Holder <Map <String, String>> subnetIdMap,
140 Holder <NetworkRollback> rollback) throws NetworkException {
141 Holder <String> networkFqdn = new Holder <> ();
142 createNetwork (cloudSiteId,
145 modelCustomizationUuid,
166 public void createNetworkContrail (String cloudSiteId,
169 String modelCustomizationUuid,
171 List <RouteTarget> routeTargets,
174 Boolean failIfExists,
176 List <Subnet> subnets,
177 List <String> policyFqdns,
178 List<String> routeTableFqdns,
179 MsoRequest msoRequest,
180 Holder <String> networkId,
181 Holder <String> neutronNetworkId,
182 Holder <String> networkFqdn,
183 Holder <Map <String, String>> subnetIdMap,
184 Holder <NetworkRollback> rollback) throws NetworkException {
185 createNetwork (cloudSiteId,
188 modelCustomizationUuid,
209 * This is the "Create Network" web service implementation.
210 * It will create a new Network of the requested type in the specified cloud
211 * and tenant. The tenant must exist at the time this service is called.
213 * If a network with the same name already exists, this can be considered a
214 * success or failure, depending on the value of the 'failIfExists' parameter.
216 * There will be a pre-defined set of network types defined in the MSO Catalog.
217 * All such networks will have a similar configuration, based on the allowable
218 * Openstack networking definitions. This includes basic networks, provider
219 * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
221 * Initially, all provider networks must be "vlan" type, and multiple segments in
222 * a multi-provider network must be multiple VLANs on the same physical network.
224 * This service supports two modes of Network creation/update:
225 * - via Heat Templates
227 * The network orchestration mode for each network type is declared in its
228 * catalog definition. All Heat-based templates must support some subset of
229 * the same input parameters: network_name, physical_network, vlan(s).
231 * The method returns the network ID and a NetworkRollback object. This latter
232 * object can be passed as-is to the rollbackNetwork operation to undo everything
233 * that was created. This is useful if a network is successfully created but
234 * the orchestration fails on a subsequent operation.
237 protected void createNetwork (String cloudSiteId,
240 String modelCustomizationUuid,
242 String physicalNetworkName,
243 List <Integer> vlans,
244 List <RouteTarget> routeTargets,
247 Boolean failIfExists,
249 List <Subnet> subnets,
250 List <String> policyFqdns,
251 List <String> routeTableFqdns,
252 MsoRequest msoRequest,
253 Holder <String> networkId,
254 Holder <String> neutronNetworkId,
255 Holder <String> networkFqdn,
256 Holder <Map <String, String>> subnetIdMap,
257 Holder <NetworkRollback> rollback) throws NetworkException {
258 MsoLogger.setLogContext (msoRequest);
259 MsoLogger.setServiceName ("CreateNetwork");
261 LOGGER.debug ("*** CREATE Network: " + networkName
269 // Will capture execution time for metrics
270 long startTime = System.currentTimeMillis ();
272 // Build a default rollback object (no actions performed)
273 NetworkRollback networkRollback = new NetworkRollback ();
274 networkRollback.setCloudId (cloudSiteId);
275 networkRollback.setTenantId (tenantId);
276 networkRollback.setMsoRequest (msoRequest);
277 networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
279 // tenant query is not required here.
280 // If the tenant doesn’t exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
281 // So this is just catching that error in a bit more obvious way up front.
283 CloudConfig cloudConfig = getCloudConfigFactory().getCloudConfig ();
284 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
285 if (!cloudSiteOpt.isPresent())
287 String error = "Configuration Error. Stack " + networkName + " in "
292 + " CloudSite does not exist in MSO Configuration";
293 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
294 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
295 // Set the detailed error as the Exception 'message'
296 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
299 // Get a handle to the Catalog Database
301 // Make sure DB connection is always closed
302 try (CatalogDatabase db = getCatalogDB()) {
303 NetworkResource networkResource = networkCheck(db,
306 modelCustomizationUuid,
312 String mode = networkResource.getOrchestrationMode();
313 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
315 if (NEUTRON_MODE.equals(mode)) {
317 // See if the Network already exists (by name)
318 NetworkInfo netInfo = null;
319 long queryNetworkStarttime = System.currentTimeMillis();
321 netInfo = neutron.queryNetwork(networkName, tenantId, cloudSiteId);
322 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
323 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
324 "QueryNetwork", null);
325 } catch (MsoException me) {
326 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
327 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack",
328 "OpenStack", "QueryNetwork", null);
329 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
330 MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack",
332 me.addContext(CREATE_NETWORK_CONTEXT);
333 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
334 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack");
335 throw new NetworkException(me);
338 if (netInfo != null) {
339 // Exists. If that's OK, return success with the network ID.
340 // Otherwise, return an exception.
341 if (failIfExists != null && failIfExists) {
342 String error = "Create Nework: Network " + networkName
343 + " already exists in "
347 + " with ID " + netInfo.getId();
348 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId,
349 "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
350 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
352 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
354 // Populate the outputs from the existing network.
355 networkId.value = netInfo.getId();
356 neutronNetworkId.value = netInfo.getId();
357 rollback.value = networkRollback; // Default rollback - no updates performed
358 String msg = "Found Existing network, status=" + netInfo.getStatus() + " for Neutron mode";
359 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
360 MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus());
361 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
367 long createNetworkStarttime = System.currentTimeMillis();
369 netInfo = neutron.createNetwork(cloudSiteId,
375 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
376 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
377 "CreateNetwork", null);
378 } catch (MsoException me) {
379 me.addContext(CREATE_NETWORK_CONTEXT);
380 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.ERROR,
381 MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack",
382 "OpenStack", "CreateNetwork", null);
383 String error = "Create Network: type " + neutronNetworkType
390 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
391 MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me);
392 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
393 MsoLogger.ResponseCode.CommunicationError, error);
395 throw new NetworkException(me);
398 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
400 // If reach this point, network creation is successful.
401 // Since directly created via Neutron, networkId tracked by MSO is the same
402 // as the neutron network ID.
403 networkId.value = netInfo.getId();
404 neutronNetworkId.value = netInfo.getId();
406 networkRollback.setNetworkCreated(true);
407 networkRollback.setNetworkId(netInfo.getId());
408 networkRollback.setNeutronNetworkId(netInfo.getId());
409 networkRollback.setNetworkType(networkType);
411 LOGGER.debug("Network " + networkName + " created, id = " + netInfo.getId());
412 } else if ("HEAT".equals(mode)) {
414 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
415 HeatTemplate heatTemplate = db
416 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
417 if (heatTemplate == null) {
418 String error = "Network error - undefined Heat Template. Network Type = " + networkType;
419 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
420 "Openstack", "", MsoLogger.ErrorCode.DataError,
421 "Network error - undefined Heat Template. Network Type = " + networkType);
422 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
426 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
428 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
431 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
433 // "Fix" the template if it has CR/LF (getting this from Oracle)
434 String template = heatTemplate.getHeatTemplate();
435 template = template.replaceAll("\r\n", "\n");
437 boolean aic3template = false;
438 String aic3nw = AIC3_NW;
440 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
441 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
442 } catch (MsoPropertiesException e) {
443 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
444 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError,
445 "Exception - Unable to get properties", e);
448 if (template.contains(aic3nw))
451 // First, look up to see if the Network already exists (by name).
452 // For HEAT orchestration of networks, the stack name will always match the network name
453 StackInfo heatStack = null;
454 long queryNetworkStarttime = System.currentTimeMillis();
456 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
457 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
458 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
459 "QueryNetwork", null);
460 } catch (MsoException me) {
461 me.addContext(CREATE_NETWORK_CONTEXT);
462 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
463 MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack",
464 "OpenStack", "QueryNetwork", null);
465 String error = "Create Network (heat): query network " + networkName
472 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
473 MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me);
474 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
475 MsoLogger.ResponseCode.CommunicationError, error);
476 throw new NetworkException(me);
479 if (heatStack != null && (heatStack.getStatus() != HeatStatus.NOTFOUND)) {
480 // Stack exists. Return success or error depending on input directive
481 if (failIfExists != null && failIfExists) {
482 String error = "CreateNetwork: Stack " + networkName
483 + " already exists in "
487 + " as " + heatStack.getCanonicalName();
488 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
489 MsoLogger.ErrorCode.DataError, "Network already exists");
490 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
492 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
494 // Populate the outputs from the existing stack.
495 networkId.value = heatStack.getCanonicalName();
496 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
497 rollback.value = networkRollback; // Default rollback - no updates performed
499 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
501 Map<String, Object> outputs = heatStack.getOutputs();
502 Map<String, String> sMap = new HashMap<>();
503 if (outputs != null) {
504 for (String key : outputs.keySet()) {
505 if (key != null && key.startsWith("subnet")) {
506 if (aic3template) //one subnet_id output
508 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
510 } else //multiples subnet_%aaid% outputs
512 String subnetUUId = (String) outputs.get(key);
513 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
518 subnetIdMap.value = sMap;
519 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
520 MsoLogger.ErrorCode.DataError,
521 "Found Existing network stack, status=" + heatStack.getStatus());
522 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc,
523 "Found Existing network stack");
528 // Ready to deploy the new Network
529 // Build the common set of HEAT template parameters
530 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
539 // Validate (and update) the input parameters against the DB definition
540 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
541 // and inputs were already validated.
543 stackParams = heat.validateStackParams(stackParams, heatTemplate);
544 } catch (IllegalArgumentException e) {
545 String error = "Create Network: Configuration Error: " + e.getMessage();
546 LOGGER.error(MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "",
547 MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e);
548 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
552 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError,
554 // Input parameters were not valid
555 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
558 if (subnets != null) {
561 template = mergeSubnetsAIC3(template, subnets, stackParams);
563 template = mergeSubnets(template, subnets);
565 } catch (MsoException me) {
566 me.addContext(CREATE_NETWORK_CONTEXT);
567 String error = "Create Network (heat): type " + neutronNetworkType
574 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
575 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
576 "Exception Create Network, merging subnets", me);
577 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
578 MsoLogger.ResponseCode.InternalError, error);
579 throw new NetworkException(me);
583 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
585 mergePolicyRefs(policyFqdns, stackParams);
586 } catch (MsoException me) {
587 me.addContext(CREATE_NETWORK_CONTEXT);
588 String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType
595 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
596 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
597 "Exception Create Network, merging policyRefs", me);
598 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
599 MsoLogger.ResponseCode.InternalError, error);
600 throw new NetworkException(me);
604 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
606 mergeRouteTableRefs(routeTableFqdns, stackParams);
607 } catch (MsoException me) {
608 me.addContext(CREATE_NETWORK_CONTEXT);
609 String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType
616 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
617 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
618 "Exception Create Network, merging routeTableRefs", me);
619 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
620 MsoLogger.ResponseCode.InternalError, error);
621 throw new NetworkException(me);
625 // Deploy the network stack
626 // Ignore MsoStackAlreadyExists exception because we already checked.
630 heatStack = heat.createStack(cloudSiteId,
636 heatTemplate.getTimeoutMinutes(),
640 backout.booleanValue());
641 } catch (MsoException me) {
642 me.addContext(CREATE_NETWORK_CONTEXT);
643 String error = "Create Network (heat): type " + neutronNetworkType
650 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "",
651 MsoLogger.ErrorCode.DataError, "Exception creating network", me);
652 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
653 MsoLogger.ResponseCode.CommunicationError, error);
654 throw new NetworkException(me);
657 // Reach this point if createStack is successful.
659 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
660 // and the neutronNetworkId is the network UUID returned in stack outputs.
661 networkId.value = heatStack.getCanonicalName();
662 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
664 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
666 Map<String, Object> outputs = heatStack.getOutputs();
667 Map<String, String> sMap = new HashMap<>();
668 if (outputs != null) {
669 for (String key : outputs.keySet()) {
670 if (key != null && key.startsWith("subnet")) {
671 if (aic3template) //one subnet output expected
673 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
675 } else //multiples subnet_%aaid% outputs allowed
677 String subnetUUId = (String) outputs.get(key);
678 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
683 subnetIdMap.value = sMap;
685 rollback.value = networkRollback;
686 // Populate remaining rollback info and response parameters.
687 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
688 networkRollback.setNeutronNetworkId((String) heatStack.getOutputs().get(NETWORK_ID));
689 networkRollback.setNetworkCreated(true);
690 networkRollback.setNetworkType(networkType);
692 LOGGER.debug("Network " + networkName + " successfully created via HEAT");
695 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network");
700 public void updateNetwork (String cloudSiteId,
703 String modelCustomizationUuid,
706 String physicalNetworkName,
707 List <Integer> vlans,
708 List <Subnet> subnets,
709 MsoRequest msoRequest,
710 Holder <Map <String, String>> subnetIdMap,
711 Holder <NetworkRollback> rollback) throws NetworkException {
712 updateNetwork (cloudSiteId,
715 modelCustomizationUuid,
733 public void updateNetworkContrail (String cloudSiteId,
736 String modelCustomizationUuid,
739 List <RouteTarget> routeTargets,
742 List <Subnet> subnets,
743 List <String> policyFqdns,
744 List<String> routeTableFqdns,
745 MsoRequest msoRequest,
746 Holder <Map <String, String>> subnetIdMap,
747 Holder <NetworkRollback> rollback) throws NetworkException {
748 updateNetwork (cloudSiteId,
751 modelCustomizationUuid,
768 * This is the "Update Network" web service implementation.
769 * It will update an existing Network of the requested type in the specified cloud
770 * and tenant. The typical use will be to replace the VLANs with the supplied
771 * list (to add or remove a VLAN), but other properties may be updated as well.
773 * There will be a pre-defined set of network types defined in the MSO Catalog.
774 * All such networks will have a similar configuration, based on the allowable
775 * Openstack networking definitions. This includes basic networks, provider
776 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
778 * Initially, all provider networks must currently be "vlan" type, and multi-provider
779 * networks must be multiple VLANs on the same physical network.
781 * This service supports two modes of Network update:
782 * - via Heat Templates
784 * The network orchestration mode for each network type is declared in its
785 * catalog definition. All Heat-based templates must support some subset of
786 * the same input parameters: network_name, physical_network, vlan, segments.
788 * The method returns a NetworkRollback object. This object can be passed
789 * as-is to the rollbackNetwork operation to undo everything that was updated.
790 * This is useful if a network is successfully updated but orchestration
791 * fails on a subsequent operation.
793 private void updateNetwork (String cloudSiteId,
796 String modelCustomizationUuid,
799 String physicalNetworkName,
800 List <Integer> vlans,
801 List <RouteTarget> routeTargets,
804 List <Subnet> subnets,
805 List <String> policyFqdns,
806 List<String> routeTableFqdns,
807 MsoRequest msoRequest,
808 Holder <Map <String, String>> subnetIdMap,
809 Holder <NetworkRollback> rollback) throws NetworkException {
810 MsoLogger.setLogContext (msoRequest);
811 MsoLogger.setServiceName ("UpdateNetwork");
812 LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName
821 // Will capture execution time for metrics
822 long startTime = System.currentTimeMillis ();
824 // Build a default rollback object (no actions performed)
825 NetworkRollback networkRollback = new NetworkRollback ();
826 networkRollback.setCloudId (cloudSiteId);
827 networkRollback.setTenantId (tenantId);
828 networkRollback.setMsoRequest (msoRequest);
830 CloudConfig cloudConfig = getCloudConfigFactory().getCloudConfig ();
831 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
832 if (!cloudSiteOpt.isPresent()) {
833 String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in "
838 + " CloudSite does not exist in MSO Configuration";
839 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration");
840 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
841 // Set the detailed error as the Exception 'message'
842 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
845 // Get a handle to the Catalog Database
847 // Make sure DB connection is always closed
848 try (CatalogDatabase db = getCatalogDB()) {
849 NetworkResource networkResource = networkCheck(db,
852 modelCustomizationUuid,
858 String mode = networkResource.getOrchestrationMode();
859 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
861 if (NEUTRON_MODE.equals(mode)) {
863 // Verify that the Network exists
864 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
865 NetworkInfo netInfo = null;
866 long queryNetworkStarttime = System.currentTimeMillis();
868 netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
869 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
870 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
871 "QueryNetwork", null);
872 } catch (MsoException me) {
873 me.addContext(UPDATE_NETWORK_CONTEXT);
874 String error = "Update Network (neutron): query " + networkId
881 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
882 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
883 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
884 "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me);
885 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
886 MsoLogger.ResponseCode.CommunicationError, error);
887 throw new NetworkException(me);
890 if (netInfo == null) {
891 String error = "Update Nework: Network " + networkId
892 + " does not exist in "
896 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "",
897 MsoLogger.ErrorCode.BusinessProcesssError, "Network not found");
898 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
900 // Does not exist. Throw an exception (can't update a non-existent network)
901 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
903 long updateNetworkStarttime = System.currentTimeMillis();
905 netInfo = neutron.updateNetwork(cloudSiteId,
911 LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
912 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
913 "UpdateNetwork", null);
914 } catch (MsoException me) {
915 me.addContext(UPDATE_NETWORK_CONTEXT);
916 String error = "Update Network (neutron): " + networkId
923 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack",
924 "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me);
925 LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.ERROR,
926 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null);
927 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
928 MsoLogger.ResponseCode.CommunicationError, error);
929 throw new NetworkException(me);
932 // Add the network ID and previously queried vlans to the rollback object
933 networkRollback.setNetworkId(netInfo.getId());
934 networkRollback.setNeutronNetworkId(netInfo.getId());
935 networkRollback.setNetworkType(networkType);
936 // Save previous parameters
937 networkRollback.setNetworkName(netInfo.getName());
938 networkRollback.setPhysicalNetwork(netInfo.getProvider());
939 networkRollback.setVlans(netInfo.getVlans());
941 LOGGER.debug("Network " + networkId + " updated, id = " + netInfo.getId());
942 } else if ("HEAT".equals(mode)) {
944 // First, look up to see that the Network already exists.
945 // For Heat-based orchestration, the networkId is the network Stack ID.
946 StackInfo heatStack = null;
947 long queryStackStarttime = System.currentTimeMillis();
949 heatStack = heatWithUpdate.queryStack(cloudSiteId, tenantId, networkName);
950 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE,
951 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
953 } catch (MsoException me) {
954 me.addContext(UPDATE_NETWORK_CONTEXT);
955 String error = "UpdateNetwork (heat): query " + networkName
962 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR,
963 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
964 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
965 "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
966 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
967 MsoLogger.ResponseCode.CommunicationError, error);
968 throw new NetworkException(me);
971 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
972 String error = "UpdateNetwork: Stack " + networkName
973 + " does not exist in "
977 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack",
978 "queryStack", MsoLogger.ErrorCode.DataError, "Network not found");
979 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
981 // Network stack does not exist. Return an error
982 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
985 // Get the previous parameters for rollback
986 Map<String, Object> heatParams = heatStack.getParameters();
988 String previousNetworkName = (String) heatParams.get("network_name");
989 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
991 List<Integer> previousVlans = new ArrayList<>();
992 String vlansParam = (String) heatParams.get(VLANS);
993 if (vlansParam != null) {
994 for (String vlan : vlansParam.split(",")) {
996 previousVlans.add(Integer.parseInt(vlan));
997 } catch (NumberFormatException e) {
998 LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", "",
999 MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e);
1003 LOGGER.debug("Update Stack: Previous VLANS: " + previousVlans);
1005 // Ready to deploy the updated Network via Heat
1007 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
1008 HeatTemplate heatTemplate = db
1009 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
1010 if (heatTemplate == null) {
1011 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
1012 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
1013 "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError,
1014 "Network error - undefined Heat Template. Network Type=" + networkType);
1015 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1016 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1018 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1021 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1023 // "Fix" the template if it has CR/LF (getting this from Oracle)
1024 String template = heatTemplate.getHeatTemplate();
1025 template = template.replaceAll("\r\n", "\n");
1027 boolean aic3template = false;
1028 String aic3nw = AIC3_NW;
1030 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
1031 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
1032 } catch (MsoPropertiesException e) {
1033 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
1034 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1035 "Exception - Unable to get properties", e);
1037 if (template.contains(aic3nw))
1038 aic3template = true;
1040 // Build the common set of HEAT template parameters
1041 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
1043 physicalNetworkName,
1050 // Validate (and update) the input parameters against the DB definition
1051 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
1053 stackParams = heatWithUpdate.validateStackParams(stackParams, heatTemplate);
1054 } catch (IllegalArgumentException e) {
1055 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
1056 LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "",
1057 MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error");
1058 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1059 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError,
1061 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
1064 if (subnets != null) {
1067 template = mergeSubnetsAIC3(template, subnets, stackParams);
1069 template = mergeSubnets(template, subnets);
1071 } catch (MsoException me) {
1072 me.addContext(UPDATE_NETWORK_CONTEXT);
1073 String error = "Update Network (heat): type " + neutronNetworkType
1080 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1081 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1082 "Exception - UpdateNetwork mergeSubnets ", me);
1083 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1084 MsoLogger.ResponseCode.InternalError, error);
1085 throw new NetworkException(me);
1089 if (policyFqdns != null && aic3template) {
1091 mergePolicyRefs(policyFqdns, stackParams);
1092 } catch (MsoException me) {
1093 me.addContext(UPDATE_NETWORK_CONTEXT);
1094 String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType
1101 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1102 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1103 "Exception - UpdateNetwork mergePolicyRefs", me);
1104 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1105 MsoLogger.ResponseCode.InternalError, error);
1106 throw new NetworkException(me);
1110 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
1112 mergeRouteTableRefs(routeTableFqdns, stackParams);
1113 } catch (MsoException me) {
1114 me.addContext(UPDATE_NETWORK_CONTEXT);
1115 String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType
1122 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1123 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
1124 "Exception - UpdateNetwork mergeRouteTableRefs", me);
1125 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1126 MsoLogger.ResponseCode.InternalError, error);
1127 throw new NetworkException(me);
1131 // Update the network stack
1132 // Ignore MsoStackNotFound exception because we already checked.
1133 long updateStackStarttime = System.currentTimeMillis();
1135 heatStack = heatWithUpdate.updateStack(cloudSiteId,
1141 heatTemplate.getTimeoutMinutes());
1142 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1143 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1144 "UpdateStack", null);
1145 } catch (MsoException me) {
1146 me.addContext(UPDATE_NETWORK_CONTEXT);
1147 String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1148 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1149 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
1150 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "",
1151 MsoLogger.ErrorCode.DataError, "Exception - update network", me);
1152 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1153 MsoLogger.ResponseCode.CommunicationError, error);
1154 throw new NetworkException(me);
1157 Map<String, Object> outputs = heatStack.getOutputs();
1158 Map<String, String> sMap = new HashMap<>();
1159 if (outputs != null) {
1160 for (String key : outputs.keySet()) {
1161 if (key != null && key.startsWith("subnet")) {
1162 if (aic3template) //one subnet output expected
1164 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
1166 } else //multiples subnet_%aaid% outputs allowed
1168 String subnetUUId = (String) outputs.get(key);
1169 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
1174 subnetIdMap.value = sMap;
1176 // Reach this point if createStack is successful.
1177 // Populate remaining rollback info and response parameters.
1178 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
1179 if (null != outputs) {
1180 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
1182 LOGGER.debug("outputs is NULL");
1184 networkRollback.setNetworkType(networkType);
1185 // Save previous parameters
1186 networkRollback.setNetworkName(previousNetworkName);
1187 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
1188 networkRollback.setVlans(previousVlans);
1190 rollback.value = networkRollback;
1192 LOGGER.debug("Network " + networkId + " successfully updated via HEAT");
1195 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network");
1199 protected NetworkResource networkCheck (CatalogDatabase db,
1202 String modelCustomizationUuid,
1204 String physicalNetworkName,
1205 List <Integer> vlans,
1206 List <RouteTarget> routeTargets,
1207 CloudSite cloudSite) throws NetworkException {
1208 // Retrieve the Network Resource definition
1209 NetworkResource networkResource = null;
1211 if (isNullOrEmpty(modelCustomizationUuid)) {
1212 networkResource = db.getNetworkResource(networkType);
1214 networkResource = db
1215 .getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1217 if (networkResource == null) {
1218 String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:"
1220 + " or ModelCustomizationUUID:"
1221 + modelCustomizationUuid;
1222 LOGGER.error(MessageEnum.RA_UNKOWN_PARAM,
1223 "NetworkType/ModelCustomizationUUID", networkType + "/"
1224 + modelCustomizationUuid, "OpenStack", "",
1225 MsoLogger.ErrorCode.DataError,
1226 "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID");
1228 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1230 LOGGER.debug("Got Network definition from Catalog: "
1231 + networkResource.toString());
1233 String mode = networkResource.getOrchestrationMode();
1234 NetworkType neutronNetworkType = NetworkType
1235 .valueOf(networkResource.getNeutronNetworkType());
1237 // All Networks are orchestrated via HEAT or Neutron
1238 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1239 String error = "CreateNetwork: Configuration Error: Network Type = "
1241 LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1242 mode, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1243 "CreateNetwork: Configuration Error");
1244 // Alarm on this error, configuration must be fixed
1245 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1246 MsoAlarmLogger.CRITICAL, error);
1248 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1251 MavenLikeVersioning aicV = new MavenLikeVersioning();
1252 aicV.setVersion(cloudSite.getAic_version());
1253 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1254 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1257 && (aicV.isTheSameVersion(networkResource
1258 .getAicVersionMax()) || !(aicV
1259 .isMoreRecentThan(networkResource
1260 .getAicVersionMax())))) // aic <= max
1262 LOGGER.debug("Network Type:" + networkType + " VersionMin:"
1263 + networkResource.getAicVersionMin() + " VersionMax:"
1264 + networkResource.getAicVersionMax()
1265 + " supported on Cloud:" + cloudSite.getId()
1266 + " with AIC_Version:" + cloudSite.getAic_version());
1268 String error = "Network Type:" + networkType + " Version_Min:"
1269 + networkResource.getAicVersionMin() + " Version_Max:"
1270 + networkResource.getAicVersionMax()
1271 + " not supported on Cloud:" + cloudSite.getId()
1272 + " with AIC_Version:" + cloudSite.getAic_version();
1273 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1274 MsoLogger.ErrorCode.DataError,
1275 "Network Type not supported on Cloud");
1276 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1277 MsoLogger.ResponseCode.DataError, error);
1278 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1281 // Validate the Network parameters.
1282 String missing = validateNetworkParams(neutronNetworkType,
1283 networkName, physicalNetworkName, vlans, routeTargets);
1284 if (!missing.isEmpty()) {
1285 String error = "Create Network: Missing parameters: " + missing;
1286 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing,
1287 "OpenStack", "", MsoLogger.ErrorCode.DataError,
1288 "Create Network: Missing parameters");
1290 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1295 return networkResource;
1299 public void queryNetwork (String cloudSiteId,
1301 String networkNameOrId,
1302 MsoRequest msoRequest,
1303 Holder <Boolean> networkExists,
1304 Holder <String> networkId,
1305 Holder <String> neutronNetworkId,
1306 Holder <NetworkStatus> status,
1307 Holder <List <Integer>> vlans,
1308 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1309 queryNetworkInfo(cloudSiteId,
1323 public void queryNetworkContrail (String cloudSiteId,
1325 String networkNameOrId,
1326 MsoRequest msoRequest,
1327 Holder <Boolean> networkExists,
1328 Holder <String> networkId,
1329 Holder <String> neutronNetworkId,
1330 Holder <NetworkStatus> status,
1331 Holder <List <RouteTarget>> routeTargets,
1332 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1333 queryNetworkInfo(cloudSiteId,
1347 * This is the queryNetworkInfo method. It returns the existence and status of
1348 * the specified network, along with its Neutron UUID and list of VLANs.
1349 * This method attempts to find the network using both Heat and Neutron.
1350 * Heat stacks are first searched based on the provided network name/id.
1351 * If none is found, the Neutron is directly queried.
1353 private void queryNetworkInfo(String cloudSiteId,
1355 String networkNameOrId,
1356 MsoRequest msoRequest,
1357 Holder <Boolean> networkExists,
1358 Holder <String> networkId,
1359 Holder <String> neutronNetworkId,
1360 Holder <NetworkStatus> status,
1361 Holder <List <Integer>> vlans,
1362 Holder <List <RouteTarget>> routeTargets,
1363 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1364 MsoLogger.setLogContext (msoRequest);
1365 MsoLogger.setServiceName ("QueryNetwork");
1366 LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId
1372 // Will capture execution time for metrics
1373 long startTime = System.currentTimeMillis ();
1375 if (isNullOrEmpty (cloudSiteId)
1376 || isNullOrEmpty(tenantId)
1377 || isNullOrEmpty(networkNameOrId)) {
1379 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1380 LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1381 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1382 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1385 CloudConfig cloudConfig = getCloudConfigFactory().getCloudConfig();
1386 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1387 if (!cloudSiteOpt.isPresent())
1389 String error = "Configuration Error. Stack " + networkNameOrId + " in "
1394 + " CloudSite does not exist in MSO Configuration";
1395 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
1396 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1397 // Set the detailed error as the Exception 'message'
1398 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1403 // Try Heat first, since networks may be named the same as the Heat stack
1404 StackInfo heatStack = null;
1405 long queryStackStarttime = System.currentTimeMillis ();
1407 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1408 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
1409 } catch (MsoException me) {
1410 me.addContext ("QueryNetwork");
1411 String error = "Query Network (heat): " + networkNameOrId
1418 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null);
1419 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me);
1420 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1421 throw new NetworkException (me);
1424 // Populate the outputs based on the returned Stack information
1425 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1426 // Found it. Get the neutronNetworkId for further query
1427 Map <String, Object> outputs = heatStack.getOutputs ();
1428 neutronId = (String) outputs.get (NETWORK_ID);
1431 Map <String, String> sMap = new HashMap <> ();
1432 if (outputs != null) {
1433 for (String key : outputs.keySet ()) {
1434 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1436 String subnetUUId = (String) outputs.get(key);
1437 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1439 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1441 Map <String, String> map = getSubnetUUId(key, outputs, null);
1447 subnetIdMap.value = sMap;
1449 // Input ID was not a Heat stack ID. Try it directly in Neutron
1450 neutronId = networkNameOrId;
1451 mode = NEUTRON_MODE;
1454 // Query directly against the Neutron Network for the details
1455 // no RouteTargets available for ContrailV2 in neutron net-show
1456 // networkId is heatStackId
1457 long queryNetworkStarttime = System.currentTimeMillis ();
1459 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1460 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
1461 if (netInfo != null) {
1462 // Found. Populate the output elements
1463 networkExists.value = Boolean.TRUE;
1464 if ("HEAT".equals (mode)) {
1465 networkId.value = heatStack.getCanonicalName ();
1467 networkId.value = netInfo.getId ();
1469 neutronNetworkId.value = netInfo.getId ();
1470 status.value = netInfo.getStatus ();
1472 vlans.value = netInfo.getVlans ();
1474 LOGGER.debug ("Network " + networkNameOrId
1479 + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1481 // Not found. Populate the status fields, leave the rest null
1482 networkExists.value = Boolean.FALSE;
1483 status.value = NetworkStatus.NOTFOUND;
1484 neutronNetworkId.value = null;
1486 vlans.value = new ArrayList<>();
1488 LOGGER.debug ("Network " + networkNameOrId + " not found");
1490 } catch (MsoException me) {
1491 me.addContext ("QueryNetwork");
1492 String error = "Query Network (neutron): " + networkNameOrId
1499 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
1500 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me);
1501 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1502 throw new NetworkException (me);
1504 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network");
1509 * This is the "Delete Network" web service implementation.
1510 * It will delete a Network in the specified cloud and tenant.
1512 * If the network is not found, it is treated as a success.
1514 * This service supports two modes of Network creation/update/delete:
1515 * - via Heat Templates
1517 * The network orchestration mode for each network type is declared in its
1518 * catalog definition.
1520 * For Heat-based orchestration, the networkId should be the stack ID.
1521 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1523 * The method returns nothing on success. Rollback is not possible for delete
1524 * commands, so any failure on delete will require manual fallout in the client.
1527 public void deleteNetwork (String cloudSiteId,
1530 String modelCustomizationUuid,
1532 MsoRequest msoRequest,
1533 Holder <Boolean> networkDeleted) throws NetworkException {
1534 MsoLogger.setLogContext (msoRequest);
1535 MsoLogger.setServiceName ("DeleteNetwork");
1536 LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId
1542 // Will capture execution time for metrics
1543 long startTime = System.currentTimeMillis ();
1545 // Get a handle to the Catalog Database
1547 // Make sure DB connection is always closed
1548 try (CatalogDatabase db = getCatalogDB()) {
1549 if (isNullOrEmpty(cloudSiteId)
1550 || isNullOrEmpty(tenantId)
1551 || isNullOrEmpty(networkId)) {
1552 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1553 LOGGER.error(MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "",
1554 MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1556 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1557 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1560 // Retrieve the Network Resource definition
1561 NetworkResource networkResource = null;
1562 if (isNullOrEmpty(modelCustomizationUuid)) {
1563 networkResource = db.getNetworkResource(networkType);
1564 } else if (!isNullOrEmpty(networkType)) {
1565 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1568 if (networkResource != null) {
1569 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1571 mode = networkResource.getOrchestrationMode();
1574 if (NEUTRON_MODE.equals(mode)) {
1575 long deleteNetworkStarttime = System.currentTimeMillis();
1577 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1578 // was not found. So don't bother to query first.
1579 boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1580 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1581 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1582 "DeleteNetwork", null);
1583 networkDeleted.value = deleted;
1584 } catch (MsoException me) {
1585 me.addContext("DeleteNetwork");
1586 String error = "Delete Network (neutron): " + networkId
1593 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1594 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1595 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1596 MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me);
1597 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1598 MsoLogger.ResponseCode.CommunicationError, error);
1599 throw new NetworkException(me);
1601 } else { // DEFAULT to ("HEAT".equals (mode))
1602 long deleteStackStarttime = System.currentTimeMillis();
1605 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1606 // So query first to report back if stack WAS deleted or just NOTOFUND
1607 StackInfo heatStack = null;
1608 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1609 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
1610 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1611 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1612 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1613 "DeleteStack", null);
1614 networkDeleted.value = true;
1616 networkDeleted.value = false;
1618 } catch (MsoException me) {
1619 me.addContext("DeleteNetwork");
1620 String error = "Delete Network (heat): " + networkId
1627 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1628 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1629 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1630 MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me);
1631 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1632 MsoLogger.ResponseCode.CommunicationError, error);
1633 throw new NetworkException(me);
1638 // On success, nothing is returned.
1639 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network");
1643 public CatalogDatabase getCatalogDB() {
1644 return CatalogDatabase.getInstance();
1647 public CloudConfigFactory getCloudConfigFactory() {
1648 return cloudConfigFactory;
1652 * This web service endpoint will rollback a previous Create VNF operation.
1653 * A rollback object is returned to the client in a successful creation
1654 * response. The client can pass that object as-is back to the rollbackVnf
1655 * operation to undo the creation.
1657 * The rollback includes removing the VNF and deleting the tenant if the
1658 * tenant did not exist prior to the VNF creation.
1661 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1662 MsoLogger.setServiceName ("RollbackNetwork");
1663 // Will capture execution time for metrics
1664 long startTime = System.currentTimeMillis ();
1666 if (rollback == null) {
1667 LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null");
1668 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform");
1672 MsoLogger.setLogContext (rollback.getMsoRequest());
1674 // Get the elements of the VnfRollback object for easier access
1675 String cloudSiteId = rollback.getCloudId ();
1676 String tenantId = rollback.getTenantId ();
1677 String networkId = rollback.getNetworkStackId ();
1678 String networkType = rollback.getNetworkType ();
1679 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1681 LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
1683 // rollback may be null (e.g. if network already existed when Create was called)
1684 // Get a handle to the Catalog Database
1686 // Make sure DB connection is always closed
1687 try (CatalogDatabase db = getCatalogDB()) {
1689 // Retrieve the Network Resource definition
1690 NetworkResource networkResource = null;
1691 if (isNullOrEmpty(modelCustomizationUuid)) {
1692 networkResource = db.getNetworkResource(networkType);
1694 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1697 if (networkResource != null) {
1699 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1701 mode = networkResource.getOrchestrationMode();
1704 if (rollback.getNetworkCreated()) {
1705 // Rolling back a newly created network, so delete it.
1706 if (NEUTRON_MODE.equals(mode)) {
1707 // Use MsoNeutronUtils for all NEUTRON commands
1708 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, getCloudConfigFactory());
1709 long deleteNetworkStarttime = System.currentTimeMillis();
1711 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1712 // was not found. So don't bother to query first.
1713 neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1714 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1715 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1716 "DeleteNetwork", null);
1717 } catch (MsoException me) {
1718 me.addContext("RollbackNetwork");
1719 String error = "Rollback Network (neutron): " + networkId
1726 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1727 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1729 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1730 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)",
1732 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1733 MsoLogger.ResponseCode.CommunicationError, error);
1734 throw new NetworkException(me);
1736 } else { // DEFAULT to if ("HEAT".equals (mode))
1737 // Use MsoHeatUtils for all HEAT commands
1738 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1739 getCloudConfigFactory());
1740 long deleteStackStarttime = System.currentTimeMillis();
1742 // The deleteStack function in MsoHeatUtils returns success if the stack
1743 // was not found. So don't bother to query first.
1744 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1745 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1746 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1747 "DeleteStack", null);
1748 } catch (MsoException me) {
1749 me.addContext("RollbackNetwork");
1750 String error = "Rollback Network (heat): " + networkId
1757 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1758 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1760 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1761 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me);
1762 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1763 MsoLogger.ResponseCode.CommunicationError, error);
1764 throw new NetworkException(me);
1769 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network");
1773 private String validateNetworkParams (NetworkType neutronNetworkType,
1775 String physicalNetwork,
1776 List <Integer> vlans,
1777 List <RouteTarget> routeTargets) {
1779 StringBuilder missing = new StringBuilder ();
1780 if (isNullOrEmpty(networkName)) {
1781 missing.append ("networkName");
1785 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1786 if (isNullOrEmpty(physicalNetwork)) {
1787 missing.append (sep).append ("physicalNetworkName");
1790 if (vlans == null || vlans.isEmpty ()) {
1791 missing.append (sep).append (VLANS);
1795 return missing.toString ();
1798 protected Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1800 String physicalNetwork,
1801 List <Integer> vlans,
1802 List <RouteTarget> routeTargets,
1805 boolean aic3template) {
1806 // Build the common set of HEAT template parameters
1807 Map <String, Object> stackParams = new HashMap <> ();
1808 stackParams.put ("network_name", networkName);
1810 if (neutronNetworkType == NetworkType.PROVIDER) {
1811 // For Provider type
1812 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1813 stackParams.put ("vlan", vlans.get (0).toString ());
1814 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1815 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1816 // It supports all ProviderNet properties except segmentation_id, and adds a
1817 // comma-separated-list of VLANs as a "segments" property.
1818 // Note that this does not match the Neutron definition of Multi-Provider network,
1819 // which contains a list of 'segments', each having physical_network, network_type,
1820 // and segmentation_id.
1821 StringBuilder buf = new StringBuilder ();
1823 for (Integer vlan : vlans) {
1824 buf.append (sep).append (vlan.toString ());
1827 String csl = buf.toString ();
1829 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1830 stackParams.put (VLANS, csl);
1833 if (routeTargets != null) {
1835 String rtGlobal = "";
1836 String rtImport = "";
1837 String rtExport = "";
1839 for (RouteTarget rt : routeTargets) {
1840 boolean rtIsNull = false;
1842 String routeTarget = rt.getRouteTarget();
1843 String routeTargetRole = rt.getRouteTargetRole();
1844 LOGGER.debug("Checking for an actually null route target: " + rt.toString());
1845 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1847 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1854 LOGGER.debug("Input RT:" + rt.toString());
1855 String role = rt.getRouteTargetRole();
1856 String rtValue = rt.getRouteTarget();
1858 if ("IMPORT".equalsIgnoreCase(role))
1860 sep = rtImport.isEmpty() ? "" : ",";
1861 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1863 else if ("EXPORT".equalsIgnoreCase(role))
1865 sep = rtExport.isEmpty() ? "" : ",";
1866 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1868 else // covers BOTH, empty etc
1870 sep = rtGlobal.isEmpty() ? "" : ",";
1871 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1876 if (!rtImport.isEmpty())
1878 stackParams.put ("route_targets_import", rtImport);
1880 if (!rtExport.isEmpty())
1882 stackParams.put ("route_targets_export", rtExport);
1884 if (!rtGlobal.isEmpty())
1886 stackParams.put ("route_targets", rtGlobal);
1889 if (isNullOrEmpty(shared)) {
1890 stackParams.put ("shared", "False");
1892 stackParams.put ("shared", shared);
1894 if (isNullOrEmpty(external)) {
1895 stackParams.put ("external", "False");
1897 stackParams.put ("external", external);
1904 /** policyRef_list structure in stackParams
1907 "network_policy_refs_data_sequence": {
1908 "network_policy_refs_data_sequence_major": "1",
1909 "network_policy_refs_data_sequence_minor": "0"
1913 "network_policy_refs_data_sequence": {
1914 "network_policy_refs_data_sequence_major": "2",
1915 "network_policy_refs_data_sequence_minor": "0"
1920 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1922 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1924 for (String pf : pFqdns) {
1925 if (!isNullOrEmpty(pf))
1927 ContrailPolicyRef pr = new ContrailPolicyRef();
1928 pr.populate(String.valueOf(index), "0");
1930 LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString());
1935 String jsonString = null;
1936 if (!prlist.isEmpty())
1940 ObjectMapper mapper = new ObjectMapper();
1941 jsonString = mapper.writeValueAsString(prlist);
1942 LOGGER.debug("Json PolicyRefs Data:" + jsonString);
1946 String error = "Error creating JsonNode for policyRefs Data";
1947 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e);
1948 throw new MsoAdapterException (error);
1952 if (pFqdns != null && !isNullOrEmpty(jsonString))
1954 StringBuilder buf = new StringBuilder ();
1956 for (String pf : pFqdns) {
1957 if (!isNullOrEmpty(pf))
1959 buf.append (sep).append (pf);
1963 String csl = buf.toString ();
1964 stackParams.put ("policy_refs", csl);
1965 stackParams.put ("policy_refsdata", jsonString);
1966 LOGGER.debug ("StackParams updated with policy refs:" + csl + " refs data:" + jsonString);
1971 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1974 if (rtFqdns != null)
1976 StringBuilder buf = new StringBuilder ();
1978 for (String rtf : rtFqdns) {
1979 if (!isNullOrEmpty(rtf))
1981 buf.append (sep).append (rtf);
1985 String csl = buf.toString ();
1986 stackParams.put ("route_table_refs", csl);
1989 LOGGER.debug ("StackParams updated with route_table refs");
1994 /*** Subnet Output structure from Juniper
1999 "ip_prefix": "10.100.1.0",
2002 "addr_from_start": null,
2003 "enable_dhcp": false,
2004 "default_gateway": "10.100.1.1",
2005 "dns_nameservers": [],
2006 "dhcp_option_list": null,
2007 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
2008 "allocation_pools": [
2010 "start": "10.100.1.3",
2014 "start": "10.100.1.6",
2018 "host_routes": null,
2019 "dns_server_address": "10.100.1.13",
2020 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
2024 "ip_prefix": "10.100.2.16",
2027 "addr_from_start": null,
2028 "enable_dhcp": true,
2029 "default_gateway": "10.100.2.17",
2030 "dns_nameservers": [],
2031 "dhcp_option_list": null,
2032 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
2033 "allocation_pools": [
2035 "start": "10.100.2.18",
2036 "end": "10.100.2.20"
2039 "host_routes": null,
2040 "dns_server_address": "10.100.2.29",
2041 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
2047 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
2050 List<ContrailSubnet> cslist = new ArrayList <> ();
2051 for (Subnet subnet : subnets) {
2052 ContrailSubnet cs = new ContrailSubnet();
2053 LOGGER.debug("Input Subnet:" + subnet.toString());
2054 cs.populateWith(subnet);
2055 LOGGER.debug("Contrail Subnet:" + cs.toString());
2059 String jsonString = null;
2060 if (!cslist.isEmpty())
2064 ObjectMapper mapper = new ObjectMapper();
2065 jsonString = mapper.writeValueAsString(cslist);
2066 LOGGER.debug("Json Subnet List:" + jsonString);
2070 String error = "Error creating JsonNode from input subnets";
2071 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e);
2072 throw new MsoAdapterException (error);
2076 if (!isNullOrEmpty(jsonString))
2078 stackParams.put ("subnet_list", jsonString);
2080 //Outputs - All subnets are in one ipam_subnets structure
2081 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
2082 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
2084 // append outputs in heatTemplate
2085 int outputsIdx = heatTemplate.indexOf ("outputs:");
2086 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
2087 LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate);
2088 return heatTemplate;
2092 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
2094 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
2097 + " network_id: { get_resource: network }\n"
2098 + " cidr: %cidr%\n";
2100 /* make these optional
2101 + " ip_version: %ipversion%\n"
2102 + " enable_dhcp: %enabledhcp%\n"
2103 + " gateway_ip: %gatewayip%\n"
2104 + " allocation_pools:\n"
2105 + " - start: %poolstart%\n"
2106 + " end: %poolend%\n";
2110 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
2111 + " value: {get_resource: subnet_%subnetId%}\n";
2115 StringBuilder resourcesBuf = new StringBuilder ();
2116 StringBuilder outputsBuf = new StringBuilder ();
2117 for (Subnet subnet : subnets) {
2119 // build template for each subnet
2120 curR = new StringBuilder(resourceTempl);
2121 if (subnet.getSubnetId () != null) {
2122 curR = new StringBuilder(curR.toString().replace("%subnetId%", subnet.getSubnetId()));
2124 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
2125 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID for subnet in HEAT Template");
2126 throw new MsoAdapterException (error);
2129 if (subnet.getSubnetName () != null) {
2130 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetName()));
2132 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetId()));
2135 if (subnet.getCidr () != null) {
2136 curR = new StringBuilder(curR.toString().replace("%cidr%", subnet.getCidr()));
2138 String error = "Missing Required cidr for subnet in HEAT Template";
2139 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template");
2140 throw new MsoAdapterException (error);
2143 if (subnet.getIpVersion () != null) {
2144 curR.append(" ip_version: " + subnet.getIpVersion() + "\n");
2146 if (subnet.getEnableDHCP () != null) {
2147 curR.append(" enable_dhcp: ").append(Boolean.toString(subnet.getEnableDHCP())).append("\n");
2149 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
2150 curR.append(" gateway_ip: " + subnet.getGatewayIp() + "\n");
2153 if (subnet.getAllocationPools() != null) {
2154 curR.append(" allocation_pools:\n");
2155 for (Pool pool : subnet.getAllocationPools())
2157 if (!isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()))
2159 curR.append(" - start: " + pool.getStart() + "\n");
2160 curR.append(" end: " + pool.getEnd() + "\n");
2165 resourcesBuf.append (curR);
2168 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
2170 outputsBuf.append (curO);
2173 // append resources and outputs in heatTemplate
2174 LOGGER.debug ("Tempate initial:" + heatTemplate);
2175 int outputsIdx = heatTemplate.indexOf ("outputs:");
2176 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
2177 int resourcesIdx = heatTemplate.indexOf ("resources:");
2178 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
2180 LOGGER.debug ("Template updated with all subnets:" + heatTemplate);
2181 return heatTemplate;
2184 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
2186 Map <String, String> sMap = new HashMap <> ();
2189 Object obj = outputs.get(key);
2190 ObjectMapper mapper = new ObjectMapper();
2191 String jStr = mapper.writeValueAsString(obj);
2192 LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr);
2194 JsonNode rootNode = mapper.readTree(jStr);
2195 for (JsonNode sNode : rootNode.path("ipam_subnets"))
2197 LOGGER.debug("Output Subnet Node" + sNode.toString());
2198 String name = sNode.path("subnet_name").textValue();
2199 String uuid = sNode.path("subnet_uuid").textValue();
2200 String aaiId = name; // default
2201 // try to find aaiId for name in input subnetList
2202 if (subnets != null)
2204 for (Subnet subnet : subnets)
2206 if ( subnet != null && !isNullOrEmpty(subnet.getSubnetName()))
2208 if (subnet.getSubnetName().equals(name))
2210 aaiId = subnet.getSubnetId();
2216 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
2221 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e);
2224 LOGGER.debug ("Return sMap" + sMap.toString());
2228 private static String insertStr (String template, String snippet, int index) {
2230 String updatedTemplate;
2232 LOGGER.debug ("Index:" + index + " Snippet:" + snippet);
2234 String templateBeg = template.substring (0, index);
2235 String templateEnd = template.substring (index);
2237 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
2239 LOGGER.debug ("Template updated with a subnet:" + updatedTemplate);
2240 return updatedTemplate;