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:
parent
0933f26b2c
commit
251f551a5f
|
@ -457,3 +457,8 @@ class SubnetPoolQuotaExceeded(OverQuota):
|
||||||
|
|
||||||
class DeviceNotFoundError(NeutronException):
|
class DeviceNotFoundError(NeutronException):
|
||||||
message = _("Device '%(device_name)s' does not exist")
|
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")
|
||||||
|
|
|
@ -641,6 +641,16 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||||
'cidr': subnet.cidr})
|
'cidr': subnet.cidr})
|
||||||
raise n_exc.InvalidInput(error_message=err_msg)
|
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):
|
def _validate_allocation_pools(self, ip_pools, subnet_cidr):
|
||||||
"""Validate IP allocation pools.
|
"""Validate IP allocation pools.
|
||||||
|
|
||||||
|
@ -1191,6 +1201,9 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
|
||||||
allocation_pools)
|
allocation_pools)
|
||||||
|
|
||||||
self._validate_subnet_cidr(context, network, subnet_args['cidr'])
|
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)
|
subnet = models_v2.Subnet(**subnet_args)
|
||||||
context.session.add(subnet)
|
context.session.add(subnet)
|
||||||
|
|
|
@ -256,3 +256,20 @@ class SubnetPoolsTestV6(SubnetPoolsTest):
|
||||||
prefixes = [u'2001:db8:3::/48']
|
prefixes = [u'2001:db8:3::/48']
|
||||||
cls._subnetpool_data = {'subnetpool': {'min_prefixlen': min_prefixlen,
|
cls._subnetpool_data = {'subnetpool': {'min_prefixlen': min_prefixlen,
|
||||||
'prefixes': prefixes}}
|
'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'])
|
||||||
|
|
|
@ -118,3 +118,24 @@ class SubnetPoolsNegativeTestJSON(base.BaseNetworkTest):
|
||||||
self.assertRaises(lib_exc.BadRequest,
|
self.assertRaises(lib_exc.BadRequest,
|
||||||
self.client.update_subnetpool,
|
self.client.update_subnetpool,
|
||||||
pool_id, subnetpool_data)
|
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)
|
||||||
|
|
|
@ -5535,6 +5535,15 @@ class NeutronDbPluginV2AsMixinTestCase(NeutronDbPluginV2TestCase,
|
||||||
subnet['subnet']['id'])
|
subnet['subnet']['id'])
|
||||||
self.assertIsNone(res)
|
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):
|
class TestNetworks(testlib_api.SqlTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue