]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
NSX: Validate gateway device list against DB
authorSalvatore <salv.orlando@gmail.com>
Mon, 1 Sep 2014 12:37:00 +0000 (14:37 +0200)
committerSalvatore Orlando <salv.orlando@gmail.com>
Tue, 18 Nov 2014 22:31:00 +0000 (22:31 +0000)
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

neutron/plugins/vmware/dbexts/networkgw_db.py
neutron/plugins/vmware/plugins/base.py
neutron/tests/unit/vmware/extensions/test_networkgw.py

index 7463d0b1ac161e1a8edc74f43964bfc5c79a1103..d499e322330b74a6d69a02f402565c298ea55d92 100644 (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)
index 6bc2e4d4a3b48f901ed476b9696698a9060d4107..9b1f95a5ee95322d4a6fbdd27313280c2f736e45 100644 (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.
index 7427527545e57021d48f115f7bfcbff9d1e8a3a6..58ec9ce8c4441562436298122908d33c3c3b02c2 100644 (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)