Optimize disconnection of container from network

The disconnection of container from network needs to delete all
the neutron ports of the container. In before, we searched
neutron ports by device_id/EndpointID. The problem is EndpointID
is not available if the container is not running. This commit
retrieves neutron ports from the 'addresses' field of the container
instead.

Partial-Implements: blueprint make-sandbox-optional
Change-Id: Ibe9383d735640d66cc9f24ce3caccd281a64b4e7
This commit is contained in:
Hongbin Lu
2017-06-25 21:37:05 +00:00
parent 81c225f987
commit 9ae81a2994
5 changed files with 29 additions and 28 deletions

View File

@@ -62,9 +62,9 @@ class Manager(object):
if created_container:
self._do_container_start(context, created_container)
def _do_sandbox_cleanup(self, context, sandbox_id):
def _do_sandbox_cleanup(self, context, container, sandbox_id):
try:
self.driver.delete_sandbox(context, sandbox_id)
self.driver.delete_sandbox(context, container, sandbox_id)
except Exception as e:
LOG.error("Error occurred while deleting sandbox: %s",
six.text_type(e))
@@ -118,21 +118,21 @@ class Manager(object):
except exception.ImageNotFound as e:
with excutils.save_and_reraise_exception(reraise=reraise):
LOG.error(six.text_type(e))
self._do_sandbox_cleanup(context, sandbox_id)
self._do_sandbox_cleanup(context, container, sandbox_id)
self._fail_container(context, container, six.text_type(e))
return
except exception.DockerError as e:
with excutils.save_and_reraise_exception(reraise=reraise):
LOG.error("Error occurred while calling Docker image API: %s",
six.text_type(e))
self._do_sandbox_cleanup(context, sandbox_id)
self._do_sandbox_cleanup(context, container, sandbox_id)
self._fail_container(context, container, six.text_type(e))
return
except Exception as e:
with excutils.save_and_reraise_exception(reraise=reraise):
LOG.exception("Unexpected exception: %s",
six.text_type(e))
self._do_sandbox_cleanup(context, sandbox_id)
self._do_sandbox_cleanup(context, container, sandbox_id)
self._fail_container(context, container, six.text_type(e))
return
@@ -153,7 +153,7 @@ class Manager(object):
with excutils.save_and_reraise_exception(reraise=reraise):
LOG.error("Error occurred while calling Docker create API: %s",
six.text_type(e))
self._do_sandbox_cleanup(context, sandbox_id)
self._do_sandbox_cleanup(context, container, sandbox_id)
self._fail_container(context, container, six.text_type(e),
unset_host=True)
return
@@ -161,7 +161,7 @@ class Manager(object):
with excutils.save_and_reraise_exception(reraise=reraise):
LOG.exception("Unexpected exception: %s",
six.text_type(e))
self._do_sandbox_cleanup(context, sandbox_id)
self._do_sandbox_cleanup(context, container, sandbox_id)
self._fail_container(context, container, six.text_type(e),
unset_host=True)
return
@@ -209,7 +209,7 @@ class Manager(object):
container.task_state = consts.SANDBOX_DELETING
container.save(context)
try:
self.driver.delete_sandbox(context, sandbox_id)
self.driver.delete_sandbox(context, container, sandbox_id)
except Exception as e:
with excutils.save_and_reraise_exception(reraise=reraise):
LOG.exception("Unexpected exception: %s",

View File

@@ -534,7 +534,8 @@ class DockerDriver(driver.ContainerDriver):
# Container connects to the bridge network by default so disconnect
# the container from it before connecting it to neutron network.
# This avoids potential conflict between these two networks.
network_api.disconnect_container_from_network(sandbox, 'bridge')
network_api.disconnect_container_from_network(
container, 'bridge', sandbox_id=sandbox['Id'])
addresses = {}
for network in networks:
addrs = network_api.connect_container_to_network(
@@ -587,12 +588,13 @@ class DockerDriver(driver.ContainerDriver):
return docker_networks[0]
def delete_sandbox(self, context, sandbox_id):
def delete_sandbox(self, context, container, sandbox_id):
with docker_utils.docker_client() as docker:
network_api = zun_network.api(context=context, docker_api=docker)
sandbox = docker.inspect_container(sandbox_id)
for network in sandbox["NetworkSettings"]["Networks"]:
network_api.disconnect_container_from_network(sandbox, network)
network_api.disconnect_container_from_network(
container, network, sandbox_id=sandbox['Id'])
try:
docker.remove_container(sandbox_id, force=True)
except errors.APIError as api_error:

View File

@@ -153,7 +153,7 @@ class ContainerDriver(object):
"""Create a sandbox."""
raise NotImplementedError()
def delete_sandbox(self, context, sandbox_id):
def delete_sandbox(self, context, container, sandbox_id):
"""Delete a sandbox."""
raise NotImplementedError()

View File

@@ -158,25 +158,23 @@ class KuryrNetwork(network.Network):
container['Id'], network_name, **kwargs)
return addresses
def disconnect_container_from_network(self, container, network_name):
container_id = container['Id']
neutron_ports = None
# TODO(hongbin): Use objects instead of an ad hoc dict.
if "NetworkSettings" in container:
network = container["NetworkSettings"]["Networks"][network_name]
endpoint_id = network["EndpointID"]
# Kuryr set the port's device_id as endpoint_id so we leverge it
neutron_ports = self.neutron.list_ports(device_id=endpoint_id)
neutron_ports = neutron_ports.get('ports', [])
if not neutron_ports:
LOG.warning("Cannot find the neutron port that bind container "
"%s to network %s", container_id, network_name)
def disconnect_container_from_network(self, container, network_name,
sandbox_id=None):
container_id = container.container_id
if sandbox_id:
container_id = sandbox_id
neutron_ports = set()
if container.addresses:
addrs_list = container.addresses.get(network_name, [])
for addr in addrs_list:
port_id = addr['port']
neutron_ports.add(port_id)
self.docker.disconnect_container_from_network(container_id,
network_name)
if neutron_ports:
for port_id in neutron_ports:
try:
port_id = neutron_ports[0]['id']
self.neutron.delete_port(port_id)
except exceptions.PortNotFoundClient:
LOG.warning('Maybe your libnetwork distribution do not have'

View File

@@ -348,7 +348,8 @@ class TestDockerDriver(base.DriverTestCase):
def test_delete_sandbox(self):
self.mock_docker.remove_container = mock.Mock()
self.driver.delete_sandbox(context=self.context,
mock_container = mock.MagicMock()
self.driver.delete_sandbox(self.context, mock_container,
sandbox_id='test_sandbox_id')
self.mock_docker.remove_container.assert_called_once_with(
'test_sandbox_id', force=True)