Adding support for existing Neutron ports
When a specific address is requested during the docker run such as the following command: docker run -it --net=kuryr_net --ip=10.0.0.5 ubuntu if a port in the corresponding subnet with the requested ip address already exists and it is unbound, that port is used for the container. Change-Id: Ia3db8c979dff279ac8ba5f6c13625e40b8cf0fd7
This commit is contained in:
parent
9c94d3ccc5
commit
fd904a6a65
kuryr_libnetwork
@ -1225,10 +1225,37 @@ def ipam_request_address():
|
||||
}
|
||||
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)
|
||||
created_port_resp = app.neutron.create_port({'port': 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:
|
||||
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']
|
||||
|
@ -238,6 +238,99 @@ class TestKuryrIpam(base.TestKuryrBase):
|
||||
decoded_json = jsonutils.loads(response.data)
|
||||
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
|
||||
|
||||
@ddt.data((False), (True))
|
||||
def test_ipam_driver_request_specific_address(self, existing_port):
|
||||
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
|
||||
docker_endpoint_id = utils.get_hash()
|
||||
neutron_network_id = str(uuid.uuid4())
|
||||
subnet_v4_id = str(uuid.uuid4())
|
||||
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']
|
||||
]
|
||||
}
|
||||
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
||||
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
||||
fake_subnet_response)
|
||||
self.mox.StubOutWithMock(app.neutron, 'list_ports')
|
||||
|
||||
# faking update_port or 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, const.PORT_STATUS_ACTIVE,
|
||||
subnet_v4_id,
|
||||
neutron_subnet_v4_address=requested_address)
|
||||
|
||||
fixed_ip_existing = [('subnet_id=%s' % subnet_v4_id)]
|
||||
if existing_port:
|
||||
fake_existing_port = fake_port['port']
|
||||
fake_existing_port['binding:host_id'] = ''
|
||||
fake_existing_port['binding:vif_type'] = 'unbound'
|
||||
fake_ports_response = {'ports': [fake_existing_port]}
|
||||
else:
|
||||
fake_ports_response = {'ports': []}
|
||||
|
||||
fixed_ip_existing.append('ip_address=%s' % requested_address)
|
||||
app.neutron.list_ports(fixed_ips=fixed_ip_existing).AndReturn(
|
||||
fake_ports_response)
|
||||
|
||||
if existing_port:
|
||||
update_port = {
|
||||
'admin_state_up': True,
|
||||
'binding:host_id': utils.get_hostname(),
|
||||
}
|
||||
self.mox.StubOutWithMock(app.neutron, 'update_port')
|
||||
app.neutron.update_port(fake_neutron_port_id,
|
||||
{'port': update_port}).AndReturn(
|
||||
fake_port)
|
||||
else:
|
||||
port_request = {
|
||||
'name': 'kuryr-unbound-port',
|
||||
'admin_state_up': True,
|
||||
'network_id': neutron_network_id,
|
||||
'binding:host_id': utils.get_hostname(),
|
||||
}
|
||||
fixed_ips = port_request['fixed_ips'] = []
|
||||
fixed_ip = {'subnet_id': subnet_v4_id,
|
||||
'ip_address': requested_address}
|
||||
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': 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'])
|
||||
|
||||
def test_ipam_driver_request_address_overlapping_cidr(self):
|
||||
# faking list_subnetpools
|
||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
||||
|
Loading…
x
Reference in New Issue
Block a user