Short-Term fix for overlapping cidrs using docker options

A quick alternative solution, until PRs to upstream Docker get accepted,
can be Docker user passing pool name to both Kuryr ipam driver and
Kuryr network driver using corresponding network and ipam options
respectively:

       $sudo docker network create --driver=kuryr --ipam-driver=kuryr \
       --subnet 10.0.0.0/16 --ip-range 10.0.0.0/24 \
       -o neutron.pool.name=neutron_pool1 \
       --ipam-opt=neutron.pool.name=neutron_pool1 \
       foo
      eddb51ebca09339cb17aaec05e48ffe60659ced6f3fc41b020b0eb506d364

Now Docker user creates another network with same cidr as the previous,
i.e 10.0.0.0/16, but with different pool name, neutron_pool2:

    $sudo docker network create --driver=kuryr --ipam-driver=kuryr \
       --subnet 10.0.0.0/16 --ip-range 10.0.0.0/24 \
       -o neutron.pool.name=neutron_pool2 \
       --ipam-opt=neutron.pool.name=neutron_pool2 \
       bar
    397badb51ebca09339cb17aaec05e48ffe60659ced6f3fc41b020b0eb506d786

At ``/IpamDriver.RequestAddress``, correct subnet will be filtered out using
corresponding pool name received from the libnetwork as explained above.

Please refer https://review.openstack.org/#/c/326894/6

TODO: unit test cases covering docker option scenario

DocImpact
Change-Id: I7090027e68e8c78219a387da66e1bd30be900ab1
Closes-bug: #1585572
This commit is contained in:
vikaschoudhary16 2016-06-17 16:23:34 +05:30
parent 4dc7caf89c
commit 709fede534
6 changed files with 490 additions and 61 deletions

View File

@ -43,3 +43,4 @@ NETWORK_GENERIC_OPTIONS = 'com.docker.network.generic'
NEUTRON_UUID_OPTION = 'neutron.net.uuid'
NEUTRON_NAME_OPTION = 'neutron.net.name'
KURYR_EXISTING_NEUTRON_NET = 'kuryr.net.existing'
NEUTRON_POOL_NAME_OPTION = 'neutron.pool.name'

View File

