Merge "Add IP version check for IP address fields."
This commit is contained in:
commit
a2452fc87f
@ -294,7 +294,7 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
pool_id = allocation_pool['id']
|
pool_id = allocation_pool['id']
|
||||||
break
|
break
|
||||||
if not pool_id:
|
if not pool_id:
|
||||||
error_message = ("No allocation pool found for "
|
error_message = _("No allocation pool found for "
|
||||||
"ip address:%s" % ip_address)
|
"ip address:%s" % ip_address)
|
||||||
raise q_exc.InvalidInput(error_message=error_message)
|
raise q_exc.InvalidInput(error_message=error_message)
|
||||||
# Two requests will be done on the database. The first will be to
|
# Two requests will be done on the database. The first will be to
|
||||||
@ -709,7 +709,7 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
pool_2=r_range,
|
pool_2=r_range,
|
||||||
subnet_cidr=subnet_cidr)
|
subnet_cidr=subnet_cidr)
|
||||||
|
|
||||||
def _validate_host_route(self, route):
|
def _validate_host_route(self, route, ip_version):
|
||||||
try:
|
try:
|
||||||
netaddr.IPNetwork(route['destination'])
|
netaddr.IPNetwork(route['destination'])
|
||||||
netaddr.IPAddress(route['nexthop'])
|
netaddr.IPAddress(route['nexthop'])
|
||||||
@ -718,8 +718,11 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
raise q_exc.InvalidInput(error_message=err_msg)
|
raise q_exc.InvalidInput(error_message=err_msg)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# netaddr.IPAddress would raise this
|
# netaddr.IPAddress would raise this
|
||||||
err_msg = ("invalid route: %s" % (str(route)))
|
err_msg = _("invalid route: %s") % str(route)
|
||||||
raise q_exc.InvalidInput(error_message=err_msg)
|
raise q_exc.InvalidInput(error_message=err_msg)
|
||||||
|
self._validate_ip_version(ip_version, route['nexthop'], 'nexthop')
|
||||||
|
self._validate_ip_version(ip_version, route['destination'],
|
||||||
|
'destination')
|
||||||
|
|
||||||
def _allocate_pools_for_subnet(self, context, subnet):
|
def _allocate_pools_for_subnet(self, context, subnet):
|
||||||
"""Create IP allocation pools for a given subnet
|
"""Create IP allocation pools for a given subnet
|
||||||
@ -912,9 +915,30 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
def create_subnet_bulk(self, context, subnets):
|
def create_subnet_bulk(self, context, subnets):
|
||||||
return self._create_bulk('subnet', context, subnets)
|
return self._create_bulk('subnet', context, subnets)
|
||||||
|
|
||||||
|
def _validate_ip_version(self, ip_version, addr, name):
|
||||||
|
"""Check IP field of a subnet match specified ip version"""
|
||||||
|
ip = netaddr.IPNetwork(addr)
|
||||||
|
if ip.version != ip_version:
|
||||||
|
msg = _("%(name)s '%(addr)s' does not match "
|
||||||
|
"the ip_version '%(ip_version)s'") % locals()
|
||||||
|
raise q_exc.InvalidInput(error_message=msg)
|
||||||
|
|
||||||
def _validate_subnet(self, s):
|
def _validate_subnet(self, s):
|
||||||
"""a subroutine to validate a subnet spec"""
|
"""Validate a subnet spec"""
|
||||||
# check if the number of DNS nameserver exceeds the quota
|
|
||||||
|
# The method requires the subnet spec 's' has 'ip_version' field.
|
||||||
|
# If 's' dict does not have 'ip_version' field in an API call
|
||||||
|
# (e.g., update_subnet()), you need to set 'ip_version' field
|
||||||
|
# before calling this method.
|
||||||
|
ip_ver = s['ip_version']
|
||||||
|
|
||||||
|
if 'cidr' in s:
|
||||||
|
self._validate_ip_version(ip_ver, s['cidr'], 'cidr')
|
||||||
|
if ('gateway_ip' in s and
|
||||||
|
s['gateway_ip'] and
|
||||||
|
s['gateway_ip'] != attributes.ATTR_NOT_SPECIFIED):
|
||||||
|
self._validate_ip_version(ip_ver, s['gateway_ip'], 'gateway_ip')
|
||||||
|
|
||||||
if 'dns_nameservers' in s and \
|
if 'dns_nameservers' in s and \
|
||||||
s['dns_nameservers'] != attributes.ATTR_NOT_SPECIFIED:
|
s['dns_nameservers'] != attributes.ATTR_NOT_SPECIFIED:
|
||||||
if len(s['dns_nameservers']) > cfg.CONF.max_dns_nameservers:
|
if len(s['dns_nameservers']) > cfg.CONF.max_dns_nameservers:
|
||||||
@ -927,8 +951,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
except Exception:
|
except Exception:
|
||||||
raise q_exc.InvalidInput(
|
raise q_exc.InvalidInput(
|
||||||
error_message=("error parsing dns address %s" % dns))
|
error_message=("error parsing dns address %s" % dns))
|
||||||
|
self._validate_ip_version(ip_ver, dns, 'dns_nameserver')
|
||||||
|
|
||||||
# check if the number of host routes exceeds the quota
|
|
||||||
if 'host_routes' in s and \
|
if 'host_routes' in s and \
|
||||||
s['host_routes'] != attributes.ATTR_NOT_SPECIFIED:
|
s['host_routes'] != attributes.ATTR_NOT_SPECIFIED:
|
||||||
if len(s['host_routes']) > cfg.CONF.max_subnet_host_routes:
|
if len(s['host_routes']) > cfg.CONF.max_subnet_host_routes:
|
||||||
@ -937,7 +961,7 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
quota=cfg.CONF.max_subnet_host_routes)
|
quota=cfg.CONF.max_subnet_host_routes)
|
||||||
# check if the routes are all valid
|
# check if the routes are all valid
|
||||||
for rt in s['host_routes']:
|
for rt in s['host_routes']:
|
||||||
self._validate_host_route(rt)
|
self._validate_host_route(rt, ip_ver)
|
||||||
|
|
||||||
def create_subnet(self, context, subnet):
|
def create_subnet(self, context, subnet):
|
||||||
s = subnet['subnet']
|
s = subnet['subnet']
|
||||||
@ -998,6 +1022,9 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2):
|
|||||||
gratuitous DHCP offers"""
|
gratuitous DHCP offers"""
|
||||||
|
|
||||||
s = subnet['subnet']
|
s = subnet['subnet']
|
||||||
|
# Fill 'ip_version' field with the current value since
|
||||||
|
# _validate_subnet() expects subnet spec has 'ip_version' field.
|
||||||
|
s['ip_version'] = self._get_subnet(context, id).ip_version
|
||||||
self._validate_subnet(s)
|
self._validate_subnet(s)
|
||||||
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
|
@ -253,11 +253,8 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
|
|||||||
subnet_in_db2 = self.plugin.get_subnet(self.context, subnet2_ret['id'])
|
subnet_in_db2 = self.plugin.get_subnet(self.context, subnet2_ret['id'])
|
||||||
subnet_in_db3 = self.plugin.get_subnet(self.context, subnet3_ret['id'])
|
subnet_in_db3 = self.plugin.get_subnet(self.context, subnet3_ret['id'])
|
||||||
|
|
||||||
subnet1['subnet']['ip_version'] = 6
|
|
||||||
subnet1['subnet']['allocation_pools'].pop()
|
subnet1['subnet']['allocation_pools'].pop()
|
||||||
subnet2['subnet']['ip_version'] = 6
|
|
||||||
subnet2['subnet']['allocation_pools'].pop()
|
subnet2['subnet']['allocation_pools'].pop()
|
||||||
subnet3['subnet']['ip_version'] = 6
|
|
||||||
subnet3['subnet']['allocation_pools'].pop()
|
subnet3['subnet']['allocation_pools'].pop()
|
||||||
|
|
||||||
self.plugin.update_subnet(self.context,
|
self.plugin.update_subnet(self.context,
|
||||||
@ -270,9 +267,9 @@ class MetaQuantumPluginV2Test(unittest.TestCase):
|
|||||||
subnet_in_db2 = self.plugin.get_subnet(self.context, subnet2_ret['id'])
|
subnet_in_db2 = self.plugin.get_subnet(self.context, subnet2_ret['id'])
|
||||||
subnet_in_db3 = self.plugin.get_subnet(self.context, subnet3_ret['id'])
|
subnet_in_db3 = self.plugin.get_subnet(self.context, subnet3_ret['id'])
|
||||||
|
|
||||||
self.assertEqual(6, subnet_in_db1['ip_version'])
|
self.assertEqual(4, subnet_in_db1['ip_version'])
|
||||||
self.assertEqual(6, subnet_in_db2['ip_version'])
|
self.assertEqual(4, subnet_in_db2['ip_version'])
|
||||||
self.assertEqual(6, subnet_in_db3['ip_version'])
|
self.assertEqual(4, subnet_in_db3['ip_version'])
|
||||||
|
|
||||||
self.plugin.delete_subnet(self.context, subnet1_ret['id'])
|
self.plugin.delete_subnet(self.context, subnet1_ret['id'])
|
||||||
self.plugin.delete_subnet(self.context, subnet2_ret['id'])
|
self.plugin.delete_subnet(self.context, subnet2_ret['id'])
|
||||||
|
@ -1950,7 +1950,7 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase):
|
|||||||
allocation_pools = [{'start': 'fe80::2',
|
allocation_pools = [{'start': 'fe80::2',
|
||||||
'end': 'fe80::ffff:fffa:ffff'}]
|
'end': 'fe80::ffff:fffa:ffff'}]
|
||||||
self._test_create_subnet(gateway_ip=gateway_ip,
|
self._test_create_subnet(gateway_ip=gateway_ip,
|
||||||
cidr=cidr,
|
cidr=cidr, ip_version=6,
|
||||||
allocation_pools=allocation_pools)
|
allocation_pools=allocation_pools)
|
||||||
|
|
||||||
def test_create_subnet_with_large_allocation_pool(self):
|
def test_create_subnet_with_large_allocation_pool(self):
|
||||||
@ -2032,6 +2032,85 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase):
|
|||||||
shared=True)
|
shared=True)
|
||||||
self.assertEquals(ctx_manager.exception.code, 422)
|
self.assertEquals(ctx_manager.exception.code, 422)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv6_cidrv4(self):
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': '10.0.2.0/24',
|
||||||
|
'ip_version': 6,
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv4_cidrv6(self):
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': 'fe80::0/80',
|
||||||
|
'ip_version': 4,
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv4_gatewayv6(self):
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': '10.0.2.0/24',
|
||||||
|
'ip_version': 4,
|
||||||
|
'gateway_ip': 'fe80::1',
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': 'fe80::0/80',
|
||||||
|
'ip_version': 6,
|
||||||
|
'gateway_ip': '192.168.0.1',
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv6_dns_v4(self):
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': 'fe80::0/80',
|
||||||
|
'ip_version': 6,
|
||||||
|
'dns_nameservers': ['192.168.0.1'],
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv4_hostroute_dst_v6(self):
|
||||||
|
host_routes = [{'destination': 'fe80::0/48',
|
||||||
|
'nexthop': '10.0.2.20'}]
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': '10.0.2.0/24',
|
||||||
|
'ip_version': 4,
|
||||||
|
'host_routes': host_routes,
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_create_subnet_inconsistent_ipv4_hostroute_np_v6(self):
|
||||||
|
host_routes = [{'destination': '172.16.0.0/24',
|
||||||
|
'nexthop': 'fe80::1'}]
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': '10.0.2.0/24',
|
||||||
|
'ip_version': 4,
|
||||||
|
'host_routes': host_routes,
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
subnet_req = self.new_create_request('subnets', data)
|
||||||
|
res = subnet_req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
def test_update_subnet(self):
|
def test_update_subnet(self):
|
||||||
with self.subnet() as subnet:
|
with self.subnet() as subnet:
|
||||||
data = {'subnet': {'gateway_ip': '11.0.0.1'}}
|
data = {'subnet': {'gateway_ip': '11.0.0.1'}}
|
||||||
@ -2050,6 +2129,59 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase):
|
|||||||
res = req.get_response(self.api)
|
res = req.get_response(self.api)
|
||||||
self.assertEqual(res.status_int, 422)
|
self.assertEqual(res.status_int, 422)
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv4_gatewayv6(self):
|
||||||
|
with self.network() as network:
|
||||||
|
with self.subnet(network=network) as subnet:
|
||||||
|
data = {'subnet': {'gateway_ip': 'fe80::1'}}
|
||||||
|
req = self.new_update_request('subnets', data,
|
||||||
|
subnet['subnet']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv6_gatewayv4(self):
|
||||||
|
with self.network() as network:
|
||||||
|
with self.subnet(network=network,
|
||||||
|
ip_version=6, cidr='fe80::/48') as subnet:
|
||||||
|
data = {'subnet': {'gateway_ip': '10.1.1.1'}}
|
||||||
|
req = self.new_update_request('subnets', data,
|
||||||
|
subnet['subnet']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv4_dns_v6(self):
|
||||||
|
dns_nameservers = ['fe80::1']
|
||||||
|
with self.network() as network:
|
||||||
|
with self.subnet(network=network) as subnet:
|
||||||
|
data = {'subnet': {'dns_nameservers': dns_nameservers}}
|
||||||
|
req = self.new_update_request('subnets', data,
|
||||||
|
subnet['subnet']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self):
|
||||||
|
host_routes = [{'destination': 'fe80::0/48',
|
||||||
|
'nexthop': '10.0.2.20'}]
|
||||||
|
with self.network() as network:
|
||||||
|
with self.subnet(network=network,
|
||||||
|
ip_version=6, cidr='fe80::/48') as subnet:
|
||||||
|
data = {'subnet': {'host_routes': host_routes}}
|
||||||
|
req = self.new_update_request('subnets', data,
|
||||||
|
subnet['subnet']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
|
def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self):
|
||||||
|
host_routes = [{'destination': '172.16.0.0/24',
|
||||||
|
'nexthop': 'fe80::1'}]
|
||||||
|
with self.network() as network:
|
||||||
|
with self.subnet(network=network,
|
||||||
|
ip_version=6, cidr='fe80::/48') as subnet:
|
||||||
|
data = {'subnet': {'host_routes': host_routes}}
|
||||||
|
req = self.new_update_request('subnets', data,
|
||||||
|
subnet['subnet']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEquals(res.status_int, 400)
|
||||||
|
|
||||||
def test_show_subnet(self):
|
def test_show_subnet(self):
|
||||||
with self.network() as network:
|
with self.network() as network:
|
||||||
with self.subnet(network=network) as subnet:
|
with self.subnet(network=network) as subnet:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user