[NSX-v3] Use bridge endpoint profiles for L2 gateways
Replace NSX bridge cluster with bridge endpoint profiles as the backend resource used to implement L2 gateways. The logic for creating a gateway connection is not changed, with the only exception that bridge endpoints now have a reference to a bridge endpoint profile. Connections created using bridge clusters can be safely removed, while creation of new connection on gateways leveraging bridge clusters will fail. Change-Id: I29cd9a2501ab4b7dd226729f33ab962bbba2dfff
This commit is contained in:
parent
0be608d8b0
commit
0a952ce786
@ -417,6 +417,7 @@ nsx_v3_opts = nsx_v3_and_p + [
|
|||||||
"Neutron networks, if no physical network has been "
|
"Neutron networks, if no physical network has been "
|
||||||
"specified")),
|
"specified")),
|
||||||
cfg.StrOpt('default_bridge_cluster',
|
cfg.StrOpt('default_bridge_cluster',
|
||||||
|
deprecated_for_removal=True,
|
||||||
help=_("(Optional) Name or UUID of the default NSX bridge "
|
help=_("(Optional) Name or UUID of the default NSX bridge "
|
||||||
"cluster that will be used to perform L2 gateway "
|
"cluster that will be used to perform L2 gateway "
|
||||||
"bridging between VXLAN and VLAN networks. If default "
|
"bridging between VXLAN and VLAN networks. If default "
|
||||||
@ -425,6 +426,13 @@ nsx_v3_opts = nsx_v3_and_p + [
|
|||||||
"NSX Bridge Cluster using L2 gateway APIs. This field "
|
"NSX Bridge Cluster using L2 gateway APIs. This field "
|
||||||
"must be specified on one of the active neutron "
|
"must be specified on one of the active neutron "
|
||||||
"servers only.")),
|
"servers only.")),
|
||||||
|
cfg.StrOpt('default_bridge_endpoint_profile',
|
||||||
|
help=_("(Optional) Name or UUID of the default NSX bridge "
|
||||||
|
"endpoint profile that will be used to perform L2 "
|
||||||
|
"bridging between networks in the NSX fabric and "
|
||||||
|
"VLANs external to NSX. If not specified, operators "
|
||||||
|
"will need to explictly create a layer-2 gateway in "
|
||||||
|
"Neutron using the L2 gateway APIs.")),
|
||||||
cfg.StrOpt('default_tier0_router',
|
cfg.StrOpt('default_tier0_router',
|
||||||
help=_("Name or UUID of the default tier0 router that will be "
|
help=_("Name or UUID of the default tier0 router that will be "
|
||||||
"used for connecting to tier1 logical routers and "
|
"used for connecting to tier1 logical routers and "
|
||||||
|
@ -76,6 +76,11 @@ class L2GatewayAlreadyInUse(n_exc.Conflict):
|
|||||||
message = _("Gateway Service %(gateway)s is already in use")
|
message = _("Gateway Service %(gateway)s is already in use")
|
||||||
|
|
||||||
|
|
||||||
|
class BridgeEndpointAttachmentInUse(n_exc.Conflict):
|
||||||
|
message = _("The NSX backend only allow a single L2 gateway connection "
|
||||||
|
"for network %(network_id)s")
|
||||||
|
|
||||||
|
|
||||||
class InvalidTransportType(NsxPluginException):
|
class InvalidTransportType(NsxPluginException):
|
||||||
message = _("The transport type %(transport_type)s is not recognized "
|
message = _("The transport type %(transport_type)s is not recognized "
|
||||||
"by the backend")
|
"by the backend")
|
||||||
|
@ -391,11 +391,6 @@ def get_l2gw_connection_mapping(session, connection_id):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_l2gw_connection_mappings_by_bridge(session, bridge_endpoint_id):
|
|
||||||
return (session.query(nsx_models.NsxL2GWConnectionMapping).
|
|
||||||
filter_by(bridge_endpoint_id=bridge_endpoint_id).all())
|
|
||||||
|
|
||||||
|
|
||||||
# NSXv3 QoS policy id <-> switch Id mapping
|
# NSXv3 QoS policy id <-> switch Id mapping
|
||||||
def add_qos_policy_profile_mapping(session, qos_policy_id, switch_profile_id):
|
def add_qos_policy_profile_mapping(session, qos_policy_id, switch_profile_id):
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
|
@ -1409,6 +1409,9 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
|
|||||||
# (for example - transport zone with KVM)
|
# (for example - transport zone with KVM)
|
||||||
LOG.exception("Unable to create port on the backend: %s",
|
LOG.exception("Unable to create port on the backend: %s",
|
||||||
inst)
|
inst)
|
||||||
|
if inst.error_code == 8407:
|
||||||
|
raise nsx_exc.BridgeEndpointAttachmentInUse(
|
||||||
|
network_id=port_data['network_id'])
|
||||||
msg = _("Unable to create port on the backend")
|
msg = _("Unable to create port on the backend")
|
||||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||||
|
|
||||||
|
@ -40,18 +40,22 @@ from vmware_nsx.db import db as nsx_db
|
|||||||
from vmware_nsx.extensions import projectpluginmap
|
from vmware_nsx.extensions import projectpluginmap
|
||||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
from vmware_nsxlib.v3 import nsx_constants
|
from vmware_nsxlib.v3 import nsx_constants
|
||||||
|
from vmware_nsxlib.v3 import utils as nsxlib_utils
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class _NotUniqueL2GW(Exception):
|
||||||
|
"""Raised if validation of default L2 GW uniqueness fails."""
|
||||||
|
|
||||||
|
|
||||||
class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
||||||
|
|
||||||
"""Class to handle API calls for L2 gateway and NSXv3 backend."""
|
"""Class to handle API calls for L2 gateway and NSXv3 backend."""
|
||||||
gateway_resource = l2gw_const.GATEWAY_RESOURCE_NAME
|
gateway_resource = l2gw_const.GATEWAY_RESOURCE_NAME
|
||||||
|
|
||||||
def __init__(self, plugin):
|
def __init__(self, plugin):
|
||||||
# Create a default L2 gateway if default_bridge_cluster is
|
|
||||||
# provided in nsx.ini
|
|
||||||
super(NsxV3Driver, self).__init__()
|
super(NsxV3Driver, self).__init__()
|
||||||
self._plugin = plugin
|
self._plugin = plugin
|
||||||
LOG.debug("Starting service plugin for NSX L2Gateway")
|
LOG.debug("Starting service plugin for NSX L2Gateway")
|
||||||
@ -75,62 +79,142 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
registry.subscribe(self._ensure_default_l2_gateway, resources.PROCESS,
|
registry.subscribe(self._ensure_default_l2_gateway, resources.PROCESS,
|
||||||
events.BEFORE_SPAWN)
|
events.BEFORE_SPAWN)
|
||||||
|
|
||||||
|
def _find_default_l2_gateway(self, admin_ctx, def_device_id):
|
||||||
|
for l2gateway in self._get_l2_gateways(admin_ctx):
|
||||||
|
if l2gateway['devices'][0]['device_name'] == def_device_id:
|
||||||
|
return l2gateway
|
||||||
|
|
||||||
|
@nsxlib_utils.retry_random_upon_exception(_NotUniqueL2GW, max_attempts=10)
|
||||||
|
def _create_default_l2_gateway(self, admin_ctx, l2gw_dict, def_device_id):
|
||||||
|
LOG.debug("Creating default layer-2 gateway with: %s", l2gw_dict)
|
||||||
|
def_l2gw = super(NsxV3Driver, self).create_l2_gateway(admin_ctx,
|
||||||
|
l2gw_dict)
|
||||||
|
# Verify that no other instance of neutron-server had the same
|
||||||
|
# brilliant idea...
|
||||||
|
l2gateways = self._get_l2_gateways(admin_ctx)
|
||||||
|
for l2gateway in l2gateways:
|
||||||
|
# Since we ensure L2 gateway is created with only 1 device, we use
|
||||||
|
# the first device in the list.
|
||||||
|
if l2gateway['devices'][0]['device_name'] == def_device_id:
|
||||||
|
if l2gateway['id'] == def_l2gw['id']:
|
||||||
|
# Nothing to worry about, that's our gateway
|
||||||
|
continue
|
||||||
|
LOG.info("Default L2 gateway is already created with "
|
||||||
|
"id %s, deleting L2 gateway with id %s",
|
||||||
|
l2gateway['id'], def_l2gw['id'])
|
||||||
|
# Commit suicide!
|
||||||
|
self.validate_l2_gateway_for_delete(
|
||||||
|
admin_ctx, def_l2gw)
|
||||||
|
# We can be sure the gateway is not in use...
|
||||||
|
super(NsxV3Driver, self).delete_l2_gateway(
|
||||||
|
admin_ctx, def_l2gw['id'])
|
||||||
|
# The operation should be retried to avoid the situation where
|
||||||
|
# every instance deletes the gateway it created
|
||||||
|
raise _NotUniqueL2GW
|
||||||
|
|
||||||
|
return def_l2gw
|
||||||
|
|
||||||
|
def _get_bridge_vlan_tz_id(self, bep_data):
|
||||||
|
nsxlib = self._core_plugin.nsxlib
|
||||||
|
# Edge cluster Id is mandatory, do not fear KeyError
|
||||||
|
edge_cluster_id = bep_data['edge_cluster_id']
|
||||||
|
member_indexes = bep_data.get('edge_cluster_member_indexes', [])
|
||||||
|
# NSX should not allow bridge endpoint profiles attached to
|
||||||
|
# non-existing edge clusters
|
||||||
|
edge_cluster = nsxlib.edge_cluster.get(edge_cluster_id)
|
||||||
|
member_map = dict((member['member_index'],
|
||||||
|
member['transport_node_id'])
|
||||||
|
for member in edge_cluster['members'])
|
||||||
|
# By default consider all transport nodes in the cluster for
|
||||||
|
# retrieving the VLAN transprtzone
|
||||||
|
tn_ids = member_map.values()
|
||||||
|
if member_indexes:
|
||||||
|
try:
|
||||||
|
tn_ids = [member_map[idx] for idx in member_indexes]
|
||||||
|
except KeyError:
|
||||||
|
LOG.warning("Invalid member indexes specified in bridge "
|
||||||
|
"endpoint profile: %(bep_id)s: %(indexes)s",
|
||||||
|
{'bep_id': bep_data['id'],
|
||||||
|
'indexes': member_indexes})
|
||||||
|
|
||||||
|
# Retrieve VLAN transport zones
|
||||||
|
vlan_transport_zones = nsxlib.search_all_resource_by_attributes(
|
||||||
|
nsxlib.transport_zone.resource_type,
|
||||||
|
transport_type='VLAN')
|
||||||
|
vlan_tz_map = dict((vlan_tz['id'], [])
|
||||||
|
for vlan_tz in vlan_transport_zones)
|
||||||
|
for tn_id in tn_ids:
|
||||||
|
tn_data = nsxlib.transport_node.get(tn_id)
|
||||||
|
for tz_endpoint in tn_data.get('transport_zone_endpoints', []):
|
||||||
|
tz_id = tz_endpoint['transport_zone_id']
|
||||||
|
if tz_id in vlan_tz_map:
|
||||||
|
vlan_tz_map[tz_id].append(tn_id)
|
||||||
|
|
||||||
|
# Find the VLAN transport zone that is used by all transport nodes
|
||||||
|
results = []
|
||||||
|
for (tz_id, nodes) in vlan_tz_map.items():
|
||||||
|
if set(nodes) != set(tn_ids):
|
||||||
|
continue
|
||||||
|
results.append(tz_id)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
def _ensure_default_l2_gateway(self, resource, event,
|
def _ensure_default_l2_gateway(self, resource, event,
|
||||||
trigger, payload=None):
|
trigger, payload=None):
|
||||||
"""
|
"""
|
||||||
Create a default logical L2 gateway.
|
Create a default logical L2 gateway.
|
||||||
|
|
||||||
Create a logical L2 gateway in the neutron database if the
|
Create a logical L2 gateway in the neutron database for the
|
||||||
default_bridge_cluster config parameter is set and if it is
|
default bridge endpoint profile, if specified in the configuration.
|
||||||
not previously created. If not set, return.
|
Ensure only one gateway is configured in presence of multiple
|
||||||
|
neutron servers.
|
||||||
"""
|
"""
|
||||||
def_l2gw_name = cfg.CONF.nsx_v3.default_bridge_cluster
|
if cfg.CONF.nsx_v3.default_bridge_cluster:
|
||||||
# Return if no default_bridge_cluster set in config
|
LOG.warning("Attention! The default_bridge_cluster option is "
|
||||||
if not def_l2gw_name:
|
"still set to %s. This option won't have any effect "
|
||||||
LOG.info("NSX: Default bridge cluster not configured "
|
"as L2 gateways based on bridge clusters are not "
|
||||||
"in nsx.ini. No default L2 gateway created.")
|
"implemented anymore",
|
||||||
|
cfg.CONF.nsx_v3.default_bridge_cluster)
|
||||||
|
def_bep = cfg.CONF.nsx_v3.default_bridge_endpoint_profile
|
||||||
|
# Return if no default_endpoint_profile set in config
|
||||||
|
if not def_bep:
|
||||||
|
LOG.info("NSX Default bridge endpoint profile not set. "
|
||||||
|
"Default L2 gateway will not be processed.")
|
||||||
return
|
return
|
||||||
admin_ctx = context.get_admin_context()
|
admin_ctx = context.get_admin_context()
|
||||||
|
nsx_bep_client = self._core_plugin.nsxlib.bridge_endpoint_profile
|
||||||
def_l2gw_uuid = (
|
bep_id = nsx_bep_client.get_id_by_name_or_id(def_bep)
|
||||||
self._core_plugin.nsxlib.bridge_cluster.get_id_by_name_or_id(
|
def_l2gw = self._find_default_l2_gateway(admin_ctx, bep_id)
|
||||||
def_l2gw_name))
|
# If there is already an existing gateway, use that one
|
||||||
|
if def_l2gw:
|
||||||
# Optimistically create the default L2 gateway in neutron DB
|
LOG.info("A default L2 gateway for bridge endpoint profile "
|
||||||
device = {'device_name': def_l2gw_uuid,
|
"%(bep_id)s already exists. Reusing L2 gateway "
|
||||||
'interfaces': [{'name': 'default-bridge-cluster'}]}
|
"%(def_l2gw_id)s)",
|
||||||
|
{'bep_id': bep_id, 'def_l2gw_id': def_l2gw['id']})
|
||||||
|
return def_l2gw
|
||||||
|
bep_data = nsx_bep_client.get(bep_id)
|
||||||
|
vlan_tzs = self._get_bridge_vlan_tz_id(bep_data)
|
||||||
|
if not vlan_tzs:
|
||||||
|
LOG.info("No NSX VLAN transport zone could be used for bridge "
|
||||||
|
"endpoint profile: %s. Default L2 gateway will not "
|
||||||
|
"be processed", bep_id)
|
||||||
|
return
|
||||||
|
# TODO(salv-orlando): Implement support for multiple VLAN TZ
|
||||||
|
vlan_tz = vlan_tzs[0]
|
||||||
|
if len(vlan_tzs) > 1:
|
||||||
|
LOG.info("The NSX L2 gateway driver currenly supports a single "
|
||||||
|
"VLAN transport zone for bridging, but %(num_tz)d "
|
||||||
|
"were specified. Transport zone %(tz)s will be used "
|
||||||
|
"for L2 gateways",
|
||||||
|
{'num_tz': len(vlan_tzs), 'tz': vlan_tz})
|
||||||
|
device = {'device_name': bep_id,
|
||||||
|
'interfaces': [{'name': vlan_tz}]}
|
||||||
# TODO(asarfaty): Add a default v3 tenant-id to allow TVD filtering
|
# TODO(asarfaty): Add a default v3 tenant-id to allow TVD filtering
|
||||||
def_l2gw = {'name': 'default-l2gw',
|
l2gw_dict = {self.gateway_resource: {
|
||||||
'devices': [device]}
|
'name': 'default-nsxedge-l2gw',
|
||||||
l2gw_dict = {self.gateway_resource: def_l2gw}
|
'devices': [device]}}
|
||||||
self.create_l2_gateway(admin_ctx, l2gw_dict)
|
self._create_default_l2_gateway(admin_ctx, l2gw_dict, bep_id)
|
||||||
l2_gateway = super(NsxV3Driver, self).create_l2_gateway(admin_ctx,
|
return def_l2gw
|
||||||
l2gw_dict)
|
|
||||||
# Verify that only one default L2 gateway is created
|
|
||||||
def_l2gw_exists = False
|
|
||||||
l2gateways = self._get_l2_gateways(admin_ctx)
|
|
||||||
for l2gateway in l2gateways:
|
|
||||||
# Since we ensure L2 gateway is created with only 1 device, we use
|
|
||||||
# the first device in the list.
|
|
||||||
if l2gateway['devices'][0]['device_name'] == def_l2gw_uuid:
|
|
||||||
if def_l2gw_exists:
|
|
||||||
LOG.info("Default L2 gateway is already created.")
|
|
||||||
try:
|
|
||||||
# Try deleting this duplicate default L2 gateway
|
|
||||||
self.validate_l2_gateway_for_delete(
|
|
||||||
admin_ctx, l2gateway['id'])
|
|
||||||
super(NsxV3Driver, self).delete_l2_gateway(
|
|
||||||
admin_ctx, l2gateway['id'])
|
|
||||||
except l2gw_exc.L2GatewayInUse:
|
|
||||||
# If the L2 gateway we are trying to delete is in
|
|
||||||
# use then we should delete the L2 gateway which
|
|
||||||
# we just created ensuring there is only one
|
|
||||||
# default L2 gateway in the database.
|
|
||||||
super(NsxV3Driver, self).delete_l2_gateway(
|
|
||||||
admin_ctx, l2_gateway['id'])
|
|
||||||
else:
|
|
||||||
def_l2gw_exists = True
|
|
||||||
return l2_gateway
|
|
||||||
|
|
||||||
def _prevent_l2gw_port_delete(self, resource, event,
|
def _prevent_l2gw_port_delete(self, resource, event,
|
||||||
trigger, payload=None):
|
trigger, payload=None):
|
||||||
@ -140,30 +224,34 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
if port_check:
|
if port_check:
|
||||||
self.prevent_l2gw_port_deletion(context, port_id)
|
self.prevent_l2gw_port_deletion(context, port_id)
|
||||||
|
|
||||||
def _validate_device_list(self, devices):
|
def _validate_device_list(self, devices, check_backend=True):
|
||||||
# In NSXv3, one L2 gateway is mapped to one bridge cluster.
|
# In NSXv3, one L2 gateway is mapped to one bridge endpoint profle.
|
||||||
# So we expect only one device to be configured as part of
|
# So we expect only one device to be configured as part of
|
||||||
# a L2 gateway resource. The name of the device must be the bridge
|
# a L2 gateway resource. The name of the device must be the bridge
|
||||||
# cluster's UUID.
|
# endpoint profile UUID.
|
||||||
if len(devices) != 1:
|
if len(devices) != 1:
|
||||||
msg = _("Only a single device is supported for one L2 gateway")
|
msg = _("Only a single device is supported by the NSX L2"
|
||||||
|
"gateway driver")
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
if not uuidutils.is_uuid_like(devices[0]['device_name']):
|
dev_name = devices[0]['device_name']
|
||||||
|
if not uuidutils.is_uuid_like(dev_name):
|
||||||
msg = _("Device name must be configured with a UUID")
|
msg = _("Device name must be configured with a UUID")
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
# Make sure the L2GW device ID exists as Bridge Cluster on NSX.
|
# Ensure the L2GW device is a valid bridge endpoint profile in NSX
|
||||||
|
if check_backend:
|
||||||
try:
|
try:
|
||||||
self._core_plugin.nsxlib.bridge_cluster.get(
|
self._core_plugin.nsxlib.bridge_endpoint_profile.get(
|
||||||
devices[0]['device_name'])
|
dev_name)
|
||||||
except nsxlib_exc.ResourceNotFound:
|
except nsxlib_exc.ResourceNotFound:
|
||||||
msg = _("Could not find Bridge Cluster for L2 gateway device "
|
msg = _("Could not find Bridge Endpoint Profile for L2 "
|
||||||
"%s on NSX backend") % devices[0]['device_name']
|
"gateway device %s on NSX backend") % dev_name
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
# One L2 gateway must have only one interface defined.
|
# One L2 gateway must have only one interface defined.
|
||||||
interfaces = devices[0].get(l2gw_const.IFACE_NAME_ATTR)
|
interfaces = devices[0].get(l2gw_const.IFACE_NAME_ATTR)
|
||||||
if len(interfaces) > 1:
|
if len(interfaces) > 1:
|
||||||
msg = _("Maximum of one interface is supported for one L2 gateway")
|
msg = _("Maximum of one interface is supported by the NSX L2 "
|
||||||
|
"gateway driver")
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
|
|
||||||
def create_l2_gateway(self, context, l2_gateway):
|
def create_l2_gateway(self, context, l2_gateway):
|
||||||
@ -196,10 +284,9 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
def _validate_network(self, context, network_id):
|
def _validate_network(self, context, network_id):
|
||||||
network = self._core_plugin.get_network(context, network_id)
|
network = self._core_plugin.get_network(context, network_id)
|
||||||
network_type = network.get(providernet.NETWORK_TYPE)
|
network_type = network.get(providernet.NETWORK_TYPE)
|
||||||
# If network is a provider network, verify whether it is of type VXLAN
|
# If network is a provider network, verify whether it is of type GENEVE
|
||||||
if network_type and network_type != nsx_utils.NsxV3NetworkTypes.VXLAN:
|
if network_type and network_type != nsx_utils.NsxV3NetworkTypes.GENEVE:
|
||||||
msg = (_("Unsupported network type %s for L2 gateway "
|
msg = (_("Unsupported network type %s for L2 gateway connection") %
|
||||||
"connection. Only VXLAN network type supported") %
|
|
||||||
network_type)
|
network_type)
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
|
|
||||||
@ -213,33 +300,67 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
|
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
|
||||||
self._validate_network(context, network_id)
|
self._validate_network(context, network_id)
|
||||||
|
|
||||||
def _get_bridge_cluster(self, context, l2gw_id):
|
def _get_bep(self, context, l2gw_id):
|
||||||
# In NSXv3, there will be only one device configured per L2 gateway.
|
# In NSXv3, there will be only one device configured per L2 gateway.
|
||||||
# The name of the device shall carry the backend bridge cluster's UUID.
|
# The name of the device shall carry the bridge endpoint profile id.
|
||||||
devices = self._get_l2_gateway_devices(context, l2gw_id)
|
devices = self._get_l2_gateway_devices(context, l2gw_id)
|
||||||
return devices[0].get('device_name')
|
return devices[0].get('device_name')
|
||||||
|
|
||||||
def _get_conn_seg_id(self, context, gw_connection):
|
def _get_conn_parameters(self, context, gw_connection):
|
||||||
|
"""Return interface and segmenantion id for a connection. """
|
||||||
if not gw_connection:
|
if not gw_connection:
|
||||||
return
|
return
|
||||||
|
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
||||||
seg_id = gw_connection.get(l2gw_const.SEG_ID)
|
seg_id = gw_connection.get(l2gw_const.SEG_ID)
|
||||||
|
devices = self._get_l2_gateway_devices(context, l2gw_id)
|
||||||
|
# TODO(salv-orlando): support more than a single interface
|
||||||
|
interface = self._get_l2_gw_interfaces(context, devices[0]['id'])[0]
|
||||||
if not seg_id:
|
if not seg_id:
|
||||||
# Seg-id was not passed as part of connection-create. Retrieve
|
# Seg-id was not passed as part of connection-create. Retrieve
|
||||||
# seg-id from L2 gateway's interface.
|
# seg-id from L2 gateway's interface.
|
||||||
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
seg_id = interface.get('segmentation_id')
|
||||||
devices = self._get_l2_gateway_devices(context, l2gw_id)
|
return interface['interface_name'], seg_id
|
||||||
interface = self._get_l2_gw_interfaces(context, devices[0]['id'])
|
|
||||||
seg_id = interface[0].get(l2gw_const.SEG_ID)
|
|
||||||
return seg_id
|
|
||||||
|
|
||||||
def create_l2_gateway_connection_precommit(self, context, gw_connection):
|
def create_l2_gateway_connection_precommit(self, context, gw_connection):
|
||||||
"""Validate the L2 gateway connection
|
"""Validate the L2 gateway connection
|
||||||
Do not allow another connection with the same bride cluster and seg_id
|
Do not allow another connection with the same bride cluster and seg_id
|
||||||
"""
|
"""
|
||||||
admin_ctx = context.elevated()
|
admin_ctx = context.elevated()
|
||||||
|
nsxlib = self._core_plugin.nsxlib
|
||||||
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
||||||
seg_id = self._get_conn_seg_id(admin_ctx, gw_connection)
|
devices = self._get_l2_gateway_devices(context, l2gw_id)
|
||||||
bridge_cluster = self._get_bridge_cluster(admin_ctx, l2gw_id)
|
bep_id = devices[0].get('device_name')
|
||||||
|
# Check for bridge endpoint profile existence
|
||||||
|
# if bridge endpoint profile is not found, this is likely an old
|
||||||
|
# connection, fail with error.
|
||||||
|
try:
|
||||||
|
nsxlib.bridge_endpoint_profile.get_id_by_name_or_id(bep_id)
|
||||||
|
except nsxlib_exc.ManagerError as e:
|
||||||
|
msg = (_("Error while retrieving bridge endpoint profile "
|
||||||
|
"%(bep_id)s from NSX backend. Check that the profile "
|
||||||
|
"exits and there are not multiple profiles with "
|
||||||
|
"the given name. Exception: %(exc)s") %
|
||||||
|
{'bep_id': bep_id, 'exc': e})
|
||||||
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
|
|
||||||
|
interface_name, seg_id = self._get_conn_parameters(
|
||||||
|
admin_ctx, gw_connection)
|
||||||
|
try:
|
||||||
|
# Use search API for listing bridge endpoints on NSX for provided
|
||||||
|
# VLAN id, transport zone id, and Bridge endpoint profile
|
||||||
|
endpoints = nsxlib.search_all_resource_by_attributes(
|
||||||
|
nsxlib.bridge_endpoint.resource_type,
|
||||||
|
bridge_endpoint_profile_id=bep_id,
|
||||||
|
vlan_transport_zone_id=interface_name,
|
||||||
|
vlan=seg_id)
|
||||||
|
endpoint_map = dict((endpoint['id'],
|
||||||
|
endpoint['bridge_endpoint_profile_id'])
|
||||||
|
for endpoint in endpoints)
|
||||||
|
except nsxlib_exc.ManagerError as e:
|
||||||
|
msg = (_("Error while retrieving endpoints for bridge endpoint "
|
||||||
|
"profile %(bep_id)s s from NSX backend. "
|
||||||
|
"Exception: %(exc)s") % {'bep_id': bep_id, 'exc': e})
|
||||||
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
|
|
||||||
# get all bridge endpoint ports
|
# get all bridge endpoint ports
|
||||||
with db_api.CONTEXT_WRITER.using(admin_ctx):
|
with db_api.CONTEXT_WRITER.using(admin_ctx):
|
||||||
@ -247,65 +368,55 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
ports = self._core_plugin.get_ports(
|
ports = self._core_plugin.get_ports(
|
||||||
admin_ctx, filters=port_filters)
|
admin_ctx, filters=port_filters)
|
||||||
for port in ports:
|
for port in ports:
|
||||||
# get the nsx mapping by bridge endpoint
|
device_id = port.get('device_id')
|
||||||
if port.get('device_id'):
|
if endpoint_map.get(device_id) == bep_id:
|
||||||
mappings = nsx_db.get_l2gw_connection_mappings_by_bridge(
|
# This device is using the same vlan id and bridge endpoint
|
||||||
admin_ctx.session, port['device_id'])
|
# profile as the one requested. Not ok.
|
||||||
for mapping in mappings:
|
msg = (_("Cannot create multiple connections with the "
|
||||||
conn_id = mapping.connection_id
|
"same segmentation id %(seg_id)s for bridge "
|
||||||
# get the matching GW connection
|
"endpoint profile %(bep_id)s") %
|
||||||
conn = self._get_l2_gateway_connection(
|
{'seg_id': seg_id,
|
||||||
admin_ctx, conn_id)
|
'bep_id': bep_id})
|
||||||
con_seg_id = self._get_conn_seg_id(admin_ctx, conn)
|
|
||||||
if (conn and con_seg_id and
|
|
||||||
int(con_seg_id) == int(seg_id)):
|
|
||||||
# compare the bridge cluster
|
|
||||||
conn_bridge_cluster = self._get_bridge_cluster(
|
|
||||||
admin_ctx, conn.l2_gateway_id)
|
|
||||||
if conn_bridge_cluster == bridge_cluster:
|
|
||||||
msg = (_("Cannot create multiple connections "
|
|
||||||
"with the same segmentation id "
|
|
||||||
"%(seg_id)s for bridge cluster "
|
|
||||||
"%(bridge)s") % {
|
|
||||||
'seg_id': seg_id,
|
|
||||||
'bridge': bridge_cluster})
|
|
||||||
raise n_exc.InvalidInput(error_message=msg)
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
|
|
||||||
def create_l2_gateway_connection_postcommit(self, context, gw_connection):
|
def create_l2_gateway_connection_postcommit(self, context, gw_connection):
|
||||||
"""Create a L2 gateway connection."""
|
"""Create a L2 gateway connection on the backend"""
|
||||||
|
nsxlib = self._core_plugin.nsxlib
|
||||||
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID)
|
||||||
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
|
network_id = gw_connection.get(l2gw_const.NETWORK_ID)
|
||||||
device_name = self._get_bridge_cluster(context, l2gw_id)
|
device_name = self._get_bep(context, l2gw_id)
|
||||||
seg_id = self._get_conn_seg_id(context, gw_connection)
|
interface_name, seg_id = self._get_conn_parameters(
|
||||||
|
context, gw_connection)
|
||||||
self._validate_segment_id(seg_id)
|
self._validate_segment_id(seg_id)
|
||||||
tenant_id = gw_connection['tenant_id']
|
tenant_id = gw_connection['tenant_id']
|
||||||
if context.is_admin and not tenant_id:
|
if context.is_admin and not tenant_id:
|
||||||
tenant_id = context.tenant_id
|
tenant_id = context.tenant_id
|
||||||
gw_connection['tenant_id'] = tenant_id
|
gw_connection['tenant_id'] = tenant_id
|
||||||
try:
|
try:
|
||||||
tags = self._core_plugin.nsxlib.build_v3_tags_payload(
|
tags = nsxlib.build_v3_tags_payload(
|
||||||
gw_connection, resource_type='os-neutron-l2gw-id',
|
gw_connection, resource_type='os-neutron-l2gw-id',
|
||||||
project_name=context.tenant_name)
|
project_name=context.tenant_name)
|
||||||
bridge_endpoint = self._core_plugin.nsxlib.bridge_endpoint.create(
|
bridge_endpoint = nsxlib.bridge_endpoint.create(
|
||||||
device_name=device_name,
|
device_name=device_name,
|
||||||
seg_id=seg_id,
|
vlan_transport_zone_id=interface_name,
|
||||||
|
vlan_id=seg_id,
|
||||||
tags=tags)
|
tags=tags)
|
||||||
except nsxlib_exc.ManagerError as e:
|
except nsxlib_exc.ManagerError as e:
|
||||||
LOG.exception("Unable to create bridge endpoint, rolling back "
|
LOG.exception("Unable to create bridge endpoint. "
|
||||||
"changes on neutron. Exception is %s", e)
|
"Exception is %s", e)
|
||||||
raise l2gw_exc.L2GatewayServiceDriverError(
|
raise l2gw_exc.L2GatewayServiceDriverError(
|
||||||
method='create_l2_gateway_connection_postcommit')
|
method='create_l2_gateway_connection_postcommit')
|
||||||
#TODO(abhiraut): Consider specifying the name of the port
|
|
||||||
# Create a logical port and connect it to the bridge endpoint.
|
|
||||||
port_dict = {'port': {
|
port_dict = {'port': {
|
||||||
|
'name': 'l2gw-conn-%s-%s' % (
|
||||||
|
l2gw_id, seg_id),
|
||||||
'tenant_id': tenant_id,
|
'tenant_id': tenant_id,
|
||||||
'network_id': network_id,
|
'network_id': network_id,
|
||||||
'mac_address': constants.ATTR_NOT_SPECIFIED,
|
'mac_address': constants.ATTR_NOT_SPECIFIED,
|
||||||
'admin_state_up': True,
|
'admin_state_up': True,
|
||||||
'fixed_ips': [],
|
'fixed_ips': [],
|
||||||
'device_id': bridge_endpoint['id'],
|
'device_id': bridge_endpoint['id'],
|
||||||
'device_owner': nsx_constants.BRIDGE_ENDPOINT,
|
'device_owner': nsx_constants.BRIDGE_ENDPOINT}}
|
||||||
'name': '', }}
|
|
||||||
try:
|
try:
|
||||||
#TODO(abhiraut): Consider adding UT for port check once UTs are
|
#TODO(abhiraut): Consider adding UT for port check once UTs are
|
||||||
# refactored
|
# refactored
|
||||||
@ -319,12 +430,16 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
LOG.debug("IP addresses deallocated on port %s", port['id'])
|
LOG.debug("IP addresses deallocated on port %s", port['id'])
|
||||||
except (nsxlib_exc.ManagerError,
|
except (nsxlib_exc.ManagerError,
|
||||||
n_exc.NeutronException) as e:
|
n_exc.NeutronException) as e:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.exception("Unable to create L2 gateway port, "
|
LOG.exception("Unable to create L2 gateway port, "
|
||||||
"rolling back changes on neutron: %s", e)
|
"rolling back changes on backend: %s", e)
|
||||||
self._core_plugin.nsxlib.bridge_endpoint.delete(
|
self._core_plugin.nsxlib.bridge_endpoint.delete(
|
||||||
bridge_endpoint['id'])
|
bridge_endpoint['id'])
|
||||||
raise l2gw_exc.L2GatewayServiceDriverError(
|
super(NsxV3Driver,
|
||||||
method='create_l2_gateway_connection_postcommit')
|
self).delete_l2_gateway_connection(
|
||||||
|
context,
|
||||||
|
gw_connection['id'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Update neutron's database with the mappings.
|
# Update neutron's database with the mappings.
|
||||||
nsx_db.add_l2gw_connection_mapping(
|
nsx_db.add_l2gw_connection_mapping(
|
||||||
@ -335,7 +450,10 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin):
|
|||||||
except db_exc.DBError:
|
except db_exc.DBError:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.exception("Unable to add L2 gateway connection "
|
LOG.exception("Unable to add L2 gateway connection "
|
||||||
"mappings, rolling back changes on neutron")
|
"mappings for %(conn_id)s on network "
|
||||||
|
"%(net_id)s. rolling back changes.",
|
||||||
|
{'conn_id': gw_connection['id'],
|
||||||
|
'net_id': network_id})
|
||||||
self._core_plugin.nsxlib.bridge_endpoint.delete(
|
self._core_plugin.nsxlib.bridge_endpoint.delete(
|
||||||
bridge_endpoint['id'])
|
bridge_endpoint['id'])
|
||||||
super(NsxV3Driver,
|
super(NsxV3Driver,
|
||||||
|
@ -121,11 +121,6 @@ def _mock_nsx_backend_calls():
|
|||||||
"create_port_mirror_profile",
|
"create_port_mirror_profile",
|
||||||
side_effect=_return_id_key).start()
|
side_effect=_return_id_key).start()
|
||||||
|
|
||||||
mock.patch(
|
|
||||||
"vmware_nsxlib.v3.core_resources.NsxLibBridgeCluster."
|
|
||||||
"get_id_by_name_or_id",
|
|
||||||
return_value=uuidutils.generate_uuid()).start()
|
|
||||||
|
|
||||||
mock.patch(
|
mock.patch(
|
||||||
"vmware_nsxlib.v3.core_resources.NsxLibBridgeEndpoint.create",
|
"vmware_nsxlib.v3.core_resources.NsxLibBridgeEndpoint.create",
|
||||||
side_effect=_return_id_key).start()
|
side_effect=_return_id_key).start()
|
||||||
|
@ -25,21 +25,23 @@ from oslo_utils import importutils
|
|||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
|
from neutron_lib.api.definitions import provider_net as providernet
|
||||||
from neutron_lib.callbacks import events
|
from neutron_lib.callbacks import events
|
||||||
from neutron_lib.callbacks import registry
|
from neutron_lib.callbacks import registry
|
||||||
from neutron_lib.callbacks import resources
|
from neutron_lib.callbacks import resources
|
||||||
from neutron_lib import context
|
from neutron_lib import context
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
|
|
||||||
|
from vmware_nsx.common import utils as nsx_utils
|
||||||
from vmware_nsx.services.l2gateway.nsx_v3 import driver as nsx_v3_driver
|
from vmware_nsx.services.l2gateway.nsx_v3 import driver as nsx_v3_driver
|
||||||
from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_nsx_v3_plugin
|
from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_nsx_v3_plugin
|
||||||
from vmware_nsxlib.tests.unit.v3 import mocks as nsx_v3_mocks
|
|
||||||
from vmware_nsxlib.v3 import nsx_constants
|
from vmware_nsxlib.v3 import nsx_constants
|
||||||
|
|
||||||
|
|
||||||
NSX_V3_PLUGIN_CLASS = ('vmware_nsx.plugins.nsx_v3.plugin.NsxV3Plugin')
|
NSX_V3_PLUGIN_CLASS = ('vmware_nsx.plugins.nsx_v3.plugin.NsxV3Plugin')
|
||||||
NSX_V3_L2GW_DRIVER_CLASS_PATH = ('vmware_nsx.services.l2gateway.'
|
NSX_V3_L2GW_DRIVER_CLASS_PATH = ('vmware_nsx.services.l2gateway.'
|
||||||
'nsx_v3.driver.NsxV3Driver')
|
'nsx_v3.driver.NsxV3Driver')
|
||||||
|
NSX_DEFAULT_BEP_NAME = "default-bridge-endpoint-profile"
|
||||||
|
|
||||||
|
|
||||||
class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
||||||
@ -58,12 +60,29 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
|||||||
mock.patch.object(l2gateway_db, 'subscribe')
|
mock.patch.object(l2gateway_db, 'subscribe')
|
||||||
mock.patch('neutron.db.servicetype_db.ServiceTypeManager.get_instance',
|
mock.patch('neutron.db.servicetype_db.ServiceTypeManager.get_instance',
|
||||||
return_value=mock.MagicMock()).start()
|
return_value=mock.MagicMock()).start()
|
||||||
|
mock_default_bep_uuid = uuidutils.generate_uuid()
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.'
|
||||||
|
'NsxLibBridgeEndpointProfile.get_id_by_name_or_id',
|
||||||
|
return_value=mock_default_bep_uuid).start()
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.'
|
||||||
|
'NsxLibBridgeEndpointProfile.get',
|
||||||
|
return_value={'id': mock_default_bep_uuid,
|
||||||
|
'edge_cluster_id': 'meh'}).start()
|
||||||
|
mock.patch('vmware_nsxlib.v3.core_resources.'
|
||||||
|
'NsxLibTransportZone.get_transport_type',
|
||||||
|
return_value="VLAN").start()
|
||||||
|
|
||||||
self.l2gw_plugin = core_l2gw_plugin.L2GatewayPlugin()
|
self.l2gw_plugin = core_l2gw_plugin.L2GatewayPlugin()
|
||||||
self.context = context.get_admin_context()
|
self.context = context.get_admin_context()
|
||||||
|
|
||||||
def _get_nw_data(self):
|
def _get_nw_data(self, provider=False):
|
||||||
net_data = super(TestNsxV3L2GatewayDriver, self)._get_nw_data()
|
net_data = super(TestNsxV3L2GatewayDriver, self)._get_nw_data()
|
||||||
net_data['network']['port_security_enabled'] = True
|
net_spec = net_data['network']
|
||||||
|
net_spec['port_security_enabled'] = True
|
||||||
|
if provider:
|
||||||
|
net_spec[providernet.NETWORK_TYPE] = (
|
||||||
|
nsx_utils.NsxV3NetworkTypes.VLAN)
|
||||||
|
net_spec[providernet.SEGMENTATION_ID] = 666
|
||||||
return net_data
|
return net_data
|
||||||
|
|
||||||
def test_nsxl2gw_driver_init(self):
|
def test_nsxl2gw_driver_init(self):
|
||||||
@ -76,34 +95,39 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
|||||||
self.assertTrue(debug.called)
|
self.assertTrue(debug.called)
|
||||||
|
|
||||||
def test_create_default_l2_gateway(self):
|
def test_create_default_l2_gateway(self):
|
||||||
def_bridge_cluster_name = nsx_v3_mocks.NSX_BRIDGE_CLUSTER_NAME
|
def_bep_name = NSX_DEFAULT_BEP_NAME
|
||||||
cfg.CONF.set_override("default_bridge_cluster",
|
cfg.CONF.set_override("default_bridge_endpoint_profile",
|
||||||
def_bridge_cluster_name,
|
def_bep_name, "nsx_v3")
|
||||||
"nsx_v3")
|
with mock.patch.object(nsx_v3_driver.NsxV3Driver,
|
||||||
|
'_get_bridge_vlan_tz_id',
|
||||||
|
return_value=['some_tz_id']) as mock_get_tz:
|
||||||
nsx_v3_driver.NsxV3Driver(mock.MagicMock())
|
nsx_v3_driver.NsxV3Driver(mock.MagicMock())
|
||||||
|
def_bep_id = (
|
||||||
|
self.nsxlib.bridge_endpoint_profile.get_id_by_name_or_id(
|
||||||
|
def_bep_name))
|
||||||
# fake the callback invoked after init
|
# fake the callback invoked after init
|
||||||
registry.publish(resources.PROCESS, events.BEFORE_SPAWN,
|
registry.publish(resources.PROCESS, events.BEFORE_SPAWN,
|
||||||
mock.MagicMock())
|
mock.MagicMock())
|
||||||
l2gws = self.driver._get_l2_gateways(self.context)
|
l2gws = self.driver._get_l2_gateways(self.context)
|
||||||
def_bridge_cluster_id = (
|
|
||||||
self.nsxlib.bridge_cluster.get_id_by_name_or_id(
|
|
||||||
def_bridge_cluster_name))
|
|
||||||
def_l2gw = None
|
def_l2gw = None
|
||||||
for l2gw in l2gws:
|
for l2gw in l2gws:
|
||||||
for device in l2gw['devices']:
|
for device in l2gw['devices']:
|
||||||
if device['device_name'] == def_bridge_cluster_id:
|
if device['device_name'] == def_bep_id:
|
||||||
def_l2gw = l2gw
|
def_l2gw = l2gw
|
||||||
self.assertIsNotNone(def_l2gw)
|
self.assertIsNotNone(def_l2gw)
|
||||||
self.assertTrue(def_l2gw.devices[0].device_name,
|
self.assertTrue(def_l2gw.devices[0].device_name, def_bep_id)
|
||||||
def_bridge_cluster_id)
|
|
||||||
self.assertTrue(def_l2gw.devices[0].interfaces[0].interface_name,
|
self.assertTrue(def_l2gw.devices[0].interfaces[0].interface_name,
|
||||||
'default-bridge-cluster')
|
'some_tz_id')
|
||||||
|
mock_get_tz.assert_called_once_with({'id': def_bep_id,
|
||||||
|
'edge_cluster_id': 'meh'})
|
||||||
|
|
||||||
def test_create_duplicate_default_l2_gateway_noop(self):
|
def test_create_duplicate_default_l2_gateway_noop(self):
|
||||||
def_bridge_cluster_name = nsx_v3_mocks.NSX_BRIDGE_CLUSTER_NAME
|
def_bep_name = NSX_DEFAULT_BEP_NAME
|
||||||
cfg.CONF.set_override("default_bridge_cluster",
|
cfg.CONF.set_override("default_bridge_endpoint_profile",
|
||||||
def_bridge_cluster_name,
|
def_bep_name, "nsx_v3")
|
||||||
"nsx_v3")
|
with mock.patch.object(nsx_v3_driver.NsxV3Driver,
|
||||||
|
'_get_bridge_vlan_tz_id',
|
||||||
|
return_value=['some_tz_id']):
|
||||||
for i in range(0, 2):
|
for i in range(0, 2):
|
||||||
nsx_v3_driver.NsxV3Driver(mock.MagicMock())
|
nsx_v3_driver.NsxV3Driver(mock.MagicMock())
|
||||||
# fake the callback invoked after init
|
# fake the callback invoked after init
|
||||||
@ -118,8 +142,8 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
|||||||
'subscribe_callback_notifications'):
|
'subscribe_callback_notifications'):
|
||||||
nsx_v3_driver.NsxV3Driver(mock.MagicMock())
|
nsx_v3_driver.NsxV3Driver(mock.MagicMock())
|
||||||
l2gws = self.driver._get_l2_gateways(self.context)
|
l2gws = self.driver._get_l2_gateways(self.context)
|
||||||
# Verify no default L2 gateway is created if bridge cluster id is
|
# Verify no default L2 gateway is created if bridge endpoint
|
||||||
# not configured in nsx.ini
|
# profile id is not configured in nsx.ini
|
||||||
self.assertEqual([], l2gws)
|
self.assertEqual([], l2gws)
|
||||||
|
|
||||||
def test_create_l2_gateway_multiple_devices_fail(self):
|
def test_create_l2_gateway_multiple_devices_fail(self):
|
||||||
@ -193,24 +217,37 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
|||||||
|
|
||||||
def test_create_l2_gateway_connections_same_params(self):
|
def test_create_l2_gateway_connections_same_params(self):
|
||||||
type(self.driver)._core_plugin = self.core_plugin
|
type(self.driver)._core_plugin = self.core_plugin
|
||||||
bc_uuid = uuidutils.generate_uuid()
|
be_uuid = uuidutils.generate_uuid()
|
||||||
l2gw_data1 = self._get_l2_gateway_data(name='def-l2gw1',
|
bep_uuid = uuidutils.generate_uuid()
|
||||||
device_name=bc_uuid)
|
l2gw_data1 = self._get_l2_gateway_data_without_seg_id(
|
||||||
|
name='def-l2gw1', device_name=bep_uuid)
|
||||||
l2gw1 = self._create_l2gateway(l2gw_data1)
|
l2gw1 = self._create_l2gateway(l2gw_data1)
|
||||||
l2gw_data2 = self._get_l2_gateway_data(name='def-l2gw2',
|
l2gw_data2 = self._get_l2_gateway_data_without_seg_id(
|
||||||
device_name=bc_uuid)
|
name='def-l2gw2', device_name=bep_uuid)
|
||||||
l2gw2 = self._create_l2gateway(l2gw_data2)
|
l2gw2 = self._create_l2gateway(l2gw_data2)
|
||||||
net_data = self._get_nw_data()
|
net_data = self._get_nw_data()
|
||||||
net = self.core_plugin.create_network(self.context, net_data)
|
net = self.core_plugin.create_network(self.context, net_data)
|
||||||
l2gw_conn_data1 = {constants.CONNECTION_RESOURCE_NAME: {
|
l2gw_conn_data1 = {constants.CONNECTION_RESOURCE_NAME: {
|
||||||
'l2_gateway_id': l2gw1['id'],
|
'l2_gateway_id': l2gw1['id'],
|
||||||
'tenant_id': 'fake_tenant_id',
|
'tenant_id': 'fake_tenant_id',
|
||||||
|
'segmentation_id': '666',
|
||||||
'network_id': net['id']}}
|
'network_id': net['id']}}
|
||||||
|
# Override "global" mock to return a known id
|
||||||
|
with mock.patch('vmware_nsxlib.v3.core_resources.'
|
||||||
|
'NsxLibBridgeEndpoint.create',
|
||||||
|
return_value={'id': be_uuid}):
|
||||||
self.l2gw_plugin.create_l2_gateway_connection(
|
self.l2gw_plugin.create_l2_gateway_connection(
|
||||||
self.context, l2gw_conn_data1)
|
self.context, l2gw_conn_data1)
|
||||||
|
fake_be = {'id': be_uuid,
|
||||||
|
'vlan': 666,
|
||||||
|
'bridge_endpoint_profile_id': bep_uuid}
|
||||||
|
with mock.patch('vmware_nsxlib.v3.NsxLib.'
|
||||||
|
'search_all_resource_by_attributes',
|
||||||
|
return_value=[fake_be]):
|
||||||
l2gw_conn_data2 = {constants.CONNECTION_RESOURCE_NAME: {
|
l2gw_conn_data2 = {constants.CONNECTION_RESOURCE_NAME: {
|
||||||
'l2_gateway_id': l2gw2['id'],
|
'l2_gateway_id': l2gw2['id'],
|
||||||
'tenant_id': 'fake_tenant_id',
|
'tenant_id': 'fake_tenant_id',
|
||||||
|
'segmentation_id': 666,
|
||||||
'network_id': net['id']}}
|
'network_id': net['id']}}
|
||||||
self.assertRaises(n_exc.InvalidInput,
|
self.assertRaises(n_exc.InvalidInput,
|
||||||
self.l2gw_plugin.create_l2_gateway_connection,
|
self.l2gw_plugin.create_l2_gateway_connection,
|
||||||
@ -241,6 +278,23 @@ class TestNsxV3L2GatewayDriver(test_l2gw_db.L2GWTestCase,
|
|||||||
self.l2gw_plugin.create_l2_gateway_connection(
|
self.l2gw_plugin.create_l2_gateway_connection(
|
||||||
self.context, l2gw_conn_data2)
|
self.context, l2gw_conn_data2)
|
||||||
|
|
||||||
|
def test_create_l2_gateway_connection_invalid_network_type_fails(self):
|
||||||
|
type(self.driver)._core_plugin = self.core_plugin
|
||||||
|
bep_uuid = uuidutils.generate_uuid()
|
||||||
|
l2gw_data = self._get_l2_gateway_data(name='def-l2gw',
|
||||||
|
device_name=bep_uuid)
|
||||||
|
l2gw = self._create_l2gateway(l2gw_data)
|
||||||
|
net_data = self._get_nw_data(provider=True)
|
||||||
|
net = self.core_plugin.create_network(self.context, net_data)
|
||||||
|
l2gw_conn_data = {constants.CONNECTION_RESOURCE_NAME: {
|
||||||
|
'l2_gateway_id': l2gw['id'],
|
||||||
|
'tenant_id': 'fake_tenant_id',
|
||||||
|
'network_id': net['id']}}
|
||||||
|
self.assertRaises(n_exc.InvalidInput,
|
||||||
|
self.l2gw_plugin.create_l2_gateway_connection,
|
||||||
|
self.context,
|
||||||
|
l2gw_conn_data)
|
||||||
|
|
||||||
def test_delete_l2_gateway_connection(self):
|
def test_delete_l2_gateway_connection(self):
|
||||||
type(self.driver)._core_plugin = self.core_plugin
|
type(self.driver)._core_plugin = self.core_plugin
|
||||||
bc_uuid = uuidutils.generate_uuid()
|
bc_uuid = uuidutils.generate_uuid()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user