From: Nachi Ueno Date: Thu, 2 Aug 2012 22:46:45 +0000 (+0000) Subject: Make sure that there's a way of creating a subnet without a gateway X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=795711f763a03bd7ae2b5f980a02af62f3a6b382;p=openstack-build%2Fneutron-build.git Make sure that there's a way of creating a subnet without a gateway Fixes bug 1028646 You can use null for gateway ip. Change-Id: I969112ad46efa22203db40106d4e35dce1757165 --- diff --git a/quantum/api/v2/attributes.py b/quantum/api/v2/attributes.py index c7e480262..c55caab12 100644 --- a/quantum/api/v2/attributes.py +++ b/quantum/api/v2/attributes.py @@ -66,6 +66,12 @@ def _validate_ip_address(data, valid_values=None): return msg +def _validate_ip_address_or_none(data, valid_values=None): + if data is None: + return None + return _validate_ip_address(data, valid_values) + + def _validate_subnet(data, valid_values=None): try: netaddr.IPNetwork(data) @@ -103,7 +109,6 @@ def convert_to_boolean(data): msg = _("%s is not boolean") % data raise q_exc.InvalidInput(error_message=msg) - HEX_ELEM = '[0-9A-Fa-f]' UUID_PATTERN = '-'.join([HEX_ELEM + '{8}', HEX_ELEM + '{4}', HEX_ELEM + '{4}', HEX_ELEM + '{4}', @@ -117,6 +122,7 @@ validators = {'type:boolean': _validate_boolean, 'type:values': _validate_values, 'type:mac_address': _validate_mac_address, 'type:ip_address': _validate_ip_address, + 'type:ip_address_or_none': _validate_ip_address_or_none, 'type:subnet': _validate_subnet, 'type:regex': _validate_regex} @@ -226,7 +232,7 @@ RESOURCE_ATTRIBUTE_MAP = { 'is_visible': True}, 'gateway_ip': {'allow_post': True, 'allow_put': True, 'default': ATTR_NOT_SPECIFIED, - 'validate': {'type:ip_address': None}, + 'validate': {'type:ip_address_or_none': None}, 'is_visible': True}, #TODO(salvatore-orlando): Enable PUT on allocation_pools 'allocation_pools': {'allow_post': True, 'allow_put': False, diff --git a/quantum/db/db_base_plugin_v2.py b/quantum/db/db_base_plugin_v2.py index e50d2e4c7..4ce915110 100644 --- a/quantum/db/db_base_plugin_v2.py +++ b/quantum/db/db_base_plugin_v2.py @@ -566,8 +566,9 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2): "and gateway ip") ip_ranges = ip_pools[:] # Treat gw as IPset as well - ip_ranges.append(gateway_ip) - ip_sets.append(netaddr.IPSet([gateway_ip])) + if gateway_ip: + ip_ranges.append(gateway_ip) + ip_sets.append(netaddr.IPSet([gateway_ip])) # Use integer cursors as an efficient way for implementing # comparison and avoiding comparing the same pair twice for l_cursor in range(len(ip_sets)): @@ -593,11 +594,12 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2): pools = [] if subnet['allocation_pools'] == attributes.ATTR_NOT_SPECIFIED: - # Auto allocate the pool around gateway - gw_ip = int(netaddr.IPAddress(subnet['gateway_ip'])) + # Auto allocate the pool around gateway_ip net = netaddr.IPNetwork(subnet['cidr']) first_ip = net.first + 1 last_ip = net.last - 1 + gw_ip = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last)) + if gw_ip > first_ip: pools.append({'start': str(netaddr.IPAddress(first_ip)), 'end': str(netaddr.IPAddress(gw_ip - 1))}) @@ -657,6 +659,8 @@ class QuantumDbPluginV2(quantum_plugin_base_v2.QuantumPluginBaseV2): for pool in subnet['allocation_pools']], 'gateway_ip': subnet['gateway_ip'], 'enable_dhcp': subnet['enable_dhcp']} + if subnet['gateway_ip']: + res['gateway_ip'] = subnet['gateway_ip'] return self._fields(res, fields) def _make_port_dict(self, port, fields=None): diff --git a/quantum/tests/unit/test_db_plugin.py b/quantum/tests/unit/test_db_plugin.py index 7dd902f31..150b14f92 100644 --- a/quantum/tests/unit/test_db_plugin.py +++ b/quantum/tests/unit/test_db_plugin.py @@ -22,6 +22,8 @@ import unittest2 import webob.exc import quantum +from quantum.api.v2 import attributes +from quantum.api.v2.attributes import ATTR_NOT_SPECIFIED from quantum.api.v2.router import APIRouter from quantum.common import config from quantum.common import exceptions as q_exc @@ -140,12 +142,16 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase): 'cidr': cidr, 'ip_version': 4, 'tenant_id': self._tenant_id}} - for arg in ('gateway_ip', 'allocation_pools', + for arg in ('allocation_pools', 'ip_version', 'tenant_id', 'enable_dhcp'): # Arg must be present and not null (but can be false) if arg in kwargs and kwargs[arg] is not None: data['subnet'][arg] = kwargs[arg] + + if kwargs.get('gateway_ip', ATTR_NOT_SPECIFIED) != ATTR_NOT_SPECIFIED: + data['subnet']['gateway_ip'] = kwargs['gateway_ip'] + subnet_req = self.new_create_request('subnets', data, fmt) if (kwargs.get('set_context') and 'tenant_id' in kwargs): # create a specific auth context for this request @@ -241,7 +247,7 @@ class QuantumDbPluginV2TestCase(unittest2.TestCase): @contextlib.contextmanager def subnet(self, network=None, - gateway_ip=None, + gateway_ip=ATTR_NOT_SPECIFIED, cidr='10.0.0.0/24', fmt='json', ip_version=4, @@ -725,7 +731,7 @@ class TestPortsV2(QuantumDbPluginV2TestCase): net_id=net_id, cidr='2607:f0d0:1002:51::0/124', ip_version=6, - gateway_ip=None) + gateway_ip=ATTR_NOT_SPECIFIED) subnet2 = self.deserialize(fmt, res) kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id']}, @@ -1220,6 +1226,27 @@ class TestSubnetsV2(QuantumDbPluginV2TestCase): cidr=cidr, allocation_pools=allocation_pools) + def test_create_subnet_with_none_gateway(self): + cidr = '10.0.0.0/24' + self._test_create_subnet(gateway_ip=None, + cidr=cidr) + + def test_create_subnet_with_none_gateway_fully_allocated(self): + cidr = '10.0.0.0/24' + allocation_pools = [{'start': '10.0.0.1', + 'end': '10.0.0.254'}] + self._test_create_subnet(gateway_ip=None, + cidr=cidr, + allocation_pools=allocation_pools) + + def test_create_subnet_with_none_gateway_allocation_pool(self): + cidr = '10.0.0.0/24' + allocation_pools = [{'start': '10.0.0.2', + 'end': '10.0.0.100'}] + self._test_create_subnet(gateway_ip=None, + cidr=cidr, + allocation_pools=allocation_pools) + def test_create_subnet_with_v6_allocation_pool(self): gateway_ip = 'fe80::1' cidr = 'fe80::0/80'