@ -171,11 +171,6 @@ def _get_networks_by_attrs(**attrs):
def _get_subnets_by_attrs(**attrs):
subnets = app.neutron.list_subnets(**attrs)
if len(subnets.get('subnets', [])) > 2: # subnets for IPv4 and/or IPv6
raise exceptions.DuplicatedResourceException(
"Multiple Neutron subnets exist for the params {0} "
.format(', '.join(['{0}={1}'.format(k, v)
for k, v in attrs.items()])))
return subnets['subnets']
@ -214,6 +209,11 @@ def _get_subnets_by_interface_cidr(neutron_network_id,
str(cidr.prefixlen)])
subnets = _get_subnets_by_attrs(
network_id=neutron_network_id, cidr=subnet_cidr)
if len(subnets) > 2:
raise exceptions.DuplicatedResourceException(
"Multiple Neutron subnets exist for the network_id={0}"
"and cidr={1}"
.format(neutron_network_id, cidr))
return subnets
@ -512,12 +512,24 @@ def network_driver_create_network():
neutron_uuid = None
neutron_name = None
pool_name = ''
pool_id = ''
options = json_data.get('Options')
if options:
generic_options = options.get(const.NETWORK_GENERIC_OPTIONS)
if generic_options:
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)
if pool_name:
pools = _get_subnetpools_by_attrs(name=pool_name)
if pools:
pool_id = pools[0]['id']
else:
raise exceptions.KuryrException(
("Specified pool name({0}) does not "
"exist.").format(pool_name))
if not neutron_uuid and not neutron_name:
network = app.neutron.create_network(
@ -565,6 +577,11 @@ def network_driver_create_network():
subnet_cidr = '/'.join([subnet_network, str(cidr.prefixlen)])
subnets = _get_subnets_by_attrs(
network_id=network_id, cidr=subnet_cidr)
if len(subnets) > 1:
raise exceptions.DuplicatedResourceException(
"Multiple Neutron subnets exist for the network_id={0}"
"and cidr={1}".format(network_id, cidr))
if not subnets:
new_subnets = [{
'name': pool_cidr,
@ -573,6 +590,8 @@ def network_driver_create_network():
'cidr': subnet_cidr,
'enable_dhcp': app.enable_dhcp,
}]
if pool_id:
new_subnets[0]['subnetpool_id'] = pool_id
if gateway_ip:
new_subnets[0]['gateway_ip'] = gateway_ip
@ -642,6 +661,10 @@ def network_driver_delete_network():
neutron_network_id = filtered_networks[0]['id']
filtered_subnets = _get_subnets_by_attrs(
network_id=neutron_network_id)
if len(filtered_subnets) > 2: # subnets for IPv4 and/or IPv6
raise exceptions.DuplicatedResourceException(
"Multiple Neutron subnets exist for the network_id={0} "
.format(neutron_network_id))
for subnet in filtered_subnets:
try:
subnetpool_id = subnet.get('subnetpool_id', None)
@ -836,6 +859,10 @@ def network_driver_join():
.format(neutron_port_name))
neutron_port = filtered_ports[0]
all_subnets = _get_subnets_by_attrs(network_id=neutron_network_id)
if len(all_subnets) > 2: # subnets for IPv4 and/or IPv6
raise exceptions.DuplicatedResourceException(
"Multiple Neutron subnets exist for the network_id={0} "
.format(neutron_network_id))
try:
ifname, peer_name, (stdout, stderr) = binding.port_bind(
@ -1046,6 +1073,11 @@ def ipam_request_pool():
v6 = json_data['V6']
pool_id = ''
subnet_cidr = ''
pool_name = ''
pools = []
options = json_data.get('Options')
if options:
pool_name = options.get(const.NEUTRON_POOL_NAME_OPTION)
if requested_pool:
app.logger.info(_LI("Creating subnetpool with the given pool CIDR"))
if requested_subpool:
@ -1053,11 +1085,14 @@ def ipam_request_pool():
else:
cidr = netaddr.IPNetwork(requested_pool)
subnet_cidr = _get_subnet_cidr_using_cidr(cidr)
pool_name = utils.get_neutron_subnetpool_name(subnet_cidr)
# Check if requested pool already exist
pools = _get_subnetpools_by_attrs(name=pool_name)
if pools:
pool_id = pools[0]['id']
if not pool_name:
pool_name = utils.get_neutron_subnetpool_name(subnet_cidr)
pools = _get_subnetpools_by_attrs(name=pool_name)
if len(pools):
raise exceptions.KuryrException(
"Another pool with same cidr exist. ipam and network"
" options not used to pass pool name")
if not pools:
new_subnetpool = {
'name': pool_name,
@ -1085,6 +1120,7 @@ def ipam_request_pool():
subnet_cidr = _get_subnet_cidr_using_cidr(cidr)
else:
app.logger.error(_LE("Default neutron pools not found."))
req_pool_res = {'PoolID': pool_id,
'Pool': subnet_cidr}
return flask.jsonify(req_pool_res)
@ -1123,6 +1159,7 @@ def ipam_request_address():
is_gateway = False
allocated_address = ''
subnet_cidr = ''
subnet = {}
pool_prefix_len = ''
pools = _get_subnetpools_by_attrs(id=pool_id)
if pools:
@ -1143,56 +1180,64 @@ def ipam_request_address():
"No subnetpools with id {0} is found."
.format(pool_id))
# check if any subnet with matching cidr is present
subnets = _get_subnets_by_attrs(cidr=subnet_cidr)
subnets_by_cidr = _get_subnets_by_attrs(cidr=subnet_cidr)
# Check if the port is gateway
options = json_data.get('Options')
if options:
request_address_type = options.get(const.REQUEST_ADDRESS_TYPE)
if request_address_type == const.NETWORK_GATEWAY_OPTIONS:
is_gateway = True
if subnets:
subnet = subnets[0]
if is_gateway:
if subnets_by_cidr:
if len(subnets_by_cidr) > 1:
for tmp_subnet in subnets_by_cidr:
if tmp_subnet.get('subnetpool_id', '') == pool_id:
subnet = tmp_subnet
if not any(subnet) and not is_gateway:
raise exceptions.KuryrException(
("Subnet with cidr({0}) and pool {1}, does not "
"exist.").format(cidr, pool_id))
else:
subnet = subnets_by_cidr[0]
if is_gateway:
if any(subnet):
# check if request gateway ip same with existed gateway ip
existed_gateway_ip = subnet.get('gateway_ip', '')
if req_address == existed_gateway_ip:
allocated_address = '/'.join([req_address, pool_prefix_len])
allocated_address = '/'.join(
[req_address, pool_prefix_len])
else:
raise exceptions.GatewayConflictFailure(
"Requested gateway {0} does not match with "
"gateway {1} in existed "
"network.".format(req_address, existed_gateway_ip))
else:
# allocating address for container port
neutron_network_id = subnet['network_id']
try:
port = {
'name': 'kuryr-unbound-port',
'admin_state_up': True,
'network_id': neutron_network_id,
'binding:host_id': utils.get_hostname(),
}
fixed_ips = port['fixed_ips'] = []
fixed_ip = {'subnet_id': subnet['id']}
if req_address:
fixed_ip['ip_address'] = req_address
fixed_ips.append(fixed_ip)
created_port_resp = app.neutron.create_port({'port': port})
created_port = created_port_resp['port']
allocated_address = created_port['fixed_ips'][0]['ip_address']
allocated_address = '/'.join(
[allocated_address, str(cidr.prefixlen)])
except n_exceptions.NeutronClientException as ex:
app.logger.error(_LE("Error happened during ip allocation on "
"Neutron side: %s"), ex)
raise
else:
# Auxiliary address or gw_address is received at network creation time.
# This address cannot be reserved with neutron at this time as subnet
# is not created yet. In /NetworkDriver.CreateNetwork this address will
# be reserved with neutron.
if req_address:
allocated_address = '/'.join([req_address, pool_prefix_len])
else:
# allocating address for container port
neutron_network_id = subnet['network_id']
try:
port = {
'name': 'kuryr-unbound-port',
'admin_state_up': True,
'network_id': neutron_network_id,
'binding:host_id': utils.get_hostname(),
}
fixed_ips = port['fixed_ips'] = []
fixed_ip = {'subnet_id': subnet['id']}
if req_address:
fixed_ip['ip_address'] = req_address
fixed_ips.append(fixed_ip)
created_port_resp = app.neutron.create_port({'port': port})
created_port = created_port_resp['port']
app.logger.debug("created port %s", created_port)
allocated_address = created_port['fixed_ips'][0]['ip_address']
allocated_address = '/'.join(
[allocated_address, str(cidr.prefixlen)])
except n_exceptions.NeutronClientException as ex:
app.logger.error(_LE("Error happened during ip allocation on "
"Neutron side: %s"), ex)
raise
return flask.jsonify({'Address': allocated_address})
@ -1277,7 +1322,18 @@ def ipam_release_address():
if not len(subnets):
app.logger.info(_LI("Subnet already deleted."))
return flask.jsonify(const.SCHEMA['SUCCESS'])
subnet = subnets[0]
if len(subnets) > 1:
subnet = {}
for tmp_subnet in subnets:
if tmp_subnet['subnetpool_id'] == pool_id:
subnet = tmp_subnet
if not subnet:
raise exceptions.KuryrException(
("Subnet with cidr({0}) and pool {1}, does not "
"exist.").format(cidr, pool_id))
else:
subnet = subnets[0]
cidr_address = netaddr.IPNetwork(rel_address)
rcvd_fixed_ips = []
fixed_ip = {'subnet_id': subnet['id']}

View File

@ -140,8 +140,8 @@ class TestKuryrBase(TestCase):
# The following fake response is retrieved from the Neutron doc:
# http://developer.openstack.org/api-ref-networking-v2.html#createSubnet # noqa
fake_subnet_response = {
"subnets": [{
"name": '-'.join([docker_endpoint_id, '192.168.1.0']),
"subnets": [
{"name": '-'.join([docker_endpoint_id, '192.168.1.0']),
"network_id": neutron_network_id,
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
"allocation_pools": [{"start": "192.168.1.2",
@ -150,9 +150,9 @@ class TestKuryrBase(TestCase):
"ip_version": 4,
"cidr": "192.168.1.0/24",
"id": fake_neutron_subnet_v4_id,
"enable_dhcp": True
}, {
"name": '-'.join([docker_endpoint_id, 'fe80::']),
"enable_dhcp": True,
"subnetpool_id": ''},
{"name": '-'.join([docker_endpoint_id, 'fe80::']),
"network_id": neutron_network_id,
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
"allocation_pools": [{"start": "fe80::f816:3eff:fe20:57c4",
@ -161,8 +161,9 @@ class TestKuryrBase(TestCase):
"ip_version": 6,
"cidr": "fe80::/64",
"id": fake_neutron_subnet_v6_id,
"enable_dhcp": True
}]
"enable_dhcp": True,
"subnetpool_id": ''}
]
}
return fake_subnet_response
@ -243,7 +244,8 @@ class TestKuryrBase(TestCase):
"ip_version": 4,
"cidr": '192.168.1.0/24',
"id": subnet_v4_id,
"enable_dhcp": True
"enable_dhcp": True,
"subnetpool_id": ''
}
}
if subnetpool_id:

View File

@ -144,6 +144,286 @@ class TestKuryr(base.TestKuryrBase):
decoded_json = jsonutils.loads(response.data)
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
def test_network_driver_create_network_with_net_name_option(self):
docker_network_id = utils.get_hash()
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
self.mox.StubOutWithMock(app.neutron, "list_networks")
fake_neutron_net_name = 'my_network_name'
fake_existing_networks_response = {
"networks": [{
"status": "ACTIVE",
"subnets": [],
"admin_state_up": True,
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
"router:external": False,
"segments": [],
"shared": False,
"id": fake_neutron_net_id,
"name": "my_network_name"
}]
}
app.neutron.list_networks(
name=fake_neutron_net_name).AndReturn(
fake_existing_networks_response)
self.mox.StubOutWithMock(app.neutron, "add_tag")
tags = utils.create_net_tags(docker_network_id)
for tag in tags:
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
app.neutron.add_tag(
'networks', fake_neutron_net_id, 'kuryr.net.existing')
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
fake_existing_subnets_response = {
"subnets": []
}
fake_cidr_v4 = '192.168.42.0/24'
app.neutron.list_subnets(
network_id=fake_neutron_net_id,
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
fake_subnet_request = {
"subnets": [{
'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',
}]
}
subnet_v4_id = str(uuid.uuid4())
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']
]
}
app.neutron.create_subnet(
fake_subnet_request).AndReturn(fake_subnet_response)
self.mox.ReplayAll()
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.net.name': 'my_network_name'
}
}
}
response = self.app.post('/NetworkDriver.CreateNetwork',
content_type='application/json',
data=jsonutils.dumps(network_request))
self.assertEqual(200, response.status_code)
decoded_json = jsonutils.loads(response.data)
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
def test_network_driver_create_network_with_netid_option(self):
docker_network_id = utils.get_hash()
fake_neutron_net_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
self.mox.StubOutWithMock(app.neutron, "list_networks")
fake_existing_networks_response = {
"networks": [{
"status": "ACTIVE",
"subnets": [],
"admin_state_up": True,
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
"router:external": False,
"segments": [],
"shared": False,
"id": fake_neutron_net_id,
}]
}
app.neutron.list_networks(
id=fake_neutron_net_id).AndReturn(
fake_existing_networks_response)
self.mox.StubOutWithMock(app.neutron, "add_tag")
tags = utils.create_net_tags(docker_network_id)
for tag in tags:
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
app.neutron.add_tag(
'networks', fake_neutron_net_id, 'kuryr.net.existing')
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
fake_existing_subnets_response = {
"subnets": []
}
fake_cidr_v4 = '192.168.42.0/24'
app.neutron.list_subnets(
network_id=fake_neutron_net_id,
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
fake_subnet_request = {
"subnets": [{
'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',
}]
}
subnet_v4_id = str(uuid.uuid4())
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']
]
}
app.neutron.create_subnet(
fake_subnet_request).AndReturn(fake_subnet_response)
self.mox.ReplayAll()
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.net.uuid': '4e8e5957-649f-477b-9e5b-f1f75b21c03c'
}
}
}
response = self.app.post('/NetworkDriver.CreateNetwork',
content_type='application/json',
data=jsonutils.dumps(network_request))
self.assertEqual(200, response.status_code)
decoded_json = jsonutils.loads(response.data)
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
def test_network_driver_create_network_with_pool_name_option(self):
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
fake_kuryr_subnetpool_id = str(uuid.uuid4())
fake_name = "fake_pool_name"
kuryr_subnetpools = self._get_fake_v4_subnetpools(
fake_kuryr_subnetpool_id, name=fake_name)
app.neutron.list_subnetpools(name=fake_name).AndReturn(
{'subnetpools': kuryr_subnetpools['subnetpools']})
docker_network_id = utils.get_hash()
self.mox.StubOutWithMock(app.neutron, "create_network")
fake_request = {
"network": {
"name": utils.make_net_name(docker_network_id),
"admin_state_up": True
}
}
# 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"
fake_response = {
"network": {
"status": "ACTIVE",
"subnets": [],
"name": utils.make_net_name(docker_network_id),
"admin_state_up": True,
"tenant_id": "9bacb3c5d39d41a79512987f338cf177",
"router:external": False,
"segments": [],
"shared": False,
"id": fake_neutron_net_id
}
}
app.neutron.create_network(fake_request).AndReturn(fake_response)
self.mox.StubOutWithMock(app.neutron, "add_tag")
tags = utils.create_net_tags(docker_network_id)
for tag in tags:
app.neutron.add_tag('networks', fake_neutron_net_id, tag)
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
fake_existing_subnets_response = {
"subnets": []
}
fake_cidr_v4 = '192.168.42.0/24'
app.neutron.list_subnets(
network_id=fake_neutron_net_id,
cidr=fake_cidr_v4).AndReturn(fake_existing_subnets_response)
self.mox.StubOutWithMock(app.neutron, 'create_subnet')
fake_subnet_request = {
"subnets": [{
'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 = str(uuid.uuid4())
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']
]
}
app.neutron.create_subnet(
fake_subnet_request).AndReturn(fake_subnet_response)
self.mox.ReplayAll()
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.name': 'fake_pool_name'
}
}
}
response = self.app.post('/NetworkDriver.CreateNetwork',
content_type='application/json',
data=jsonutils.dumps(network_request))
self.assertEqual(200, response.status_code)
decoded_json = jsonutils.loads(response.data)
self.assertEqual(constants.SCHEMA['SUCCESS'], decoded_json)
def test_network_driver_create_network_wo_gw(self):
docker_network_id = utils.get_hash()
self.mox.StubOutWithMock(app.neutron, "create_network")

