RequestAddress when subnet has not been created

gw_address is received in IpamDriver.RequestAddress when create network.
In Docker 1.12+, it will have NETWORK_GATEWAY_OPTIONS, but in lower
docker version, such as 1.9.1, it will not carry this option.
This change check if subnet exist first, this makes it can work for both
docker version.

Change-Id: I1c741172e927179f83284e8a23afce5f07b130f9
Closes-bug: #1611261
This commit is contained in:
Liping Mao 2016-08-09 16:15:14 +08:00
parent 4a820b0b98
commit 3e4e6a612f
2 changed files with 93 additions and 52 deletions

View File

@ -1318,8 +1318,8 @@ def ipam_request_address():
else:
subnet = subnets_by_cidr[0]
if is_gateway:
if any(subnet):
if any(subnet):
if is_gateway:
# check if request gateway ip same with existed gateway ip
existed_gateway_ip = subnet.get('gateway_ip', '')
if req_address == existed_gateway_ip:
@ -1331,59 +1331,65 @@ def ipam_request_address():
"gateway {1} in existed "
"network.".format(req_address, existed_gateway_ip))
else:
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']}
num_ports = 0
if req_address:
fixed_ip['ip_address'] = req_address
fixed_ip_existing = [('subnet_id=%s' % subnet['id'])]
fixed_ip_existing.append('ip_address=%s' % str(req_address))
filtered_ports = app.neutron.list_ports(
fixed_ips=fixed_ip_existing)
num_ports = len(filtered_ports.get('ports', []))
fixed_ips.append(fixed_ip)
# 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']}
num_ports = 0
if req_address:
fixed_ip['ip_address'] = req_address
fixed_ip_existing = [('subnet_id=%s' % subnet['id'])]
fixed_ip_existing.append('ip_address='
'%s' % str(req_address))
filtered_ports = app.neutron.list_ports(
fixed_ips=fixed_ip_existing)
num_ports = len(filtered_ports.get('ports', []))
fixed_ips.append(fixed_ip)
if num_ports:
existing_port = filtered_ports['ports'][0]
created_port_resp = {'port': existing_port}
host = existing_port.get('binding:host_id')
vif_type = existing_port.get('binding:vif_type')
if not host and vif_type == 'unbound':
updated_port = {
'admin_state_up': True,
'binding:host_id': utils.get_hostname(),
}
created_port_resp = app.neutron.update_port(
existing_port['id'],
{'port': updated_port})
if num_ports:
existing_port = filtered_ports['ports'][0]
created_port_resp = {'port': existing_port}
host = existing_port.get('binding:host_id')
vif_type = existing_port.get('binding:vif_type')
if not host and vif_type == 'unbound':
updated_port = {
'admin_state_up': True,
'binding:host_id': utils.get_hostname(),
}
created_port_resp = app.neutron.update_port(
existing_port['id'],
{'port': updated_port})
else:
raise exceptions.AddressInUseException(
"Requested ip address {0} already belongs to a "
"bound Neutron port: {1}".format(fixed_ip,
existing_port['id']))
else:
raise exceptions.AddressInUseException(
"Requested ip address {0} already belongs to a bound "
"Neutron port: {1}".format(fixed_ip,
existing_port['id']))
else:
created_port_resp = app.neutron.create_port({'port': port})
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
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
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])
return flask.jsonify({'Address': allocated_address})

View File

@ -238,6 +238,41 @@ 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_when_subnet_not_exist(self):
requested_address = '10.0.0.5'
# faking list_subnetpools
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
fake_kuryr_subnetpool_id = 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
fake_subnet_response = {'subnets': []}
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
fake_subnet_response)
# Apply mocks
self.mox.ReplayAll()
# Testing container ip allocation
fake_request = {
'PoolID': fake_kuryr_subnetpool_id,
'Address': requested_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(requested_address + '/16', decoded_json['Address'])
@ddt.data((False), (True))
def test_ipam_driver_request_specific_address(self, existing_port):
requested_address = '10.0.0.5'