diff --git a/kuryr_libnetwork/schemata/commons.py b/kuryr_libnetwork/schemata/commons.py index 33429e20..75ed4d48 100755 --- a/kuryr_libnetwork/schemata/commons.py +++ b/kuryr_libnetwork/schemata/commons.py @@ -38,6 +38,7 @@ IPV6_PATTERN = EPSILON_PATTERN + u'|^' + IPV6_PATTERN_BASE + u'$' CIDRV6_PATTERN = EPSILON_PATTERN + u'|^(' + IPV6_PATTERN_BASE + \ u'(/(1[0-2][0-8]|[1-9]?[0-9]))' + u')$' IPV4_OR_IPV6_PATTERN = IPV4_PATTERN + u'|^' + IPV6_PATTERN_BASE + u'$' +CIDRV4_OR_CIDRV6_PATTERN = CIDRV4_PATTERN + u'|^' + CIDRV6_PATTERN + u'$' UUID_BASE = u'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' UUID_PATTERN = EPSILON_PATTERN + u'|' + UUID_BASE @@ -109,6 +110,11 @@ COMMONS = { u'description': u'A IPv4 CIDR of the subnet.', u'example': u'10.0.0.0/24' }, + u'cidrv4_or_cidrv6': { + u'pattern': CIDRV4_OR_CIDRV6_PATTERN, + u'type': u'string', + u'description': u'An IPv4 or IPv6 CIDR of the subnet.' + }, u'id': { u'pattern': u'^([0-9a-f]{64})$', u'type': u'string', diff --git a/kuryr_libnetwork/schemata/request_pool.py b/kuryr_libnetwork/schemata/request_pool.py index c5858cf7..cec8ba11 100644 --- a/kuryr_libnetwork/schemata/request_pool.py +++ b/kuryr_libnetwork/schemata/request_pool.py @@ -34,12 +34,12 @@ REQUEST_POOL_SCHEMA = { u'Pool': { u'description': u'A range of IP Addresses represented in ' u'CIDR format address/mask.', - u'$ref': u'#/definitions/commons/definitions/cidr' + u'$ref': u'#/definitions/commons/definitions/cidrv4_or_cidrv6' }, u'SubPool': { u'description': u'A subset of IP range from Pool in' u'CIDR format address/mask.', - u'$ref': u'#/definitions/commons/definitions/cidr' + u'$ref': u'#/definitions/commons/definitions/cidrv4_or_cidrv6' }, u'Options': { u'type': [u'object', u'null'], diff --git a/kuryr_libnetwork/tests/unit/base.py b/kuryr_libnetwork/tests/unit/base.py index 6dfc671f..5137273c 100644 --- a/kuryr_libnetwork/tests/unit/base.py +++ b/kuryr_libnetwork/tests/unit/base.py @@ -98,7 +98,8 @@ class TestKuryrBase(TestCase): return v4_subnetpools @staticmethod - def _get_fake_v6_subnetpools(subnetpool_id, prefixes=['fe80::/64']): + def _get_fake_v6_subnetpools(subnetpool_id, prefixes=['fe80::/64'], + name="kuryr6"): # The following fake response is retrieved from the Neutron doc: # http://developer.openstack.org/api-ref-networking-v2-ext.html#listSubnetPools # noqa v6_subnetpools = { @@ -108,7 +109,7 @@ class TestKuryrBase(TestCase): "default_prefixlen": "64", "id": subnetpool_id, "max_prefixlen": "64", - "name": "kuryr6", + "name": name, "default_quota": None, "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", "prefixes": prefixes, diff --git a/kuryr_libnetwork/tests/unit/test_kuryr_ipam.py b/kuryr_libnetwork/tests/unit/test_kuryr_ipam.py index 5c0ecbbd..22794087 100644 --- a/kuryr_libnetwork/tests/unit/test_kuryr_ipam.py +++ b/kuryr_libnetwork/tests/unit/test_kuryr_ipam.py @@ -10,6 +10,9 @@ # License for the specific language governing permissions and limitations # under the License. +import ipaddress +import six + import ddt import mock from oslo_serialization import jsonutils @@ -25,6 +28,7 @@ from kuryr_libnetwork import utils FAKE_IP4_CIDR = '10.0.0.0/16' +FAKE_IP6_CIDR = 'fe80::/64' @ddt.ddt @@ -60,21 +64,28 @@ class TestKuryrIpam(base.TestKuryrBase): @mock.patch('kuryr_libnetwork.controllers.app.neutron.create_subnetpool') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets') - def test_ipam_driver_request_pool_with_user_pool(self, + @ddt.data((FAKE_IP4_CIDR), (FAKE_IP6_CIDR)) + def test_ipam_driver_request_pool_with_user_pool(self, pool_cidr, mock_list_subnets, mock_list_subnetpools, mock_create_subnetpool): fake_subnet = {"subnets": []} mock_list_subnets.return_value = fake_subnet - pool_name = lib_utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR) + pool_name = lib_utils.get_neutron_subnetpool_name(pool_cidr) + prefixlen = ipaddress.ip_network(six.text_type(pool_cidr)).prefixlen new_subnetpool = { 'name': pool_name, - 'default_prefixlen': 16, - 'prefixes': [FAKE_IP4_CIDR]} + 'default_prefixlen': prefixlen, + 'prefixes': [pool_cidr]} fake_kuryr_subnetpool_id = uuidutils.generate_uuid() fake_name = pool_name - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) + if pool_cidr == FAKE_IP4_CIDR: + kuryr_subnetpools = self._get_fake_v4_subnetpools( + fake_kuryr_subnetpool_id, prefixes=[pool_cidr], + name=fake_name) + else: + kuryr_subnetpools = self._get_fake_v6_subnetpools( + fake_kuryr_subnetpool_id, prefixes=[pool_cidr], + name=fake_name) mock_list_subnetpools.return_value = {'subnetpools': []} fake_subnetpool_response = { 'subnetpool': kuryr_subnetpools['subnetpools'][0] @@ -84,7 +95,7 @@ class TestKuryrIpam(base.TestKuryrBase): fake_request = { 'AddressSpace': '', - 'Pool': FAKE_IP4_CIDR, + 'Pool': pool_cidr, 'SubPool': '', # In the case --ip-range is not given 'Options': {}, 'V6': False @@ -94,7 +105,7 @@ class TestKuryrIpam(base.TestKuryrBase): data=jsonutils.dumps(fake_request)) self.assertEqual(200, response.status_code) - mock_list_subnets.assert_called_with(cidr=FAKE_IP4_CIDR) + mock_list_subnets.assert_called_with(cidr=pool_cidr) mock_list_subnetpools.assert_called_with(name=fake_name) mock_create_subnetpool.assert_called_with( {'subnetpool': new_subnetpool}) @@ -103,21 +114,28 @@ class TestKuryrIpam(base.TestKuryrBase): @mock.patch('kuryr_libnetwork.controllers.app.neutron.create_subnetpool') @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets') + @ddt.data((FAKE_IP4_CIDR), (FAKE_IP6_CIDR)) def test_ipam_driver_request_pool_with_pool_name_option(self, - mock_list_subnets, mock_create_subnetpool): + pool_cidr, mock_list_subnets, mock_create_subnetpool): fake_subnet = {"subnets": []} mock_list_subnets.return_value = fake_subnet fake_kuryr_subnetpool_id = uuidutils.generate_uuid() fake_name = 'fake_pool_name' + prefixlen = ipaddress.ip_network(six.text_type(pool_cidr)).prefixlen new_subnetpool = { 'name': fake_name, - 'default_prefixlen': 16, - 'prefixes': [FAKE_IP4_CIDR]} + 'default_prefixlen': prefixlen, + 'prefixes': [pool_cidr]} - kuryr_subnetpools = self._get_fake_v4_subnetpools( - fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR], - name=fake_name) + if pool_cidr == FAKE_IP4_CIDR: + kuryr_subnetpools = self._get_fake_v4_subnetpools( + fake_kuryr_subnetpool_id, prefixes=[pool_cidr], + name=fake_name) + else: + kuryr_subnetpools = self._get_fake_v6_subnetpools( + fake_kuryr_subnetpool_id, prefixes=[pool_cidr], + name=fake_name) fake_subnetpool_response = { 'subnetpool': kuryr_subnetpools['subnetpools'][0] } @@ -126,8 +144,8 @@ class TestKuryrIpam(base.TestKuryrBase): fake_request = { 'AddressSpace': '', - 'Pool': FAKE_IP4_CIDR, - 'SubPool': '', # In the case --ip-range is not given + 'Pool': pool_cidr, + 'SubPool': pool_cidr, 'Options': {'neutron.pool.name': 'fake_pool_name'}, 'V6': False } @@ -136,7 +154,7 @@ class TestKuryrIpam(base.TestKuryrBase): data=jsonutils.dumps(fake_request)) self.assertEqual(200, response.status_code) - mock_list_subnets.assert_called_with(cidr=FAKE_IP4_CIDR) + mock_list_subnets.assert_called_with(cidr=pool_cidr) mock_create_subnetpool.assert_called_with( {'subnetpool': new_subnetpool}) decoded_json = jsonutils.loads(response.data)