View File

@ -39,13 +39,15 @@ class TestKuryrEndpointFailures(base.TestKuryrFailures):
'network_id': neutron_network_id,
'ip_version': 4,
"cidr": '192.168.1.0/24',
'enable_dhcp': 'False'
'enable_dhcp': 'False',
'subnetpool_id': ''
}, {
'name': '-'.join([docker_endpoint_id, 'fe80::']),
'network_id': neutron_network_id,
'ip_version': 6,
"cidr": 'fe80::/64',
'enable_dhcp': 'False'
'enable_dhcp': 'False',
'subnetpool_id': ''
}]
}
fake_subnets = self._get_fake_subnets(

View File

@ -94,23 +94,33 @@ class TestKuryrIpam(base.TestKuryrBase):
decoded_json = jsonutils.loads(response.data)
self.assertEqual(fake_kuryr_subnetpool_id, decoded_json['PoolID'])
def test_ipam_driver_request_pool_with_default_v4pool(self):
def test_ipam_driver_request_pool_with_pool_name_option(self):
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
fake_kuryr_subnetpool_id = str(uuid.uuid4())
fake_name = 'kuryr'
fake_name = 'fake_pool_name'
new_subnetpool = {
'name': fake_name,
'default_prefixlen': 16,
'prefixes': [FAKE_IP4_CIDR]}
kuryr_subnetpools = self._get_fake_v4_subnetpools(
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
name=fake_name)
app.neutron.list_subnetpools(name=fake_name).AndReturn(
{'subnetpools': kuryr_subnetpools['subnetpools']})
fake_subnetpool_response = {
'subnetpool': kuryr_subnetpools['subnetpools'][0]
}
self.mox.StubOutWithMock(app.neutron, 'create_subnetpool')
app.neutron.create_subnetpool(
{'subnetpool': new_subnetpool}).AndReturn(fake_subnetpool_response)
self.mox.ReplayAll()
fake_request = {
'AddressSpace': '',
'Pool': '',
'Pool': FAKE_IP4_CIDR,
'SubPool': '', # In the case --ip-range is not given
'Options': {},
'Options': {'neutron.pool.name': 'fake_pool_name'},
'V6': False
}
response = self.app.post('/IpamDriver.RequestPool',
@ -228,6 +238,84 @@ class TestKuryrIpam(base.TestKuryrBase):
decoded_json = jsonutils.loads(response.data)
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
def test_ipam_driver_request_address_overlapping_cidr(self):
# faking list_subnetpools
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
fake_kuryr_subnetpool_id = str(uuid.uuid4())
fake_kuryr_subnetpool_id2 = str(uuid.uuid4())
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
kuryr_subnetpools = self._get_fake_v4_subnetpools(
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
name=fake_name)
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
kuryr_subnetpools)
# faking list_subnets
docker_endpoint_id = utils.get_hash()
neutron_network_id = str(uuid.uuid4())
neutron_network_id2 = str(uuid.uuid4())
neutron_subnet_v4_id = str(uuid.uuid4())
neutron_subnet_v4_id2 = str(uuid.uuid4())
fake_v4_subnet = self._get_fake_v4_subnet(
neutron_network_id, docker_endpoint_id, neutron_subnet_v4_id,
subnetpool_id=fake_kuryr_subnetpool_id,
cidr=FAKE_IP4_CIDR)
fake_v4_subnet2 = self._get_fake_v4_subnet(
neutron_network_id2, docker_endpoint_id, neutron_subnet_v4_id2,
subnetpool_id=fake_kuryr_subnetpool_id2,
cidr=FAKE_IP4_CIDR)
fake_subnet_response = {
'subnets': [
fake_v4_subnet2['subnet'],
fake_v4_subnet['subnet']
]
}
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
fake_subnet_response)
# faking create_port
fake_neutron_port_id = str(uuid.uuid4())
fake_port = base.TestKuryrBase._get_fake_port(
docker_endpoint_id, neutron_network_id,
fake_neutron_port_id,
neutron_subnet_v4_id=neutron_subnet_v4_id,
neutron_subnet_v4_address="10.0.0.5")
port_request = {
'name': 'kuryr-unbound-port',
'admin_state_up': True,
'network_id': neutron_network_id,
'binding:host_id': utils.get_hostname(),
}
port_request['fixed_ips'] = []
fixed_ip = {'subnet_id': neutron_subnet_v4_id}
port_request['fixed_ips'].append(fixed_ip)
self.mox.StubOutWithMock(app.neutron, 'create_port')
app.neutron.create_port({'port': port_request}).AndReturn(fake_port)
# Apply mocks
self.mox.ReplayAll()
# Testing container ip allocation
fake_request = {
'PoolID': fake_kuryr_subnetpool_id,
'Address': '', # Querying for container address
'Options': {}
}
response = self.app.post('/IpamDriver.RequestAddress',
content_type='application/json',
data=jsonutils.dumps(fake_request))
self.assertEqual(200, response.status_code)
decoded_json = jsonutils.loads(response.data)
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
def test_ipam_driver_request_address_for_same_gateway(self):
# faking list_subnetpools
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')