Support creating from existing subnetpool

To use this feature, users need to pre-create the subnetpool and
pass the pool name to kuryr. For example:

$ docker network create -d kuryr --ipam-driver=kuryr ... \
    -o neutron.pool.name=testpool \
    --ipam-opt neutron.pool.name=testpool \
    foo

Kuryr will look for the existing subnetpool in neutron instead of
creating a new subnetpool. If the network is deleted, the existing
subnetpool will not be deleted.

NOTE: the option 'neutron.pool.name' was used to specify an custom
name of subnetpool. This commit will the semantic of this option.

Implements: blueprint existing-subnetpool
Change-Id: I73f6c17e0e941ef9dbd20591002fdf96c59e6424
This commit is contained in:
Hongbin Lu
2017-01-29 18:44:59 +00:00
parent 1033c972c3
commit 9e99cc0242
3 changed files with 84 additions and 17 deletions

View File

@@ -1280,7 +1280,6 @@ def ipam_request_pool():
"Another pool with same cidr exist. ipam and network"
" options not used to pass pool name")
if not pools:
new_subnetpool = {
'name': pool_name,
'default_prefixlen': cidr.prefixlen,
@@ -1289,6 +1288,15 @@ def ipam_request_pool():
{'subnetpool': new_subnetpool})
pool = created_subnetpool_response['subnetpool']
pool_id = pool['id']
else:
existing_pools = _get_subnetpools_by_attrs(name=pool_name)
if not existing_pools:
raise exceptions.KuryrException(
("Specified subnetpool name({0}) does not "
"exist.").format(pool_name))
pool_id = existing_pools[0]['id']
LOG.info(_LI("Using existing Neutron subnetpool %s successfully"),
pool_id)
else:
if v6:
default_pool_list = SUBNET_POOLS_V6
@@ -1500,6 +1508,15 @@ def ipam_release_pool():
if pool_id in tmp_subnet.get('tags', []):
_neutron_subnet_remove_tag(tmp_subnet['id'], pool_id)
break
pools = _get_subnetpools_by_attrs(id=pool_id)
if pools:
pool_name = pools[0]['name']
if not pool_name.startswith(cfg.CONF.subnetpool_name_prefix):
LOG.debug('Skip the cleanup since this is an existing Neutron '
'subnetpool.')
return flask.jsonify(const.SCHEMA['SUCCESS'])
try:
app.neutron.delete_subnetpool(pool_id)
except n_exceptions.Conflict as ex:

View File

@@ -112,22 +112,16 @@ class TestKuryrIpam(base.TestKuryrBase):
decoded_json = jsonutils.loads(response.data)
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
@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')
@ddt.data((FAKE_IP4_CIDR), (FAKE_IP6_CIDR))
def test_ipam_driver_request_pool_with_pool_name_option(self,
pool_cidr, mock_list_subnets, mock_create_subnetpool):
pool_cidr, mock_list_subnets, mock_list_subnetpools):
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': prefixlen,
'prefixes': [pool_cidr]}
if pool_cidr == FAKE_IP4_CIDR:
kuryr_subnetpools = self._get_fake_v4_subnetpools(
fake_kuryr_subnetpool_id, prefixes=[pool_cidr],
@@ -136,17 +130,13 @@ class TestKuryrIpam(base.TestKuryrBase):
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]
}
mock_create_subnetpool.return_value = fake_subnetpool_response
mock_list_subnetpools.return_value = kuryr_subnetpools
fake_request = {
'AddressSpace': '',
'Pool': pool_cidr,
'SubPool': pool_cidr,
'Options': {'neutron.pool.name': 'fake_pool_name'},
'Options': {'neutron.pool.name': fake_name},
'V6': False
}
response = self.app.post('/IpamDriver.RequestPool',
@@ -155,8 +145,6 @@ class TestKuryrIpam(base.TestKuryrBase):
self.assertEqual(200, response.status_code)
mock_list_subnets.assert_called_with(cidr=pool_cidr)
mock_create_subnetpool.assert_called_with(
{'subnetpool': new_subnetpool})
decoded_json = jsonutils.loads(response.data)
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
@@ -243,6 +231,54 @@ class TestKuryrIpam(base.TestKuryrBase):
fake_kuryr_subnetpool_id)
mock_delete_subnetpool.assert_called_with(fake_kuryr_subnetpool_id)
@mock.patch('kuryr_libnetwork.controllers.app.neutron.remove_tag')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
@mock.patch('kuryr_libnetwork.controllers.app')
@ddt.data((True), (False))
def test_ipam_driver_release_pool_with_pool_name_option(
self, use_tag_ext, mock_app, mock_list_subnetpools,
mock_list_subnets, mock_remove_tag):
mock_app.tag_ext = use_tag_ext
fake_kuryr_subnetpool_id = uuidutils.generate_uuid()
fake_subnetpool_name = 'fake_pool_name'
kuryr_subnetpools = self._get_fake_v4_subnetpools(
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
name=fake_subnetpool_name)
mock_list_subnetpools.return_value = kuryr_subnetpools
docker_endpoint_id = lib_utils.get_hash()
neutron_network_id = uuidutils.generate_uuid()
subnet_v4_id = uuidutils.generate_uuid()
fake_v4_subnet = self._get_fake_v4_subnet(
neutron_network_id, docker_endpoint_id, subnet_v4_id,
subnetpool_id=fake_kuryr_subnetpool_id,
cidr=FAKE_IP4_CIDR)
fake_subnet_response = {
'subnets': [
fake_v4_subnet['subnet']
]
}
mock_list_subnets.return_value = fake_subnet_response
fake_request = {
'PoolID': fake_kuryr_subnetpool_id
}
response = self.app.post('/IpamDriver.ReleasePool',
content_type='application/json',
data=jsonutils.dumps(fake_request))
self.assertEqual(200, response.status_code)
if mock_app.tag_ext:
mock_list_subnetpools.assert_called_with(
id=fake_kuryr_subnetpool_id)
mock_list_subnets.assert_called_with(
cidr=FAKE_IP4_CIDR)
mock_remove_tag.assert_called_with('subnets',
subnet_v4_id,
fake_kuryr_subnetpool_id)
@mock.patch('kuryr_libnetwork.controllers._neutron_port_add_tag')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.create_port')
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')

View File

@@ -0,0 +1,14 @@
---
features:
- |
Support creating a Docker network with existing subnetpool. Users can use
the option "neutron.pool.name" to specify the name of existing neutron
subnetpool.
upgrade:
- |
The semantic of the option "neutron.pool.name" is changed. This option was
used to specify a custom name of the creating subnetpool, and now it is
used to specify the name of a pre-existing subnetpool. As a result,
subnetpools created with custom name in before are now treated as external
resources and won't be cleanup on deletion. Users need to cleanup the
resources manually.