Block subnet create when a network hosts subnets allocated from different pools

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
This commit is contained in:
Ryan Tidwell 2015-05-04 15:56:41 -07:00 committed by Ryan Tidwell
parent 0933f26b2c
commit 251f551a5f
5 changed files with 65 additions and 0 deletions

View 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")

View 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)

View 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'])

View 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)

View 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):