]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Block subnet create when a network hosts subnets allocated from different pools
authorRyan Tidwell <ryan.tidwell@hp.com>
Mon, 4 May 2015 22:56:41 +0000 (15:56 -0700)
committerRyan Tidwell <rktidwell85@gmail.com>
Wed, 13 May 2015 22:23:58 +0000 (22:23 +0000)
This change will ensure that all subnets with the same ip_version on a given
network have been allocated from the same subnet pool or no pool. This
provides cleaner subnet overlap detection.

Change-Id: I3c7366c69b10c202c0511126fbee6b3aac36759e
Closes-Bug: #1451559

neutron/common/exceptions.py
neutron/db/db_base_plugin_v2.py
neutron/tests/api/test_subnetpools.py
neutron/tests/api/test_subnetpools_negative.py
neutron/tests/unit/db/test_db_base_plugin_v2.py

index 227cf0821509ef060018e67ca7dc1e49f3321b72..09f27512863d6edb26e79d9abe38cbb80708ae03 100644 (file)
@@ -457,3 +457,8 @@ class SubnetPoolQuotaExceeded(OverQuota):
 
 class DeviceNotFoundError(NeutronException):
     message = _("Device '%(device_name)s' does not exist")
+
+
+class NetworkSubnetPoolAffinityError(BadRequest):
+    message = _("Subnets hosted on the same network must be allocated from "
+                "the same subnet pool")
index 74dabca7ffaef7b5bcccd2ad9b38622c966da6c8..e755754c6b12baaa345d1b898b3d3e977a7d9bfa 100644 (file)
@@ -641,6 +641,16 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
                           'cidr': subnet.cidr})
                 raise n_exc.InvalidInput(error_message=err_msg)
 
+    def _validate_network_subnetpools(self, network,
+                                      new_subnetpool_id, ip_version):
+        """Validate all subnets on the given network have been allocated from
+           the same subnet pool as new_subnetpool_id
+        """
+        for subnet in network.subnets:
+            if (subnet.ip_version == ip_version and
+               new_subnetpool_id != subnet.subnetpool_id):
+                raise n_exc.NetworkSubnetPoolAffinityError()
+
     def _validate_allocation_pools(self, ip_pools, subnet_cidr):
         """Validate IP allocation pools.
 
@@ -1191,6 +1201,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
                                                allocation_pools)
 
         self._validate_subnet_cidr(context, network, subnet_args['cidr'])
+        self._validate_network_subnetpools(network,
+                                           subnet_args['subnetpool_id'],
+                                           subnet_args['ip_version'])
 
         subnet = models_v2.Subnet(**subnet_args)
         context.session.add(subnet)
index 73aad6806171a93c16bac165f46c027a3d0bad71..454dfb86b78836a46943731fed3c1c7aae07bb6f 100644 (file)
@@ -256,3 +256,20 @@ class SubnetPoolsTestV6(SubnetPoolsTest):
         prefixes = [u'2001:db8:3::/48']
         cls._subnetpool_data = {'subnetpool': {'min_prefixlen': min_prefixlen,
                                                'prefixes': prefixes}}
+
+    @test.attr(type='smoke')
+    @test.idempotent_id('f62d73dc-cf6f-4879-b94b-dab53982bf3b')
+    def test_create_dual_stack_subnets_from_subnetpools(self):
+        pool_id_v6, subnet_v6 = self._create_subnet_from_pool()
+        self.addCleanup(self.client.delete_subnet, subnet_v6['id'])
+        pool_values_v4 = {'prefixes': ['192.168.0.0/16'],
+                          'min_prefixlen': 21,
+                          'max_prefixlen': 32}
+        pool_name_v4, pool_id_v4 = self._create_subnetpool(self.client,
+                                                  pool_values=pool_values_v4)
+        subnet_v4 = self.client.create_subnet(
+                                network_id=subnet_v6['network_id'],
+                                ip_version=4,
+                                subnetpool_id=pool_id_v4)['subnet']
+        self.addCleanup(self.client.delete_subnet, subnet_v4['id'])
+        self.assertEqual(subnet_v4['network_id'], subnet_v6['network_id'])
index 52424499a0e76ad233a8868dff180a7ed10e3ab3..c82c6f87273f904e36a7bc64371542b8685cefb5 100644 (file)
@@ -118,3 +118,24 @@ class SubnetPoolsNegativeTestJSON(base.BaseNetworkTest):
         self.assertRaises(lib_exc.BadRequest,
                           self.client.update_subnetpool,
                           pool_id, subnetpool_data)
+
+    @test.attr(type=['negative', 'smoke'])
+    @test.idempotent_id('fc011824-153e-4469-97ad-9808eb88cae1')
+    def test_create_subnet_different_pools_same_network(self):
+        network = self.create_network(network_name='smoke-network')
+        subnetpool_data = {'prefixes': ['192.168.0.0/16'],
+                           'name': 'test-pool'}
+        pool_id = self._create_subnetpool(self.admin_client, subnetpool_data)
+        subnet = self.admin_client.create_subnet(
+                    network_id=network['id'],
+                    cidr='10.10.10.0/24',
+                    ip_version=4,
+                    gateway_ip=None)
+        subnet_id = subnet['subnet']['id']
+        self.addCleanup(self.admin_client.delete_subnet, subnet_id)
+        self.addCleanup(self.admin_client.delete_subnetpool, pool_id)
+        self.assertRaises(lib_exc.BadRequest,
+                          self.admin_client.create_subnet,
+                          network_id=network['id'],
+                          ip_version=4,
+                          subnetpool_id=pool_id)
index a088e3522707341ff288aa67de0d26af28a4238e..680b1d59c9a3b86c2a6dc10218c20f8b94247557 100644 (file)
@@ -5535,6 +5535,15 @@ class NeutronDbPluginV2AsMixinTestCase(NeutronDbPluginV2TestCase,
                         subnet['subnet']['id'])
                     self.assertIsNone(res)
 
+    def test__validate_network_subnetpools(self):
+        network = models_v2.Network()
+        network.subnets = [models_v2.Subnet(subnetpool_id='test_id',
+                                            ip_version=4)]
+        new_subnetpool_id = None
+        self.assertRaises(n_exc.NetworkSubnetPoolAffinityError,
+                          self.plugin._validate_network_subnetpools,
+                          network, new_subnetpool_id, 4)
+
 
 class TestNetworks(testlib_api.SqlTestCase):
     def setUp(self):