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:
@@ -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:
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user