NSX: Validate gateway device list against DB

This patch adds a check for validating the devices for a network
gateway are defined in the neutron DB before the request for
creating the network gateway is sent to the NSX backend.

Change-Id: Ic2245f965da332dbaee4ab5a869ce47f06a9e6ce
Partial-Bug: #1319581
This commit is contained in:
Salvatore 2014-09-01 14:37:00 +02:00 committed by Salvatore Orlando
parent f9d3e91789
commit 9d80a8accd
3 changed files with 49 additions and 16 deletions

View File

@ -60,6 +60,11 @@ class GatewayDeviceNotFound(exceptions.NotFound):
message = _("Network Gateway Device %(device_id)s could not be found.")
class GatewayDevicesNotFound(exceptions.NotFound):
message = _("One or more Network Gateway Devices could not be found: "
"%(device_ids)s.")
class NetworkGatewayPortInUse(exceptions.InUse):
message = _("Port '%(port_id)s' is owned by '%(device_owner)s' and "
"therefore cannot be deleted directly via the port API.")
@ -244,7 +249,24 @@ class NetworkGatewayMixin(networkgw.NetworkGatewayPluginBase):
raise NetworkGatewayPortInUse(port_id=port['id'],
device_owner=port['device_owner'])
def create_network_gateway(self, context, network_gateway):
def _validate_device_list(self, context, tenant_id, gateway_data):
device_query = self._query_gateway_devices(
context, filters={'id': [device['id']
for device in gateway_data['devices']]})
retrieved_device_ids = set()
for device in device_query:
retrieved_device_ids.add(device['id'])
if device['tenant_id'] != tenant_id:
raise GatewayDeviceNotFound(device_id=device['id'])
missing_device_ids = (
set(device['id'] for device in gateway_data['devices']) -
retrieved_device_ids)
if missing_device_ids:
raise GatewayDevicesNotFound(
device_ids=",".join(missing_device_ids))
def create_network_gateway(self, context, network_gateway,
validate_device_list=True):
gw_data = network_gateway[self.gateway_resource]
tenant_id = self._get_tenant_id_for_create(context, gw_data)
with context.session.begin(subtransactions=True):
@ -252,13 +274,10 @@ class NetworkGatewayMixin(networkgw.NetworkGatewayPluginBase):
id=gw_data.get('id', uuidutils.generate_uuid()),
tenant_id=tenant_id,
name=gw_data.get('name'))
# Device list is guaranteed to be a valid list
device_query = self._query_gateway_devices(
context, filters={'id': [device['id']
for device in gw_data['devices']]})
for device in device_query:
if device['tenant_id'] != tenant_id:
raise GatewayDeviceNotFound(device_id=device['id'])
# Device list is guaranteed to be a valid list, but some devices
# might still either not exist or belong to a different tenant
if validate_device_list:
self._validate_device_list(context, tenant_id, gw_data)
gw_db.devices.extend([NetworkGatewayDeviceReference(**device)
for device in gw_data['devices']])
context.session.add(gw_db)

View File

@ -1998,11 +1998,12 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
Create the gateway service on NSX platform and corresponding data
structures in Neutron datase.
"""
# Ensure the default gateway in the config file is in sync with the db
self._ensure_default_network_gateway()
# Need to re-do authZ checks here in order to avoid creation on NSX
gw_data = network_gateway[networkgw.GATEWAY_RESOURCE_NAME]
tenant_id = self._get_tenant_id_for_create(context, gw_data)
# Ensure the default gateway in the config file is in sync with the db
self._ensure_default_network_gateway()
# Validate provided gateway device list
self._validate_device_list(context, tenant_id, gw_data)
devices = gw_data['devices']
# Populate default physical network where not specified
for device in devices:
@ -2029,7 +2030,7 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
raise nsx_exc.NsxPluginException(err_msg=err_msg)
gw_data['id'] = nsx_uuid
return super(NsxPluginV2, self).create_network_gateway(
context, network_gateway)
context, network_gateway, validate_device_list=False)
def delete_network_gateway(self, context, gateway_id):
"""Remove a layer-2 network gateway.

View File

@ -557,6 +557,13 @@ class NetworkGatewayDbTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
'json', _uuid(), name=name, devices=devices)
self.assertEqual(404, res.status_int)
def test_create_network_gateway_non_existent_device_raises_404(self):
name = 'test-gw'
devices = [{'id': _uuid(), 'interface_name': 'xxx'}]
res = self._create_network_gateway(
'json', _uuid(), name=name, devices=devices)
self.assertEqual(404, res.status_int)
def test_delete_network_gateway(self):
tenant_id = _uuid()
with self._gateway_device(tenant_id=tenant_id) as dev:
@ -979,9 +986,12 @@ class TestNetworkGateway(test_nsx_plugin.NsxPluginV2TestCase,
with mock.patch.object(nsxlib.l2gateway,
'create_l2_gw_service',
new=raise_nsx_api_exc):
with self._gateway_device() as dev:
tenant_id = _uuid()
with self._gateway_device(tenant_id=tenant_id) as dev:
res = self._create_network_gateway(
self.fmt, 'xxx', name='yyy',
self.fmt,
tenant_id,
name='yyy',
devices=[{'id': dev[self.dev_resource]['id']}])
self.assertEqual(500, res.status_int)
@ -989,9 +999,12 @@ class TestNetworkGateway(test_nsx_plugin.NsxPluginV2TestCase,
with mock.patch.object(nsxlib.l2gateway,
'create_l2_gw_service',
side_effect=api_exc.Conflict):
with self._gateway_device() as dev:
tenant_id = _uuid()
with self._gateway_device(tenant_id=tenant_id) as dev:
res = self._create_network_gateway(
self.fmt, 'xxx', name='yyy',
self.fmt,
tenant_id,
name='yyy',
devices=[{'id': dev[self.dev_resource]['id']}])
self.assertEqual(409, res.status_int)