Refactor kuryr libnetwork code

Change-Id: Ia81975d15cab318dc6688a6ebd51dd6877ba0aaf
Implement: blueprint migrate-docker-to-cni
This commit is contained in:
Hongbin Lu 2020-08-02 03:48:02 +00:00
parent cded431e7d
commit 05d55ec9bd
6 changed files with 80 additions and 138 deletions

View File

@ -284,9 +284,14 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
kwargs['volumes'] = [b['bind'] for b in binds.values()]
self._process_exposed_ports(network_driver.neutron_api, container,
kwargs)
self._process_networking_config(
context, container, requested_networks, host_config,
kwargs, docker)
# Process the first requested network at create time. The rest
# will be processed after create.
requested_network = requested_networks.pop()
security_group_ids = utils.get_security_group_ids(
context, container.security_groups)
network_driver.process_networking_config(
container, requested_network, host_config, kwargs, docker,
security_group_ids=security_group_ids)
if container.auto_remove:
host_config['auto_remove'] = container.auto_remove
if self._should_limit_memory(container):
@ -377,48 +382,10 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
ports.append((port, proto))
kwargs['ports'] = ports
def _process_networking_config(self, context, container,
requested_networks, host_config,
container_kwargs, docker):
network_driver = zun_network.driver(context=context, docker_api=docker)
neutron_api = network_driver.neutron_api
# Process the first requested network at create time. The rest
# will be processed after create.
requested_network = requested_networks.pop()
docker_net_name = self._get_docker_network_name(
context, requested_network['network'])
security_group_ids = utils.get_security_group_ids(
context, container.security_groups)
docker_network = network_driver.inspect_network(docker_net_name)
device_owner = network_driver.get_device_owner()
neutron_net_id = docker_network['Options']['neutron.net.uuid']
addresses, port = neutron_api.create_or_update_port(
container, neutron_net_id, requested_network, device_owner,
security_group_ids, set_binding_host=True)
container.addresses = {requested_network['network']: addresses}
ipv4_address = None
ipv6_address = None
for address in addresses:
if address['version'] == 4:
ipv4_address = address['addr']
if address['version'] == 6:
ipv6_address = address['addr']
endpoint_config = docker.create_endpoint_config(
ipv4_address=ipv4_address, ipv6_address=ipv6_address)
network_config = docker.create_networking_config({
docker_net_name: endpoint_config})
host_config['network_mode'] = docker_net_name
container_kwargs['networking_config'] = network_config
container_kwargs['mac_address'] = port['mac_address']
def _provision_network(self, context, network_driver, requested_networks):
for rq_network in requested_networks:
self._get_or_create_docker_network(
context, network_driver, rq_network['network'])
network_driver.get_or_create_network(context,
rq_network['network'])
def _get_secgorup_name(self, container_uuid):
return consts.NAME_PREFIX + container_uuid
@ -443,11 +410,8 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
# This network is already setup so skip it
continue
docker_net_name = self._get_docker_network_name(
context, network['network'])
addrs = network_driver.connect_container_to_network(
container, docker_net_name, network,
security_groups=security_group_ids)
container, network, security_groups=security_group_ids)
addresses[network['network']] = addrs
return addresses
@ -475,9 +439,8 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
if not container.addresses:
return
for neutron_net in container.addresses:
docker_net = neutron_net
network_driver.disconnect_container_from_network(
container, docker_net, neutron_network_id=neutron_net)
container, neutron_network_id=neutron_net)
def _cleanup_exposed_ports(self, neutron_api, container):
exposed_ports = {}
@ -1031,21 +994,6 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
def _encode_utf8(self, value):
return value.encode('utf-8')
def _get_or_create_docker_network(self, context, network_driver,
neutron_net_id):
docker_net_name = self._get_docker_network_name(context,
neutron_net_id)
docker_networks = network_driver.list_networks(names=[docker_net_name])
if not docker_networks:
network_driver.create_network(neutron_net_id=neutron_net_id,
name=docker_net_name)
def _get_docker_network_name(self, context, neutron_net_id):
# Note(kiseok7): neutron_net_id is a unique ID in neutron networks and
# docker networks.
# so it will not be duplicated across projects.
return neutron_net_id
def get_container_name(self, container):
return consts.NAME_PREFIX + container.uuid
@ -1146,9 +1094,8 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
with docker_utils.docker_client() as docker:
network_driver = zun_network.driver(context,
docker_api=docker)
docker_net = self._get_docker_network_name(context, network)
network_driver.disconnect_container_from_network(
container, docker_net, network)
network_driver.disconnect_container_from_network(container,
network)
# Only clear network info related to this network
# Cannot del container.address directly which will not update
@ -1165,8 +1112,7 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
if container.security_groups:
security_group_ids = utils.get_security_group_ids(
context, container.security_groups)
network_driver = zun_network.driver(context,
docker_api=docker)
network_driver = zun_network.driver(context, docker_api=docker)
network = requested_network['network']
if network in container.addresses:
raise exception.ZunException('Container %(container)s has '
@ -1174,11 +1120,9 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
'network %(network)s.'
% {'container': container.uuid,
'network': network})
self._get_or_create_docker_network(context, network_driver,
network)
docker_net_name = self._get_docker_network_name(context, network)
network_driver.get_or_create_network(context, network)
addrs = network_driver.connect_container_to_network(
container, docker_net_name, requested_network,
container, requested_network,
security_groups=security_group_ids)
if addrs is None:
raise exception.ZunException(_(
@ -1192,13 +1136,8 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
def create_network(self, context, neutron_net_id):
with docker_utils.docker_client() as docker:
network_driver = zun_network.driver(context,
docker_api=docker)
docker_net_name = self._get_docker_network_name(
context, neutron_net_id)
return network_driver.create_network(
neutron_net_id=neutron_net_id,
name=docker_net_name)
network_driver = zun_network.driver(context, docker_api=docker)
return network_driver.create_network(neutron_net_id)
def delete_network(self, context, network):
with docker_utils.docker_client() as docker:

View File

@ -447,9 +447,6 @@ class ContainerDriver(object):
def delete_network(self, context, network):
raise NotImplementedError()
def inspect_network(self, network):
raise NotImplementedError()
def pull_image(self, context, repo, tag, **kwargs):
raise NotImplementedError()

View File

@ -40,7 +40,13 @@ class KuryrNetwork(network.Network):
self.neutron_api = neutron.NeutronAPI(context)
self.context = context
def create_network(self, name, neutron_net_id):
def get_or_create_network(self, context, neutron_net_id):
docker_net_name = neutron_net_id
docker_networks = self.docker.networks(names=[docker_net_name])
if not docker_networks:
self.create_network(neutron_net_id)
def create_network(self, neutron_net_id):
"""Create a docker network with Kuryr driver.
The docker network to be created will be based on the specified
@ -53,6 +59,7 @@ class KuryrNetwork(network.Network):
neutron net, retrieving the cidr, gateway of each
subnet, and compile the list of parameters for docker.create_network.
"""
name = neutron_net_id
# find a v4 and/or v6 subnet of the network
shared = \
self.neutron_api.get_neutron_network(neutron_net_id)[
@ -136,7 +143,7 @@ class KuryrNetwork(network.Network):
"%(networks)s",
{"net_id": network.neutron_net_id,
"networks": networks})
docker_networks = self.list_networks(names=[network.name])
docker_networks = self.docker.networks(names=[network.name])
LOG.debug("docker networks with name matching '%(name)s': "
"%(networks)s",
{"name": network.name,
@ -187,26 +194,44 @@ class KuryrNetwork(network.Network):
self.docker.remove_network(network.name)
network.destroy()
def inspect_network(self, network_name):
return self.docker.inspect_network(network_name)
def process_networking_config(self, container, requested_network,
host_config, container_kwargs, docker,
security_group_ids):
docker_net_name = requested_network['network']
neutron_net_id = requested_network['network']
addresses, port = self.neutron_api.create_or_update_port(
container, neutron_net_id, requested_network, DEVICE_OWNER,
security_group_ids, set_binding_host=True)
container.addresses = {requested_network['network']: addresses}
def list_networks(self, **kwargs):
return self.docker.networks(**kwargs)
ipv4_address = None
ipv6_address = None
for address in addresses:
if address['version'] == 4:
ipv4_address = address['addr']
if address['version'] == 6:
ipv6_address = address['addr']
def get_device_owner(self):
return DEVICE_OWNER
endpoint_config = docker.create_endpoint_config(
ipv4_address=ipv4_address, ipv6_address=ipv6_address)
network_config = docker.create_networking_config({
docker_net_name: endpoint_config})
def connect_container_to_network(self, container, network_name,
requested_network, security_groups=None):
host_config['network_mode'] = docker_net_name
container_kwargs['networking_config'] = network_config
container_kwargs['mac_address'] = port['mac_address']
def connect_container_to_network(self, container, requested_network,
security_groups=None):
"""Connect container to the network
This method will create a neutron port, retrieve the ip address(es)
of the port, and pass them to docker.connect_container_to_network.
"""
network_name = requested_network['network']
container_id = container.container_id
network = self.inspect_network(network_name)
neutron_net_id = network['Options']['neutron.net.uuid']
neutron_net_id = requested_network['network']
addresses, original_port = self.neutron_api.create_or_update_port(
container, neutron_net_id, requested_network, DEVICE_OWNER,
security_groups)
@ -259,8 +284,8 @@ class KuryrNetwork(network.Network):
LOG.debug('Unable to delete port %s as it no longer '
'exists.', port_id)
def disconnect_container_from_network(self, container, network_name,
neutron_network_id=None):
def disconnect_container_from_network(self, container, neutron_network_id):
network_name = neutron_network_id
container_id = container.container_id
addrs_list = []

View File

@ -37,16 +37,16 @@ class Network(object, metaclass=abc.ABCMeta):
def init(self, context, *args, **kwargs):
raise NotImplementedError()
def get_or_create_network(self, *args, **kwargs):
raise NotImplementedError()
def create_network(self, *args, **kwargs):
raise NotImplementedError()
def remove_network(self, network_name, **kwargs):
raise NotImplementedError()
def inspect_network(self, network_name, **kwargs):
raise NotImplementedError()
def list_networks(self, **kwargs):
def process_networking_config(self, *args, **kwargs):
raise NotImplementedError()
def connect_container_to_network(self, container, network_name, **kwargs):

View File

@ -821,21 +821,19 @@ class TestDockerDriver(base.DriverTestCase):
def test_network_detach(self, mock_detach):
mock_container = mock.MagicMock()
self.driver.network_detach(self.context, mock_container, 'network')
mock_detach.assert_called_once_with(mock_container,
'network',
mock.ANY)
mock_detach.assert_called_once_with(mock_container, 'network')
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
'.connect_container_to_network')
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
'.disconnect_container_from_network')
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
'.list_networks')
def test_network_attach(self, mock_list, mock_disconnect, mock_connect):
'.get_or_create_network')
def test_network_attach(self, mock_get_or_create, mock_disconnect,
mock_connect):
mock_container = mock.Mock()
mock_container.security_groups = None
mock_container.addresses = {}
mock_list.return_value = {'network': 'network'}
requested_network = {'network': 'network',
'port': '',
'fixed_ip': '',
@ -843,7 +841,6 @@ class TestDockerDriver(base.DriverTestCase):
self.driver.network_attach(self.context, mock_container,
requested_network)
mock_connect.assert_called_once_with(mock_container,
'network',
requested_network,
security_groups=None)
@ -863,15 +860,14 @@ class TestDockerDriver(base.DriverTestCase):
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
'.connect_container_to_network')
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
'.list_networks')
def test_network_attach_with_security_group(self, mock_list,
'.get_or_create_network')
def test_network_attach_with_security_group(self, mock_get_or_create,
mock_connect,
mock_get_sec_group_id):
test_sec_group_id = '84e3a4c1-c8cd-46b1-a0d9-c8c35f6a32a4'
mock_container = mock.Mock()
mock_container.security_groups = ['test_sec_group']
mock_container.addresses = {}
mock_list.return_value = {'network': 'network'}
mock_get_sec_group_id.return_value = test_sec_group_id
requested_network = {'network': 'network',
'port': '',
@ -880,7 +876,6 @@ class TestDockerDriver(base.DriverTestCase):
self.driver.network_attach(self.context, mock_container,
requested_network)
mock_connect.assert_called_once_with(mock_container,
'network',
requested_network,
security_groups=test_sec_group_id)

View File

@ -191,15 +191,14 @@ class KuryrNetworkTestCase(base.TestCase):
self, mock_neutron_api_cls, mock_save, mock_create):
self.network_driver.neutron_api.subnets[0].pop('subnetpool_id')
mock_neutron_api_cls.return_value = self.network_driver.neutron_api
name = 'test_kuryr_network'
neutron_net_id = 'fake-net-id'
with mock.patch.object(self.network_driver.docker, 'create_network',
return_value={'Id': 'docker-net'}
) as mock_create_network:
network = self.network_driver.create_network(name, neutron_net_id)
network = self.network_driver.create_network(neutron_net_id)
self.assertEqual('docker-net', network.network_id)
mock_create_network.assert_called_once_with(
name=name,
name=neutron_net_id,
driver='kuryr',
enable_ipv6=False,
ipam={'Config': [{'Subnet': '10.5.0.0/16', 'Gateway': '10.5.0.1'}],
@ -216,15 +215,14 @@ class KuryrNetworkTestCase(base.TestCase):
def test_create_network_with_subnetpool(
self, mock_neutron_api_cls, mock_save, mock_create):
mock_neutron_api_cls.return_value = self.network_driver.neutron_api
name = 'test_kuryr_network'
neutron_net_id = 'fake-net-id'
with mock.patch.object(self.network_driver.docker, 'create_network',
return_value={'Id': 'docker-net'}
) as mock_create_network:
network = self.network_driver.create_network(name, neutron_net_id)
network = self.network_driver.create_network(neutron_net_id)
self.assertEqual('docker-net', network.network_id)
mock_create_network.assert_called_once_with(
name=name,
name=neutron_net_id,
driver='kuryr',
enable_ipv6=False,
ipam={'Config': [{'Subnet': '10.5.0.0/16', 'Gateway': '10.5.0.1'}],
@ -242,7 +240,6 @@ class KuryrNetworkTestCase(base.TestCase):
def test_create_network_already_exist(
self, mock_neutron_api_cls, mock_list, mock_save, mock_create):
mock_neutron_api_cls.return_value = self.network_driver.neutron_api
name = 'test_kuryr_network'
neutron_net_id = 'fake-net-id'
docker_net_id = 'docker-net'
fake_network = mock.Mock()
@ -253,34 +250,23 @@ class KuryrNetworkTestCase(base.TestCase):
with mock.patch.object(self.network_driver.docker, 'networks',
return_value=[{'Id': docker_net_id}]
) as mock_list_network:
network = self.network_driver.create_network(name, neutron_net_id)
network = self.network_driver.create_network(neutron_net_id)
self.assertEqual(docker_net_id, network.network_id)
mock_list.assert_called_once_with(
self.context, filters={'neutron_net_id': neutron_net_id})
mock_list_network.assert_called_once_with(names=[name])
mock_list_network.assert_called_once_with(names=[neutron_net_id])
def test_remove_network(self):
network = mock.Mock(name='c02afe4e-8350-4263-8078')
self.network_driver.remove_network(network)
network.destroy.assert_called_once_with()
def test_inspect_network(self):
network_name = 'c02afe4e-8350-4263-8078'
expected = {'Name': 'c02afe4e-8350-4263-8078',
'Options': {'neutron.net.uuid': '1234567'}}
info = self.network_driver.inspect_network(network_name)
self.assertEqual(expected, info)
def test_list_networks(self):
expected = [{'Name': 'test_network'}]
networks = self.network_driver.list_networks()
self.assertEqual(expected, networks)
def test_connect_container_to_network(self):
container = Container(self.context, **utils.get_test_container())
network_name = 'c02afe4e-8350-4263-8078'
requested_net = {'ipv4_address': '10.5.0.22',
'port': 'fake-port-id',
'network': network_name,
'preserve_on_delete': True}
expected_address = [{'version': 4, 'addr': '10.5.0.22',
'port': 'fake-port-id',
@ -292,7 +278,7 @@ class KuryrNetworkTestCase(base.TestCase):
with mock.patch.object(self.network_driver.docker,
'connect_container_to_network') as mock_connect:
address = self.network_driver.connect_container_to_network(
container, network_name, requested_net)
container, requested_net)
self.assertEqual(expected_address, address)
mock_connect.assert_called_once_with(
@ -306,6 +292,7 @@ class KuryrNetworkTestCase(base.TestCase):
container = Container(self.context, **utils.get_test_container())
network_name = 'c02afe4e-8350-4263-8078'
requested_net = {'ipv4_address': '10.5.0.22',
'network': network_name,
'port': 'fake-port-id',
'preserve_on_delete': True}
mock_neutron_api_cls.return_value = self.network_driver.neutron_api
@ -317,7 +304,7 @@ class KuryrNetworkTestCase(base.TestCase):
mock.Mock(side_effect=exception.DockerError)
self.assertRaises(exception.DockerError,
self.network_driver.connect_container_to_network,
container, network_name, requested_net)
container, requested_net)
new_port = self.network_driver.neutron_api.list_ports(
id='fake-port-id')['ports'][0]
self.assertEqual('', new_port['device_id'])
@ -327,7 +314,6 @@ class KuryrNetworkTestCase(base.TestCase):
'preserve_on_delete': False}]}
container = Container(self.context, **utils.get_test_container(
addresses=addresses))
network_name = 'c02afe4e-8350-4263-8078'
ports = self.network_driver.neutron_api.list_ports(
id='fake-port-id')['ports']
self.assertEqual(1, len(ports))
@ -335,9 +321,9 @@ class KuryrNetworkTestCase(base.TestCase):
'disconnect_container_from_network'
) as mock_disconnect:
self.network_driver.disconnect_container_from_network(
container, network_name, 'fake-net-id')
container, 'fake-net-id')
mock_disconnect.assert_called_once_with(
container.container_id, network_name)
container.container_id, 'fake-net-id')
# assert the neutron port is deleted
ports = self.network_driver.neutron_api.list_ports(
id='fake-port-id')['ports']