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 private static final String AIC3_NW_PROPERTY= "org.openecomp.mso.adapters.network.aic3nw";
76 private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork";
77 public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER";
78 private static final String VLANS = "vlans";
79 private static final String PHYSICAL_NETWORK = "physical_network";
80 private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork";
81 private static final String NETWORK_ID = "network_id";
82 private static final String NETWORK_FQDN = "network_fqdn";
83 private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork";
84 private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
85 private static final String NEUTRON_MODE = "NEUTRON";
86 private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
87 private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
88 protected CloudConfig cloudConfig;
91 * Health Check web method. Does nothing but return to show the adapter is deployed.
94 public void healthCheck () {
95 LOGGER.debug ("Health check call in Network Adapter");
99 * Do not use this constructor or the msoPropertiesFactory will be NULL.
101 * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
103 public MsoNetworkAdapterImpl() {
107 * This constructor MUST be used if this class if called with the new operator.
108 * @param msoPropFactory
111 public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) {
112 this.msoPropertiesFactory = msoPropFactory;
113 this.cloudConfigFactory=cloudConfigFact;
114 cloudConfig = cloudConfigFactory.getCloudConfig ();
118 public void createNetwork (String cloudSiteId,
121 String modelCustomizationUuid,
123 String physicalNetworkName,
124 List <Integer> vlans,
125 Boolean failIfExists,
127 List <Subnet> subnets,
128 MsoRequest msoRequest,
129 Holder <String> networkId,
130 Holder <String> neutronNetworkId,
131 Holder <Map <String, String>> subnetIdMap,
132 Holder <NetworkRollback> rollback) throws NetworkException {
133 Holder <String> networkFqdn = new Holder <> ();
134 createNetwork (cloudSiteId,
137 modelCustomizationUuid,
158 public void createNetworkContrail (String cloudSiteId,
161 String modelCustomizationUuid,
163 List <RouteTarget> routeTargets,
166 Boolean failIfExists,
168 List <Subnet> subnets,
169 List <String> policyFqdns,
170 List<String> routeTableFqdns,
171 MsoRequest msoRequest,
172 Holder <String> networkId,
173 Holder <String> neutronNetworkId,
174 Holder <String> networkFqdn,
175 Holder <Map <String, String>> subnetIdMap,
176 Holder <NetworkRollback> rollback) throws NetworkException {
177 createNetwork (cloudSiteId,
180 modelCustomizationUuid,
201 * This is the "Create Network" web service implementation.
202 * It will create a new Network of the requested type in the specified cloud
203 * and tenant. The tenant must exist at the time this service is called.
205 * If a network with the same name already exists, this can be considered a
206 * success or failure, depending on the value of the 'failIfExists' parameter.
208 * There will be a pre-defined set of network types defined in the MSO Catalog.
209 * All such networks will have a similar configuration, based on the allowable
210 * Openstack networking definitions. This includes basic networks, provider
211 * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
213 * Initially, all provider networks must be "vlan" type, and multiple segments in
214 * a multi-provider network must be multiple VLANs on the same physical network.
216 * This service supports two modes of Network creation/update:
217 * - via Heat Templates
219 * The network orchestration mode for each network type is declared in its
220 * catalog definition. All Heat-based templates must support some subset of
221 * the same input parameters: network_name, physical_network, vlan(s).
223 * The method returns the network ID and a NetworkRollback object. This latter
224 * object can be passed as-is to the rollbackNetwork operation to undo everything
225 * that was created. This is useful if a network is successfully created but
226 * the orchestration fails on a subsequent operation.
229 private void createNetwork (String cloudSiteId,
232 String modelCustomizationUuid,
234 String physicalNetworkName,
235 List <Integer> vlans,
236 List <RouteTarget> routeTargets,
239 Boolean failIfExists,
241 List <Subnet> subnets,
242 List <String> policyFqdns,
243 List <String> routeTableFqdns,
244 MsoRequest msoRequest,
245 Holder <String> networkId,
246 Holder <String> neutronNetworkId,
247 Holder <String> networkFqdn,
248 Holder <Map <String, String>> subnetIdMap,
249 Holder <NetworkRollback> rollback) throws NetworkException {
250 MsoLogger.setLogContext (msoRequest);
251 MsoLogger.setServiceName ("CreateNetwork");
253 LOGGER.debug ("*** CREATE Network: " + networkName
261 // Will capture execution time for metrics
262 long startTime = System.currentTimeMillis ();
264 // Build a default rollback object (no actions performed)
265 NetworkRollback networkRollback = new NetworkRollback ();
266 networkRollback.setCloudId (cloudSiteId);
267 networkRollback.setTenantId (tenantId);
268 networkRollback.setMsoRequest (msoRequest);
269 networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
271 // tenant query is not required here.
272 // If the tenant doesn’t exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
273 // So this is just catching that error in a bit more obvious way up front.
275 cloudConfig = cloudConfigFactory.getCloudConfig ();
276 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
277 if (!cloudSiteOpt.isPresent())
279 String error = "Configuration Error. Stack " + networkName + " in "
284 + " CloudSite does not exist in MSO Configuration";
285 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
286 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
287 // Set the detailed error as the Exception 'message'
288 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
291 // Get a handle to the Catalog Database
293 // Make sure DB connection is always closed
294 try (CatalogDatabase db = getCatalogDB()) {
295 NetworkResource networkResource = networkCheck(db,
298 modelCustomizationUuid,
304 String mode = networkResource.getOrchestrationMode();
305 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
307 if (NEUTRON_MODE.equals(mode)) {
309 // Use an MsoNeutronUtils for all neutron commands
310 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
312 // See if the Network already exists (by name)
313 NetworkInfo netInfo = null;
314 long queryNetworkStarttime = System.currentTimeMillis();
316 netInfo = neutron.queryNetwork(networkName, tenantId, cloudSiteId);
317 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
318 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
319 "QueryNetwork", null);
320 } catch (MsoException me) {
321 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
322 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack",
323 "OpenStack", "QueryNetwork", null);
324 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
325 MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack",
327 me.addContext(CREATE_NETWORK_CONTEXT);
328 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
329 MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack");
330 throw new NetworkException(me);
333 if (netInfo != null) {
334 // Exists. If that's OK, return success with the network ID.
335 // Otherwise, return an exception.
336 if (failIfExists != null && failIfExists) {
337 String error = "Create Nework: Network " + networkName
338 + " already exists in "
342 + " with ID " + netInfo.getId();
343 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId,
344 "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
345 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
347 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
349 // Populate the outputs from the existing network.
350 networkId.value = netInfo.getId();
351 neutronNetworkId.value = netInfo.getId();
352 rollback.value = networkRollback; // Default rollback - no updates performed
353 String msg = "Found Existing network, status=" + netInfo.getStatus() + " for Neutron mode";
354 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
355 MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus());
356 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
362 long createNetworkStarttime = System.currentTimeMillis();
364 netInfo = neutron.createNetwork(cloudSiteId,
370 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
371 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
372 "CreateNetwork", null);
373 } catch (MsoException me) {
374 me.addContext(CREATE_NETWORK_CONTEXT);
375 LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.ERROR,
376 MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack",
377 "OpenStack", "CreateNetwork", null);
378 String error = "Create Network: type " + neutronNetworkType
385 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
386 MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me);
387 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
388 MsoLogger.ResponseCode.CommunicationError, error);
390 throw new NetworkException(me);
393 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
395 // If reach this point, network creation is successful.
396 // Since directly created via Neutron, networkId tracked by MSO is the same
397 // as the neutron network ID.
398 networkId.value = netInfo.getId();
399 neutronNetworkId.value = netInfo.getId();
401 networkRollback.setNetworkCreated(true);
402 networkRollback.setNetworkId(netInfo.getId());
403 networkRollback.setNeutronNetworkId(netInfo.getId());
404 networkRollback.setNetworkType(networkType);
406 LOGGER.debug("Network " + networkName + " created, id = " + netInfo.getId());
407 } else if ("HEAT".equals(mode)) {
409 // Use an MsoHeatUtils for all Heat commands
410 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
413 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
414 HeatTemplate heatTemplate = db
415 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
416 if (heatTemplate == null) {
417 String error = "Network error - undefined Heat Template. Network Type = " + networkType;
418 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
419 "Openstack", "", MsoLogger.ErrorCode.DataError,
420 "Network error - undefined Heat Template. Network Type = " + networkType);
421 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
425 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
427 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
430 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
432 // "Fix" the template if it has CR/LF (getting this from Oracle)
433 String template = heatTemplate.getHeatTemplate();
434 template = template.replaceAll("\r\n", "\n");
436 boolean aic3template = false;
437 String aic3nw = AIC3_NW;
439 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
440 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
441 } catch (MsoPropertiesException e) {
442 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
443 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError,
444 "Exception - Unable to get properties", e);
447 if (template.contains(aic3nw))
450 // First, look up to see if the Network already exists (by name).
451 // For HEAT orchestration of networks, the stack name will always match the network name
452 StackInfo heatStack = null;
453 long queryNetworkStarttime = System.currentTimeMillis();
455 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
456 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
457 MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
458 "QueryNetwork", null);
459 } catch (MsoException me) {
460 me.addContext(CREATE_NETWORK_CONTEXT);
461 LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
462 MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack",
463 "OpenStack", "QueryNetwork", null);
464 String error = "Create Network (heat): query network " + networkName
471 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
472 MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me);
473 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
474 MsoLogger.ResponseCode.CommunicationError, error);
475 throw new NetworkException(me);
478 if (heatStack != null && (heatStack.getStatus() != HeatStatus.NOTFOUND)) {
479 // Stack exists. Return success or error depending on input directive
480 if (failIfExists != null && failIfExists) {
481 String error = "CreateNetwork: Stack " + networkName
482 + " already exists in "
486 + " as " + heatStack.getCanonicalName();
487 LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
488 MsoLogger.ErrorCode.DataError, "Network already exists");
489 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
491 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
493 // Populate the outputs from the existing stack.
494 networkId.value = heatStack.getCanonicalName();
495 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
496 rollback.value = networkRollback; // Default rollback - no updates performed
498 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
500 Map<String, Object> outputs = heatStack.getOutputs();
501 Map<String, String> sMap = new HashMap<>();
502 if (outputs != null) {
503 for (String key : outputs.keySet()) {
504 if (key != null && key.startsWith("subnet")) {
505 if (aic3template) //one subnet_id output
507 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
509 } else //multiples subnet_%aaid% outputs
511 String subnetUUId = (String) outputs.get(key);
512 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
517 subnetIdMap.value = sMap;
518 LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
519 MsoLogger.ErrorCode.DataError,
520 "Found Existing network stack, status=" + heatStack.getStatus());
521 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc,
522 "Found Existing network stack");
527 // Ready to deploy the new Network
528 // Build the common set of HEAT template parameters
529 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
538 // Validate (and update) the input parameters against the DB definition
539 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
540 // and inputs were already validated.
542 stackParams = heat.validateStackParams(stackParams, heatTemplate);
543 } catch (IllegalArgumentException e) {
544 String error = "Create Network: Configuration Error: " + e.getMessage();
545 LOGGER.error(MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "",
546 MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e);
547 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
551 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError,
553 // Input parameters were not valid
554 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
557 if (subnets != null) {
560 template = mergeSubnetsAIC3(template, subnets, stackParams);
562 template = mergeSubnets(template, subnets);
564 } catch (MsoException me) {
565 me.addContext(CREATE_NETWORK_CONTEXT);
566 String error = "Create Network (heat): type " + neutronNetworkType
573 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
574 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
575 "Exception Create Network, merging subnets", me);
576 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
577 MsoLogger.ResponseCode.InternalError, error);
578 throw new NetworkException(me);
582 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
584 mergePolicyRefs(policyFqdns, stackParams);
585 } catch (MsoException me) {
586 me.addContext(CREATE_NETWORK_CONTEXT);
587 String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType
594 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
595 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
596 "Exception Create Network, merging policyRefs", me);
597 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
598 MsoLogger.ResponseCode.InternalError, error);
599 throw new NetworkException(me);
603 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
605 mergeRouteTableRefs(routeTableFqdns, stackParams);
606 } catch (MsoException me) {
607 me.addContext(CREATE_NETWORK_CONTEXT);
608 String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType
615 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
616 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
617 "Exception Create Network, merging routeTableRefs", me);
618 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
619 MsoLogger.ResponseCode.InternalError, error);
620 throw new NetworkException(me);
624 // Deploy the network stack
625 // Ignore MsoStackAlreadyExists exception because we already checked.
629 heatStack = heat.createStack(cloudSiteId,
635 heatTemplate.getTimeoutMinutes(),
639 backout.booleanValue());
640 } catch (MsoException me) {
641 me.addContext(CREATE_NETWORK_CONTEXT);
642 String error = "Create Network (heat): type " + neutronNetworkType
649 LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "",
650 MsoLogger.ErrorCode.DataError, "Exception creating network", me);
651 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
652 MsoLogger.ResponseCode.CommunicationError, error);
653 throw new NetworkException(me);
656 // Reach this point if createStack is successful.
658 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
659 // and the neutronNetworkId is the network UUID returned in stack outputs.
660 networkId.value = heatStack.getCanonicalName();
661 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
663 networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
665 Map<String, Object> outputs = heatStack.getOutputs();
666 Map<String, String> sMap = new HashMap<>();
667 if (outputs != null) {
668 for (String key : outputs.keySet()) {
669 if (key != null && key.startsWith("subnet")) {
670 if (aic3template) //one subnet output expected
672 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
674 } else //multiples subnet_%aaid% outputs allowed
676 String subnetUUId = (String) outputs.get(key);
677 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
682 subnetIdMap.value = sMap;
684 rollback.value = networkRollback;
685 // Populate remaining rollback info and response parameters.
686 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
687 networkRollback.setNeutronNetworkId((String) heatStack.getOutputs().get(NETWORK_ID));
688 networkRollback.setNetworkCreated(true);
689 networkRollback.setNetworkType(networkType);
691 LOGGER.debug("Network " + networkName + " successfully created via HEAT");
694 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network");
699 public void updateNetwork (String cloudSiteId,
702 String modelCustomizationUuid,
705 String physicalNetworkName,
706 List <Integer> vlans,
707 List <Subnet> subnets,
708 MsoRequest msoRequest,
709 Holder <Map <String, String>> subnetIdMap,
710 Holder <NetworkRollback> rollback) throws NetworkException {
711 updateNetwork (cloudSiteId,
714 modelCustomizationUuid,
732 public void updateNetworkContrail (String cloudSiteId,
735 String modelCustomizationUuid,
738 List <RouteTarget> routeTargets,
741 List <Subnet> subnets,
742 List <String> policyFqdns,
743 List<String> routeTableFqdns,
744 MsoRequest msoRequest,
745 Holder <Map <String, String>> subnetIdMap,
746 Holder <NetworkRollback> rollback) throws NetworkException {
747 updateNetwork (cloudSiteId,
750 modelCustomizationUuid,
767 * This is the "Update Network" web service implementation.
768 * It will update an existing Network of the requested type in the specified cloud
769 * and tenant. The typical use will be to replace the VLANs with the supplied
770 * list (to add or remove a VLAN), but other properties may be updated as well.
772 * There will be a pre-defined set of network types defined in the MSO Catalog.
773 * All such networks will have a similar configuration, based on the allowable
774 * Openstack networking definitions. This includes basic networks, provider
775 * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
777 * Initially, all provider networks must currently be "vlan" type, and multi-provider
778 * networks must be multiple VLANs on the same physical network.
780 * This service supports two modes of Network update:
781 * - via Heat Templates
783 * The network orchestration mode for each network type is declared in its
784 * catalog definition. All Heat-based templates must support some subset of
785 * the same input parameters: network_name, physical_network, vlan, segments.
787 * The method returns a NetworkRollback object. This object can be passed
788 * as-is to the rollbackNetwork operation to undo everything that was updated.
789 * This is useful if a network is successfully updated but orchestration
790 * fails on a subsequent operation.
792 private void updateNetwork (String cloudSiteId,
795 String modelCustomizationUuid,
798 String physicalNetworkName,
799 List <Integer> vlans,
800 List <RouteTarget> routeTargets,
803 List <Subnet> subnets,
804 List <String> policyFqdns,
805 List<String> routeTableFqdns,
806 MsoRequest msoRequest,
807 Holder <Map <String, String>> subnetIdMap,
808 Holder <NetworkRollback> rollback) throws NetworkException {
809 MsoLogger.setLogContext (msoRequest);
810 MsoLogger.setServiceName ("UpdateNetwork");
811 LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName
820 // Will capture execution time for metrics
821 long startTime = System.currentTimeMillis ();
823 // Build a default rollback object (no actions performed)
824 NetworkRollback networkRollback = new NetworkRollback ();
825 networkRollback.setCloudId (cloudSiteId);
826 networkRollback.setTenantId (tenantId);
827 networkRollback.setMsoRequest (msoRequest);
829 cloudConfig = cloudConfigFactory.getCloudConfig ();
830 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
831 if (!cloudSiteOpt.isPresent()) {
832 String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in "
837 + " CloudSite does not exist in MSO Configuration";
838 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration");
839 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
840 // Set the detailed error as the Exception 'message'
841 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
844 // Get a handle to the Catalog Database
846 // Make sure DB connection is always closed
847 try (CatalogDatabase db = getCatalogDB()) {
848 NetworkResource networkResource = networkCheck(db,
851 modelCustomizationUuid,
857 String mode = networkResource.getOrchestrationMode();
858 NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
860 // Use an MsoNeutronUtils for all Neutron commands
861 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
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 // Use an MsoHeatUtils for all Heat commands
947 MsoHeatUtilsWithUpdate heat = new MsoHeatUtilsWithUpdate(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
950 // First, look up to see that the Network already exists.
951 // For Heat-based orchestration, the networkId is the network Stack ID.
952 StackInfo heatStack = null;
953 long queryStackStarttime = System.currentTimeMillis();
955 heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
956 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE,
957 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
959 } catch (MsoException me) {
960 me.addContext(UPDATE_NETWORK_CONTEXT);
961 String error = "UpdateNetwork (heat): query " + networkName
968 LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR,
969 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
970 LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
971 "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
972 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
973 MsoLogger.ResponseCode.CommunicationError, error);
974 throw new NetworkException(me);
977 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
978 String error = "UpdateNetwork: Stack " + networkName
979 + " does not exist in "
983 LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack",
984 "queryStack", MsoLogger.ErrorCode.DataError, "Network not found");
985 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
987 // Network stack does not exist. Return an error
988 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
991 // Get the previous parameters for rollback
992 Map<String, Object> heatParams = heatStack.getParameters();
994 String previousNetworkName = (String) heatParams.get("network_name");
995 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
997 List<Integer> previousVlans = new ArrayList<>();
998 String vlansParam = (String) heatParams.get(VLANS);
999 if (vlansParam != null) {
1000 for (String vlan : vlansParam.split(",")) {
1002 previousVlans.add(Integer.parseInt(vlan));
1003 } catch (NumberFormatException e) {
1004 LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", "",
1005 MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e);
1009 LOGGER.debug("Update Stack: Previous VLANS: " + previousVlans);
1011 // Ready to deploy the updated Network via Heat
1013 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
1014 HeatTemplate heatTemplate = db
1015 .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
1016 if (heatTemplate == null) {
1017 String error = "Network error - undefined Heat Template. Network Type=" + networkType;
1018 LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
1019 "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError,
1020 "Network error - undefined Heat Template. Network Type=" + networkType);
1021 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1022 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1024 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1027 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1029 // "Fix" the template if it has CR/LF (getting this from Oracle)
1030 String template = heatTemplate.getHeatTemplate();
1031 template = template.replaceAll("\r\n", "\n");
1033 boolean aic3template = false;
1034 String aic3nw = AIC3_NW;
1036 aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
1037 .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
1038 } catch (MsoPropertiesException e) {
1039 String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
1040 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1041 "Exception - Unable to get properties", e);
1043 if (template.contains(aic3nw))
1044 aic3template = true;
1046 // Build the common set of HEAT template parameters
1047 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
1049 physicalNetworkName,
1056 // Validate (and update) the input parameters against the DB definition
1057 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
1059 stackParams = heat.validateStackParams(stackParams, heatTemplate);
1060 } catch (IllegalArgumentException e) {
1061 String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
1062 LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "",
1063 MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error");
1064 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1065 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError,
1067 throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
1070 if (subnets != null) {
1073 template = mergeSubnetsAIC3(template, subnets, stackParams);
1075 template = mergeSubnets(template, subnets);
1077 } catch (MsoException me) {
1078 me.addContext(UPDATE_NETWORK_CONTEXT);
1079 String error = "Update Network (heat): type " + neutronNetworkType
1086 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1087 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1088 "Exception - UpdateNetwork mergeSubnets ", me);
1089 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1090 MsoLogger.ResponseCode.InternalError, error);
1091 throw new NetworkException(me);
1095 if (policyFqdns != null && aic3template) {
1097 mergePolicyRefs(policyFqdns, stackParams);
1098 } catch (MsoException me) {
1099 me.addContext(UPDATE_NETWORK_CONTEXT);
1100 String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType
1107 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1108 tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1109 "Exception - UpdateNetwork mergePolicyRefs", me);
1110 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1111 MsoLogger.ResponseCode.InternalError, error);
1112 throw new NetworkException(me);
1116 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
1118 mergeRouteTableRefs(routeTableFqdns, stackParams);
1119 } catch (MsoException me) {
1120 me.addContext(UPDATE_NETWORK_CONTEXT);
1121 String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType
1128 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1129 tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
1130 "Exception - UpdateNetwork mergeRouteTableRefs", me);
1131 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1132 MsoLogger.ResponseCode.InternalError, error);
1133 throw new NetworkException(me);
1137 // Update the network stack
1138 // Ignore MsoStackNotFound exception because we already checked.
1139 long updateStackStarttime = System.currentTimeMillis();
1141 heatStack = heat.updateStack(cloudSiteId,
1147 heatTemplate.getTimeoutMinutes());
1148 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1149 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1150 "UpdateStack", null);
1151 } catch (MsoException me) {
1152 me.addContext(UPDATE_NETWORK_CONTEXT);
1153 String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1154 LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1155 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
1156 LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "",
1157 MsoLogger.ErrorCode.DataError, "Exception - update network", me);
1158 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1159 MsoLogger.ResponseCode.CommunicationError, error);
1160 throw new NetworkException(me);
1163 Map<String, Object> outputs = heatStack.getOutputs();
1164 Map<String, String> sMap = new HashMap<>();
1165 if (outputs != null) {
1166 for (String key : outputs.keySet()) {
1167 if (key != null && key.startsWith("subnet")) {
1168 if (aic3template) //one subnet output expected
1170 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
1172 } else //multiples subnet_%aaid% outputs allowed
1174 String subnetUUId = (String) outputs.get(key);
1175 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
1180 subnetIdMap.value = sMap;
1182 // Reach this point if createStack is successful.
1183 // Populate remaining rollback info and response parameters.
1184 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
1185 if (null != outputs) {
1186 networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
1188 LOGGER.debug("outputs is NULL");
1190 networkRollback.setNetworkType(networkType);
1191 // Save previous parameters
1192 networkRollback.setNetworkName(previousNetworkName);
1193 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
1194 networkRollback.setVlans(previousVlans);
1196 rollback.value = networkRollback;
1198 LOGGER.debug("Network " + networkId + " successfully updated via HEAT");
1201 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network");
1205 private NetworkResource networkCheck (CatalogDatabase db,
1208 String modelCustomizationUuid,
1210 String physicalNetworkName,
1211 List <Integer> vlans,
1212 List <RouteTarget> routeTargets,
1213 CloudSite cloudSite) throws NetworkException {
1214 // Retrieve the Network Resource definition
1215 NetworkResource networkResource = null;
1217 if (isNullOrEmpty(modelCustomizationUuid)) {
1218 networkResource = db.getNetworkResource(networkType);
1220 networkResource = db
1221 .getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1223 if (networkResource == null) {
1224 String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:"
1226 + " or ModelCustomizationUUID:"
1227 + modelCustomizationUuid;
1228 LOGGER.error(MessageEnum.RA_UNKOWN_PARAM,
1229 "NetworkType/ModelCustomizationUUID", networkType + "/"
1230 + modelCustomizationUuid, "OpenStack", "",
1231 MsoLogger.ErrorCode.DataError,
1232 "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID");
1234 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1236 LOGGER.debug("Got Network definition from Catalog: "
1237 + networkResource.toString());
1239 String mode = networkResource.getOrchestrationMode();
1240 NetworkType neutronNetworkType = NetworkType
1241 .valueOf(networkResource.getNeutronNetworkType());
1243 // All Networks are orchestrated via HEAT or Neutron
1244 if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1245 String error = "CreateNetwork: Configuration Error: Network Type = "
1247 LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1248 mode, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1249 "CreateNetwork: Configuration Error");
1250 // Alarm on this error, configuration must be fixed
1251 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1252 MsoAlarmLogger.CRITICAL, error);
1254 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1257 MavenLikeVersioning aicV = new MavenLikeVersioning();
1258 aicV.setVersion(cloudSite.getAic_version());
1259 if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1260 .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1263 && (aicV.isTheSameVersion(networkResource
1264 .getAicVersionMax()) || !(aicV
1265 .isMoreRecentThan(networkResource
1266 .getAicVersionMax())))) // aic <= max
1268 LOGGER.debug("Network Type:" + networkType + " VersionMin:"
1269 + networkResource.getAicVersionMin() + " VersionMax:"
1270 + networkResource.getAicVersionMax()
1271 + " supported on Cloud:" + cloudSite.getId()
1272 + " with AIC_Version:" + cloudSite.getAic_version());
1274 String error = "Network Type:" + networkType + " Version_Min:"
1275 + networkResource.getAicVersionMin() + " Version_Max:"
1276 + networkResource.getAicVersionMax()
1277 + " not supported on Cloud:" + cloudSite.getId()
1278 + " with AIC_Version:" + cloudSite.getAic_version();
1279 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1280 MsoLogger.ErrorCode.DataError,
1281 "Network Type not supported on Cloud");
1282 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1283 MsoLogger.ResponseCode.DataError, error);
1284 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1287 // Validate the Network parameters.
1288 String missing = validateNetworkParams(neutronNetworkType,
1289 networkName, physicalNetworkName, vlans, routeTargets);
1290 if (!missing.isEmpty()) {
1291 String error = "Create Network: Missing parameters: " + missing;
1292 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing,
1293 "OpenStack", "", MsoLogger.ErrorCode.DataError,
1294 "Create Network: Missing parameters");
1296 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1301 return networkResource;
1305 public void queryNetwork (String cloudSiteId,
1307 String networkNameOrId,
1308 MsoRequest msoRequest,
1309 Holder <Boolean> networkExists,
1310 Holder <String> networkId,
1311 Holder <String> neutronNetworkId,
1312 Holder <NetworkStatus> status,
1313 Holder <List <Integer>> vlans,
1314 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1315 queryNetworkInfo(cloudSiteId,
1329 public void queryNetworkContrail (String cloudSiteId,
1331 String networkNameOrId,
1332 MsoRequest msoRequest,
1333 Holder <Boolean> networkExists,
1334 Holder <String> networkId,
1335 Holder <String> neutronNetworkId,
1336 Holder <NetworkStatus> status,
1337 Holder <List <RouteTarget>> routeTargets,
1338 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1339 queryNetworkInfo(cloudSiteId,
1353 * This is the queryNetworkInfo method. It returns the existence and status of
1354 * the specified network, along with its Neutron UUID and list of VLANs.
1355 * This method attempts to find the network using both Heat and Neutron.
1356 * Heat stacks are first searched based on the provided network name/id.
1357 * If none is found, the Neutron is directly queried.
1359 private void queryNetworkInfo(String cloudSiteId,
1361 String networkNameOrId,
1362 MsoRequest msoRequest,
1363 Holder <Boolean> networkExists,
1364 Holder <String> networkId,
1365 Holder <String> neutronNetworkId,
1366 Holder <NetworkStatus> status,
1367 Holder <List <Integer>> vlans,
1368 Holder <List <RouteTarget>> routeTargets,
1369 Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1370 MsoLogger.setLogContext (msoRequest);
1371 MsoLogger.setServiceName ("QueryNetwork");
1372 LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId
1378 // Will capture execution time for metrics
1379 long startTime = System.currentTimeMillis ();
1381 if (isNullOrEmpty (cloudSiteId)
1382 || isNullOrEmpty(tenantId)
1383 || isNullOrEmpty(networkNameOrId)) {
1385 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1386 LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1387 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1388 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1391 cloudConfig = cloudConfigFactory.getCloudConfig();
1392 Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1393 if (!cloudSiteOpt.isPresent())
1395 String error = "Configuration Error. Stack " + networkNameOrId + " in "
1400 + " CloudSite does not exist in MSO Configuration";
1401 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
1402 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1403 // Set the detailed error as the Exception 'message'
1404 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1407 // Use MsoNeutronUtils for all NEUTRON commands
1408 MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER,msoPropertiesFactory,cloudConfigFactory);
1409 MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1413 // Try Heat first, since networks may be named the same as the Heat stack
1414 StackInfo heatStack = null;
1415 long queryStackStarttime = System.currentTimeMillis ();
1417 heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1418 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
1419 } catch (MsoException me) {
1420 me.addContext ("QueryNetwork");
1421 String error = "Query Network (heat): " + networkNameOrId
1428 LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null);
1429 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me);
1430 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1431 throw new NetworkException (me);
1434 // Populate the outputs based on the returned Stack information
1435 if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1436 // Found it. Get the neutronNetworkId for further query
1437 Map <String, Object> outputs = heatStack.getOutputs ();
1438 neutronId = (String) outputs.get (NETWORK_ID);
1441 Map <String, String> sMap = new HashMap <> ();
1442 if (outputs != null) {
1443 for (String key : outputs.keySet ()) {
1444 if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1446 String subnetUUId = (String) outputs.get(key);
1447 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1449 else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1451 Map <String, String> map = getSubnetUUId(key, outputs, null);
1457 subnetIdMap.value = sMap;
1459 // Input ID was not a Heat stack ID. Try it directly in Neutron
1460 neutronId = networkNameOrId;
1461 mode = NEUTRON_MODE;
1464 // Query directly against the Neutron Network for the details
1465 // no RouteTargets available for ContrailV2 in neutron net-show
1466 // networkId is heatStackId
1467 long queryNetworkStarttime = System.currentTimeMillis ();
1469 NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1470 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
1471 if (netInfo != null) {
1472 // Found. Populate the output elements
1473 networkExists.value = Boolean.TRUE;
1474 if ("HEAT".equals (mode)) {
1475 networkId.value = heatStack.getCanonicalName ();
1477 networkId.value = netInfo.getId ();
1479 neutronNetworkId.value = netInfo.getId ();
1480 status.value = netInfo.getStatus ();
1482 vlans.value = netInfo.getVlans ();
1484 LOGGER.debug ("Network " + networkNameOrId
1489 + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1491 // Not found. Populate the status fields, leave the rest null
1492 networkExists.value = Boolean.FALSE;
1493 status.value = NetworkStatus.NOTFOUND;
1494 neutronNetworkId.value = null;
1496 vlans.value = new ArrayList<>();
1498 LOGGER.debug ("Network " + networkNameOrId + " not found");
1500 } catch (MsoException me) {
1501 me.addContext ("QueryNetwork");
1502 String error = "Query Network (neutron): " + networkNameOrId
1509 LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
1510 LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me);
1511 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1512 throw new NetworkException (me);
1514 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network");
1519 * This is the "Delete Network" web service implementation.
1520 * It will delete a Network in the specified cloud and tenant.
1522 * If the network is not found, it is treated as a success.
1524 * This service supports two modes of Network creation/update/delete:
1525 * - via Heat Templates
1527 * The network orchestration mode for each network type is declared in its
1528 * catalog definition.
1530 * For Heat-based orchestration, the networkId should be the stack ID.
1531 * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1533 * The method returns nothing on success. Rollback is not possible for delete
1534 * commands, so any failure on delete will require manual fallout in the client.
1537 public void deleteNetwork (String cloudSiteId,
1540 String modelCustomizationUuid,
1542 MsoRequest msoRequest,
1543 Holder <Boolean> networkDeleted) throws NetworkException {
1544 MsoLogger.setLogContext (msoRequest);
1545 MsoLogger.setServiceName ("DeleteNetwork");
1546 LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId
1552 // Will capture execution time for metrics
1553 long startTime = System.currentTimeMillis ();
1555 // Get a handle to the Catalog Database
1557 // Make sure DB connection is always closed
1558 try (CatalogDatabase db = getCatalogDB()) {
1559 if (isNullOrEmpty(cloudSiteId)
1560 || isNullOrEmpty(tenantId)
1561 || isNullOrEmpty(networkId)) {
1562 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1563 LOGGER.error(MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "",
1564 MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1566 .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1567 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1570 // Retrieve the Network Resource definition
1571 NetworkResource networkResource = null;
1572 if (isNullOrEmpty(modelCustomizationUuid)) {
1573 networkResource = db.getNetworkResource(networkType);
1574 } else if (!isNullOrEmpty(networkType)) {
1575 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1578 if (networkResource != null) {
1579 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1581 mode = networkResource.getOrchestrationMode();
1584 if (NEUTRON_MODE.equals(mode)) {
1586 // Use MsoNeutronUtils for all NEUTRON commands
1587 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1588 long deleteNetworkStarttime = System.currentTimeMillis();
1590 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1591 // was not found. So don't bother to query first.
1592 boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1593 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1594 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1595 "DeleteNetwork", null);
1596 networkDeleted.value = deleted;
1597 } catch (MsoException me) {
1598 me.addContext("DeleteNetwork");
1599 String error = "Delete Network (neutron): " + networkId
1606 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1607 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1608 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1609 MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me);
1610 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1611 MsoLogger.ResponseCode.CommunicationError, error);
1612 throw new NetworkException(me);
1614 } else { // DEFAULT to ("HEAT".equals (mode))
1615 long deleteStackStarttime = System.currentTimeMillis();
1616 // Use MsoHeatUtils for all HEAT commands
1617 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1618 cloudConfigFactory);
1621 // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1622 // So query first to report back if stack WAS deleted or just NOTOFUND
1623 StackInfo heatStack = null;
1624 heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1625 if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
1626 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1627 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1628 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1629 "DeleteStack", null);
1630 networkDeleted.value = true;
1632 networkDeleted.value = false;
1634 } catch (MsoException me) {
1635 me.addContext("DeleteNetwork");
1636 String error = "Delete Network (heat): " + networkId
1643 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1644 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1645 LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1646 MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me);
1647 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1648 MsoLogger.ResponseCode.CommunicationError, error);
1649 throw new NetworkException(me);
1654 // On success, nothing is returned.
1655 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network");
1659 public CatalogDatabase getCatalogDB() {
1660 return CatalogDatabase.getInstance();
1664 * This web service endpoint will rollback a previous Create VNF operation.
1665 * A rollback object is returned to the client in a successful creation
1666 * response. The client can pass that object as-is back to the rollbackVnf
1667 * operation to undo the creation.
1669 * The rollback includes removing the VNF and deleting the tenant if the
1670 * tenant did not exist prior to the VNF creation.
1673 public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1674 MsoLogger.setServiceName ("RollbackNetwork");
1675 // Will capture execution time for metrics
1676 long startTime = System.currentTimeMillis ();
1678 if (rollback == null) {
1679 LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null");
1680 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform");
1684 MsoLogger.setLogContext (rollback.getMsoRequest());
1686 // Get the elements of the VnfRollback object for easier access
1687 String cloudSiteId = rollback.getCloudId ();
1688 String tenantId = rollback.getTenantId ();
1689 String networkId = rollback.getNetworkStackId ();
1690 String networkType = rollback.getNetworkType ();
1691 String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1693 LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
1695 // rollback may be null (e.g. if network already existed when Create was called)
1696 // Get a handle to the Catalog Database
1698 // Make sure DB connection is always closed
1699 try (CatalogDatabase db = getCatalogDB()) {
1701 // Retrieve the Network Resource definition
1702 NetworkResource networkResource = null;
1703 if (isNullOrEmpty(modelCustomizationUuid)) {
1704 networkResource = db.getNetworkResource(networkType);
1706 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1709 if (networkResource != null) {
1711 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1713 mode = networkResource.getOrchestrationMode();
1716 if (rollback.getNetworkCreated()) {
1717 // Rolling back a newly created network, so delete it.
1718 if (NEUTRON_MODE.equals(mode)) {
1719 // Use MsoNeutronUtils for all NEUTRON commands
1720 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1721 long deleteNetworkStarttime = System.currentTimeMillis();
1723 // The deleteNetwork function in MsoNeutronUtils returns success if the network
1724 // was not found. So don't bother to query first.
1725 neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1726 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1727 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1728 "DeleteNetwork", null);
1729 } catch (MsoException me) {
1730 me.addContext("RollbackNetwork");
1731 String error = "Rollback Network (neutron): " + networkId
1738 LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1739 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1741 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1742 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)",
1744 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1745 MsoLogger.ResponseCode.CommunicationError, error);
1746 throw new NetworkException(me);
1748 } else { // DEFAULT to if ("HEAT".equals (mode))
1749 // Use MsoHeatUtils for all HEAT commands
1750 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1751 cloudConfigFactory);
1752 long deleteStackStarttime = System.currentTimeMillis();
1754 // The deleteStack function in MsoHeatUtils returns success if the stack
1755 // was not found. So don't bother to query first.
1756 heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1757 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1758 MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1759 "DeleteStack", null);
1760 } catch (MsoException me) {
1761 me.addContext("RollbackNetwork");
1762 String error = "Rollback Network (heat): " + networkId
1769 LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1770 MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1772 .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1773 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me);
1774 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1775 MsoLogger.ResponseCode.CommunicationError, error);
1776 throw new NetworkException(me);
1781 LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network");
1785 private String validateNetworkParams (NetworkType neutronNetworkType,
1787 String physicalNetwork,
1788 List <Integer> vlans,
1789 List <RouteTarget> routeTargets) {
1791 StringBuilder missing = new StringBuilder ();
1792 if (isNullOrEmpty(networkName)) {
1793 missing.append ("networkName");
1797 if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1798 if (isNullOrEmpty(physicalNetwork)) {
1799 missing.append (sep).append ("physicalNetworkName");
1802 if (vlans == null || vlans.isEmpty ()) {
1803 missing.append (sep).append (VLANS);
1807 return missing.toString ();
1810 private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1812 String physicalNetwork,
1813 List <Integer> vlans,
1814 List <RouteTarget> routeTargets,
1817 boolean aic3template) {
1818 // Build the common set of HEAT template parameters
1819 Map <String, Object> stackParams = new HashMap <> ();
1820 stackParams.put ("network_name", networkName);
1822 if (neutronNetworkType == NetworkType.PROVIDER) {
1823 // For Provider type
1824 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1825 stackParams.put ("vlan", vlans.get (0).toString ());
1826 } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1827 // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1828 // It supports all ProviderNet properties except segmentation_id, and adds a
1829 // comma-separated-list of VLANs as a "segments" property.
1830 // Note that this does not match the Neutron definition of Multi-Provider network,
1831 // which contains a list of 'segments', each having physical_network, network_type,
1832 // and segmentation_id.
1833 StringBuilder buf = new StringBuilder ();
1835 for (Integer vlan : vlans) {
1836 buf.append (sep).append (vlan.toString ());
1839 String csl = buf.toString ();
1841 stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1842 stackParams.put (VLANS, csl);
1845 if (routeTargets != null) {
1847 String rtGlobal = "";
1848 String rtImport = "";
1849 String rtExport = "";
1851 for (RouteTarget rt : routeTargets) {
1852 boolean rtIsNull = false;
1854 String routeTarget = rt.getRouteTarget();
1855 String routeTargetRole = rt.getRouteTargetRole();
1856 LOGGER.debug("Checking for an actually null route target: " + rt.toString());
1857 if (routeTarget == null || routeTarget.equals("") || routeTarget.equalsIgnoreCase("null"))
1859 if (routeTargetRole == null || routeTargetRole.equals("") || routeTargetRole.equalsIgnoreCase("null"))
1866 LOGGER.debug("Input RT:" + rt.toString());
1867 String role = rt.getRouteTargetRole();
1868 String rtValue = rt.getRouteTarget();
1870 if ("IMPORT".equalsIgnoreCase(role))
1872 sep = rtImport.isEmpty() ? "" : ",";
1873 rtImport = aic3template ? rtImport + sep + "target:" + rtValue : rtImport + sep + rtValue ;
1875 else if ("EXPORT".equalsIgnoreCase(role))
1877 sep = rtExport.isEmpty() ? "" : ",";
1878 rtExport = aic3template ? rtExport + sep + "target:" + rtValue : rtExport + sep + rtValue ;
1880 else // covers BOTH, empty etc
1882 sep = rtGlobal.isEmpty() ? "" : ",";
1883 rtGlobal = aic3template ? rtGlobal + sep + "target:" + rtValue : rtGlobal + sep + rtValue ;
1888 if (!rtImport.isEmpty())
1890 stackParams.put ("route_targets_import", rtImport);
1892 if (!rtExport.isEmpty())
1894 stackParams.put ("route_targets_export", rtExport);
1896 if (!rtGlobal.isEmpty())
1898 stackParams.put ("route_targets", rtGlobal);
1901 if (isNullOrEmpty(shared)) {
1902 stackParams.put ("shared", "False");
1904 stackParams.put ("shared", shared);
1906 if (isNullOrEmpty(external)) {
1907 stackParams.put ("external", "False");
1909 stackParams.put ("external", external);
1916 /** policyRef_list structure in stackParams
1919 "network_policy_refs_data_sequence": {
1920 "network_policy_refs_data_sequence_major": "1",
1921 "network_policy_refs_data_sequence_minor": "0"
1925 "network_policy_refs_data_sequence": {
1926 "network_policy_refs_data_sequence_major": "2",
1927 "network_policy_refs_data_sequence_minor": "0"
1932 private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1934 List<ContrailPolicyRef> prlist = new ArrayList <> ();
1936 for (String pf : pFqdns) {
1937 if (!isNullOrEmpty(pf))
1939 ContrailPolicyRef pr = new ContrailPolicyRef();
1940 pr.populate(String.valueOf(index), "0");
1942 LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString());
1947 String jsonString = null;
1948 if (!prlist.isEmpty())
1952 ObjectMapper mapper = new ObjectMapper();
1953 jsonString = mapper.writeValueAsString(prlist);
1954 LOGGER.debug("Json PolicyRefs Data:" + jsonString);
1958 String error = "Error creating JsonNode for policyRefs Data";
1959 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e);
1960 throw new MsoAdapterException (error);
1964 if (pFqdns != null && !isNullOrEmpty(jsonString))
1966 StringBuilder buf = new StringBuilder ();
1968 for (String pf : pFqdns) {
1969 if (!isNullOrEmpty(pf))
1971 buf.append (sep).append (pf);
1975 String csl = buf.toString ();
1976 stackParams.put ("policy_refs", csl);
1977 stackParams.put ("policy_refsdata", jsonString);
1978 LOGGER.debug ("StackParams updated with policy refs:" + csl + " refs data:" + jsonString);
1983 private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1986 if (rtFqdns != null)
1988 StringBuilder buf = new StringBuilder ();
1990 for (String rtf : rtFqdns) {
1991 if (!isNullOrEmpty(rtf))
1993 buf.append (sep).append (rtf);
1997 String csl = buf.toString ();
1998 stackParams.put ("route_table_refs", csl);
2001 LOGGER.debug ("StackParams updated with route_table refs");
2006 /*** Subnet Output structure from Juniper
2011 "ip_prefix": "10.100.1.0",
2014 "addr_from_start": null,
2015 "enable_dhcp": false,
2016 "default_gateway": "10.100.1.1",
2017 "dns_nameservers": [],
2018 "dhcp_option_list": null,
2019 "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
2020 "allocation_pools": [
2022 "start": "10.100.1.3",
2026 "start": "10.100.1.6",
2030 "host_routes": null,
2031 "dns_server_address": "10.100.1.13",
2032 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
2036 "ip_prefix": "10.100.2.16",
2039 "addr_from_start": null,
2040 "enable_dhcp": true,
2041 "default_gateway": "10.100.2.17",
2042 "dns_nameservers": [],
2043 "dhcp_option_list": null,
2044 "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
2045 "allocation_pools": [
2047 "start": "10.100.2.18",
2048 "end": "10.100.2.20"
2051 "host_routes": null,
2052 "dns_server_address": "10.100.2.29",
2053 "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
2059 private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
2062 List<ContrailSubnet> cslist = new ArrayList <> ();
2063 for (Subnet subnet : subnets) {
2064 ContrailSubnet cs = new ContrailSubnet();
2065 LOGGER.debug("Input Subnet:" + subnet.toString());
2066 cs.populateWith(subnet);
2067 LOGGER.debug("Contrail Subnet:" + cs.toString());
2071 String jsonString = null;
2072 if (!cslist.isEmpty())
2076 ObjectMapper mapper = new ObjectMapper();
2077 jsonString = mapper.writeValueAsString(cslist);
2078 LOGGER.debug("Json Subnet List:" + jsonString);
2082 String error = "Error creating JsonNode from input subnets";
2083 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e);
2084 throw new MsoAdapterException (error);
2088 if (!isNullOrEmpty(jsonString))
2090 stackParams.put ("subnet_list", jsonString);
2092 //Outputs - All subnets are in one ipam_subnets structure
2093 String outputTempl = " subnet:\n" + " description: Openstack subnet identifier\n"
2094 + " value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
2096 // append outputs in heatTemplate
2097 int outputsIdx = heatTemplate.indexOf ("outputs:");
2098 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
2099 LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate);
2100 return heatTemplate;
2104 private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
2106 String resourceTempl = " subnet_%subnetId%:\n" + " type: OS::Neutron::Subnet\n"
2109 + " network_id: { get_resource: network }\n"
2110 + " cidr: %cidr%\n";
2112 /* make these optional
2113 + " ip_version: %ipversion%\n"
2114 + " enable_dhcp: %enabledhcp%\n"
2115 + " gateway_ip: %gatewayip%\n"
2116 + " allocation_pools:\n"
2117 + " - start: %poolstart%\n"
2118 + " end: %poolend%\n";
2122 String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n"
2123 + " value: {get_resource: subnet_%subnetId%}\n";
2127 StringBuilder resourcesBuf = new StringBuilder ();
2128 StringBuilder outputsBuf = new StringBuilder ();
2129 for (Subnet subnet : subnets) {
2131 // build template for each subnet
2132 curR = new StringBuilder(resourceTempl);
2133 if (subnet.getSubnetId () != null) {
2134 curR = new StringBuilder(curR.toString().replace("%subnetId%", subnet.getSubnetId()));
2136 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
2137 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID for subnet in HEAT Template");
2138 throw new MsoAdapterException (error);
2141 if (subnet.getSubnetName () != null) {
2142 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetName()));
2144 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetId()));
2147 if (subnet.getCidr () != null) {
2148 curR = new StringBuilder(curR.toString().replace("%cidr%", subnet.getCidr()));
2150 String error = "Missing Required cidr for subnet in HEAT Template";
2151 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template");
2152 throw new MsoAdapterException (error);
2155 if (subnet.getIpVersion () != null) {
2156 curR.append(" ip_version: " + subnet.getIpVersion() + "\n");
2158 if (subnet.getEnableDHCP () != null) {
2159 curR.append(" enable_dhcp: ").append(Boolean.toString(subnet.getEnableDHCP())).append("\n");
2161 if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
2162 curR.append(" gateway_ip: " + subnet.getGatewayIp() + "\n");
2165 if (subnet.getAllocationPools() != null) {
2166 curR.append(" allocation_pools:\n");
2167 for (Pool pool : subnet.getAllocationPools())
2169 if (!isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()))
2171 curR.append(" - start: " + pool.getStart() + "\n");
2172 curR.append(" end: " + pool.getEnd() + "\n");
2177 resourcesBuf.append (curR);
2180 curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
2182 outputsBuf.append (curO);
2185 // append resources and outputs in heatTemplate
2186 LOGGER.debug ("Tempate initial:" + heatTemplate);
2187 int outputsIdx = heatTemplate.indexOf ("outputs:");
2188 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
2189 int resourcesIdx = heatTemplate.indexOf ("resources:");
2190 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
2192 LOGGER.debug ("Template updated with all subnets:" + heatTemplate);
2193 return heatTemplate;
2196 private Map <String, String> getSubnetUUId(String key, Map <String, Object> outputs, List <Subnet> subnets) {
2198 Map <String, String> sMap = new HashMap <> ();
2201 Object obj = outputs.get(key);
2202 ObjectMapper mapper = new ObjectMapper();
2203 String jStr = mapper.writeValueAsString(obj);
2204 LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr);
2206 JsonNode rootNode = mapper.readTree(jStr);
2207 for (JsonNode sNode : rootNode.path("ipam_subnets"))
2209 LOGGER.debug("Output Subnet Node" + sNode.toString());
2210 String name = sNode.path("subnet_name").textValue();
2211 String uuid = sNode.path("subnet_uuid").textValue();
2212 String aaiId = name; // default
2213 // try to find aaiId for name in input subnetList
2214 if (subnets != null)
2216 for (Subnet subnet : subnets)
2218 if ( subnet != null && !isNullOrEmpty(subnet.getSubnetName()))
2220 if (subnet.getSubnetName().equals(name))
2222 aaiId = subnet.getSubnetId();
2228 sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
2233 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e);
2236 LOGGER.debug ("Return sMap" + sMap.toString());
2240 private static String insertStr (String template, String snippet, int index) {
2242 String updatedTemplate;
2244 LOGGER.debug ("Index:" + index + " Snippet:" + snippet);
2246 String templateBeg = template.substring (0, index);
2247 String templateEnd = template.substring (index);
2249 updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
2251 LOGGER.debug ("Template updated with a subnet:" + updatedTemplate);
2252 return updatedTemplate;