Support creating network with pool uuid
Right now, we can create network with pool name, but it doesn't work well if there are two subnetpools with the same name. This commit add support for pool uuid as an alternative. Implements: blueprint existing-subnetpool Closes-Bug: #1659434 Change-Id: Ib7c2bac86a1b1647c2da9684bc4317767116d7aa
This commit is contained in:
parent
9e99cc0242
commit
2e6f4cd1cb
18
README.rst
18
README.rst
|
@ -405,10 +405,11 @@ Limitations
|
|||
-----------
|
||||
|
||||
To create Docker networks with subnets having same/overlapping cidr, it is
|
||||
expected to pass unique pool name for each such network creation Docker
|
||||
command. Docker cli options -o and --ipam-opt should be used to pass pool
|
||||
names as shown below::
|
||||
expected to pre-create Neutron subnetpool and pass the pool name for each
|
||||
such network creation Docker command. Docker cli options -o and --ipam-opt
|
||||
should be used to pass pool names as shown below::
|
||||
|
||||
$ neutron subnetpool-create --pool-prefix 10.0.0.0/24 neutron_pool1
|
||||
$ sudo docker network create --driver=kuryr --ipam-driver=kuryr \
|
||||
--subnet 10.0.0.0/16 --gateway=10.0.0.1 --ip-range 10.0.0.0/24 \
|
||||
-o neutron.pool.name=neutron_pool1 \
|
||||
|
@ -419,6 +420,7 @@ names as shown below::
|
|||
Now Docker user creates another network with same cidr as the previous one,
|
||||
i.e 10.0.0.0/16, but with different pool name, neutron_pool2::
|
||||
|
||||
$ neutron subnetpool-create --pool-prefix 10.0.0.0/24 neutron_pool2
|
||||
$ sudo docker network create --driver=kuryr --ipam-driver=kuryr \
|
||||
--subnet 10.0.0.0/16 --gateway=10.0.0.1 --ip-range 10.0.0.0/24 \
|
||||
-o neutron.pool.name=neutron_pool2 \
|
||||
|
@ -426,6 +428,16 @@ i.e 10.0.0.0/16, but with different pool name, neutron_pool2::
|
|||
bar
|
||||
397badb51ebca09339cb17aaec05e48ffe60659ced6f3fc41b020b0eb506d786
|
||||
|
||||
Alternatively, Docker user can pass an existing pool uuid if there are multiple
|
||||
pools with the same name::
|
||||
|
||||
$ sudo sudo docker network create --driver=kuryr --ipam-driver=kuryr \
|
||||
--subnet 10.0.0.0/16 --gateway=10.0.0.1 --ip-range 10.0.0.0/24 \
|
||||
-o neutron.pool.uuid=2d5767a4-6c96-4522-ab1d-a06d7adc9e23 \
|
||||
--ipam-opt=neutron.pool.uuid=2d5767a4-6c96-4522-ab1d-a06d7adc9e23 \
|
||||
bar
|
||||
0aed1efbe21f6c29dc77eccd0dd17ba729274f9275070e1469230c864f9054ff
|
||||
|
||||
|
||||
External Resources
|
||||
------------------
|
||||
|
|
|
@ -39,5 +39,6 @@ NETWORK_GATEWAY_OPTIONS = 'com.docker.network.gateway'
|
|||
NETWORK_GENERIC_OPTIONS = 'com.docker.network.generic'
|
||||
NEUTRON_NAME_OPTION = 'neutron.net.name'
|
||||
NEUTRON_POOL_NAME_OPTION = 'neutron.pool.name'
|
||||
NEUTRON_POOL_UUID_OPTION = 'neutron.pool.uuid'
|
||||
NEUTRON_UUID_OPTION = 'neutron.net.uuid'
|
||||
REQUEST_ADDRESS_TYPE = 'RequestAddressType'
|
||||
|
|
|
@ -614,17 +614,21 @@ def network_driver_create_network():
|
|||
neutron_uuid = generic_options.get(const.NEUTRON_UUID_OPTION)
|
||||
neutron_name = generic_options.get(const.NEUTRON_NAME_OPTION)
|
||||
pool_name = generic_options.get(const.NEUTRON_POOL_NAME_OPTION)
|
||||
pool_id = generic_options.get(const.NEUTRON_POOL_UUID_OPTION)
|
||||
|
||||
if not pool_name:
|
||||
pool_name = lib_utils.get_neutron_subnetpool_name(pool_cidr)
|
||||
|
||||
pools = _get_subnetpools_by_attrs(name=pool_name)
|
||||
if pools:
|
||||
pool_id = pools[0]['id']
|
||||
if pool_id:
|
||||
pools = _get_subnetpools_by_attrs(id=pool_id)
|
||||
elif pool_name:
|
||||
pools = _get_subnetpools_by_attrs(name=pool_name)
|
||||
else:
|
||||
pool_name = lib_utils.get_neutron_subnetpool_name(pool_cidr)
|
||||
pools = _get_subnetpools_by_attrs(name=pool_name)
|
||||
|
||||
if not pools:
|
||||
raise exceptions.KuryrException(
|
||||
("Specified pool name({0}) does not "
|
||||
"exist.").format(pool_name))
|
||||
("Specified pool id/name({0}) does not "
|
||||
"exist.").format(pool_id or pool_name))
|
||||
pool_id = pools[0]['id']
|
||||
|
||||
# let the user override the driver default
|
||||
if not neutron_uuid and not neutron_name:
|
||||
|
@ -1253,13 +1257,14 @@ def ipam_request_pool():
|
|||
requested_pool = json_data['Pool']
|
||||
requested_subpool = json_data['SubPool']
|
||||
v6 = json_data['V6']
|
||||
pool_id = ''
|
||||
subnet_cidr = ''
|
||||
pool_name = ''
|
||||
pool_id = ''
|
||||
pools = []
|
||||
options = json_data.get('Options')
|
||||
if options:
|
||||
pool_name = options.get(const.NEUTRON_POOL_NAME_OPTION)
|
||||
pool_id = options.get(const.NEUTRON_POOL_UUID_OPTION)
|
||||
if requested_pool:
|
||||
LOG.info(_LI("Creating subnetpool with the given pool CIDR"))
|
||||
if requested_subpool:
|
||||
|
@ -1272,7 +1277,7 @@ def ipam_request_pool():
|
|||
LOG.warning(_LW("There is already existing subnet for the "
|
||||
"same cidr. Please check and specify pool name "
|
||||
"in Options."))
|
||||
if not pool_name:
|
||||
if not pool_name and not pool_id:
|
||||
pool_name = lib_utils.get_neutron_subnetpool_name(subnet_cidr)
|
||||
pools = _get_subnetpools_by_attrs(name=pool_name)
|
||||
if len(pools):
|
||||
|
@ -1289,11 +1294,14 @@ def ipam_request_pool():
|
|||
pool = created_subnetpool_response['subnetpool']
|
||||
pool_id = pool['id']
|
||||
else:
|
||||
existing_pools = _get_subnetpools_by_attrs(name=pool_name)
|
||||
if pool_id:
|
||||
existing_pools = _get_subnetpools_by_attrs(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))
|
||||
("Specified subnetpool id/name({0}) does not "
|
||||
"exist.").format(pool_id or pool_name))
|
||||
pool_id = existing_pools[0]['id']
|
||||
LOG.info(_LI("Using existing Neutron subnetpool %s successfully"),
|
||||
pool_id)
|
||||
|
|
|
@ -519,6 +519,137 @@ class TestKuryr(base.TestKuryrBase):
|
|||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
||||
|
||||
@ddt.data((True), (False))
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.create_subnet')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.add_tag')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.create_network')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks')
|
||||
@mock.patch(
|
||||
'kuryr_libnetwork.controllers.app.driver.get_default_network_id')
|
||||
def test_network_driver_create_network_with_pool_id_option(self,
|
||||
driver_default_net, mock_get_default_network_id,
|
||||
mock_list_networks, mock_create_network, mock_add_tag,
|
||||
mock_create_subnet, mock_list_subnetpools,
|
||||
mock_list_subnets):
|
||||
fake_kuryr_subnetpool_id = uuidutils.generate_uuid()
|
||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
||||
fake_kuryr_subnetpool_id)
|
||||
docker_network_id = lib_utils.get_hash()
|
||||
|
||||
# The following fake response is retrieved from the Neutron doc:
|
||||
# http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa
|
||||
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
||||
driver_value = fake_neutron_net_id if driver_default_net else None
|
||||
mock_get_default_network_id.return_value = driver_value
|
||||
|
||||
fake_network = {
|
||||
"status": "ACTIVE",
|
||||
"subnets": [],
|
||||
"admin_state_up": True,
|
||||
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
|
||||
"router:external": False,
|
||||
"segments": [],
|
||||
"shared": False,
|
||||
"id": fake_neutron_net_id,
|
||||
}
|
||||
|
||||
if driver_value:
|
||||
fake_existing_networks_response = {
|
||||
"networks": [fake_network]
|
||||
}
|
||||
mock_list_networks.return_value = fake_existing_networks_response
|
||||
else:
|
||||
fake_create_network_request = {
|
||||
"network": {
|
||||
"name": utils.make_net_name(docker_network_id),
|
||||
"admin_state_up": True
|
||||
}
|
||||
}
|
||||
fake_network['name'] = utils.make_net_name(docker_network_id)
|
||||
# The following fake response is retrieved from the Neutron doc:
|
||||
# http://developer.openstack.org/api-ref-networking-v2.html#createNetwork # noqa
|
||||
fake_create_network_response = {
|
||||
"network": fake_network
|
||||
}
|
||||
mock_create_network.return_value = fake_create_network_response
|
||||
|
||||
tags = utils.create_net_tags(docker_network_id)
|
||||
|
||||
fake_existing_subnets_response = {
|
||||
"subnets": []
|
||||
}
|
||||
fake_cidr_v4 = '192.168.42.0/24'
|
||||
|
||||
fake_subnet_request = {
|
||||
"subnets": [{
|
||||
'name': utils.make_subnet_name(fake_cidr_v4),
|
||||
'network_id': fake_neutron_net_id,
|
||||
'ip_version': 4,
|
||||
'cidr': fake_cidr_v4,
|
||||
'enable_dhcp': app.enable_dhcp,
|
||||
'gateway_ip': '192.168.42.1',
|
||||
'subnetpool_id': fake_kuryr_subnetpool_id,
|
||||
}]
|
||||
}
|
||||
subnet_v4_id = uuidutils.generate_uuid()
|
||||
fake_v4_subnet = self._get_fake_v4_subnet(
|
||||
fake_neutron_net_id, subnet_v4_id,
|
||||
name=fake_cidr_v4, cidr=fake_cidr_v4)
|
||||
fake_subnet_response = {
|
||||
'subnets': [
|
||||
fake_v4_subnet['subnet']
|
||||
]
|
||||
}
|
||||
network_request = {
|
||||
'NetworkID': docker_network_id,
|
||||
'IPv4Data': [{
|
||||
'AddressSpace': 'foo',
|
||||
'Pool': '192.168.42.0/24',
|
||||
'Gateway': '192.168.42.1/24',
|
||||
}],
|
||||
'IPv6Data': [{
|
||||
'AddressSpace': 'bar',
|
||||
'Pool': 'fe80::/64',
|
||||
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
||||
}],
|
||||
'Options': {
|
||||
'com.docker.network.enable_ipv6': False,
|
||||
'com.docker.network.generic': {
|
||||
'neutron.pool.uuid': fake_kuryr_subnetpool_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
mock_create_subnet.return_value = fake_subnet_response
|
||||
mock_list_subnetpools.return_value = {'subnetpools':
|
||||
kuryr_subnetpools['subnetpools']}
|
||||
mock_list_subnets.return_value = fake_existing_subnets_response
|
||||
response = self.app.post('/NetworkDriver.CreateNetwork',
|
||||
content_type='application/json',
|
||||
data=jsonutils.dumps(network_request))
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
mock_get_default_network_id.assert_any_call()
|
||||
|
||||
for tag in tags:
|
||||
mock_add_tag.assert_any_call('networks',
|
||||
fake_neutron_net_id, tag)
|
||||
if driver_value:
|
||||
mock_list_networks.assert_called_with(id=fake_neutron_net_id)
|
||||
mock_add_tag.assert_any_call('networks', fake_neutron_net_id,
|
||||
'kuryr.net.existing')
|
||||
else:
|
||||
mock_create_network.assert_called_with(fake_create_network_request)
|
||||
|
||||
mock_create_subnet.assert_called_with(fake_subnet_request)
|
||||
mock_list_subnetpools.assert_called_with(id=fake_kuryr_subnetpool_id)
|
||||
mock_list_subnets.assert_called_with(network_id=fake_neutron_net_id,
|
||||
cidr=fake_cidr_v4)
|
||||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
|
||||
|
||||
@ddt.data((True), (False))
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.create_subnet')
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.create_network')
|
||||
|
|
|
@ -148,6 +148,39 @@ 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.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_id_option(self,
|
||||
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()
|
||||
if pool_cidr == FAKE_IP4_CIDR:
|
||||
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
||||
fake_kuryr_subnetpool_id, prefixes=[pool_cidr])
|
||||
else:
|
||||
kuryr_subnetpools = self._get_fake_v6_subnetpools(
|
||||
fake_kuryr_subnetpool_id, prefixes=[pool_cidr])
|
||||
mock_list_subnetpools.return_value = kuryr_subnetpools
|
||||
|
||||
fake_request = {
|
||||
'AddressSpace': '',
|
||||
'Pool': pool_cidr,
|
||||
'SubPool': pool_cidr,
|
||||
'Options': {'neutron.pool.uuid': fake_kuryr_subnetpool_id},
|
||||
'V6': False
|
||||
}
|
||||
response = self.app.post('/IpamDriver.RequestPool',
|
||||
content_type='application/json',
|
||||
data=jsonutils.dumps(fake_request))
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
mock_list_subnets.assert_called_with(cidr=pool_cidr)
|
||||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
|
||||
|
||||
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
||||
def test_ipam_driver_request_pool_with_default_v6pool(self,
|
||||
mock_list_subnetpools):
|
||||
|
|
Loading…
Reference in New Issue