From 5caaa8fb212dbb9a1b22732341d19c3d3e47b797 Mon Sep 17 00:00:00 2001 From: Kien Nguyen Date: Thu, 20 Jul 2017 10:22:05 +0700 Subject: [PATCH] Add delete_container to periodic task - The container with status DELETED is not removed automatically. This patch will add delete_container method to remove it in periodic task. - Increase the severity of log level to Info. - Support filter container with status, task_state. - Change param handlers to endpoints for consistent. Change-Id: I0c703fc2c69c9a582e7cb3b34e8aa08c098e37e4 Depends-On: Ic6d35274a49648bde5e0e7486453a6d1a13f6f2e Related-Bug: #1644901 Closes-Bug: #1701984 --- zun/common/rpc_service.py | 12 ++++++++++-- zun/compute/manager.py | 36 ++++++++++++++++++++++++++++++++++-- zun/db/sqlalchemy/api.py | 3 ++- zun/network/kuryr_network.py | 22 ++++++++++++---------- zun/service/periodic.py | 3 ++- 5 files changed, 60 insertions(+), 16 deletions(-) diff --git a/zun/common/rpc_service.py b/zun/common/rpc_service.py index c933112d8..3b6649943 100644 --- a/zun/common/rpc_service.py +++ b/zun/common/rpc_service.py @@ -19,6 +19,7 @@ from oslo_messaging.rpc import dispatcher from oslo_service import service from oslo_utils import importutils +from zun.common import context from zun.common import profiler from zun.common import rpc import zun.conf @@ -43,14 +44,15 @@ def _init_serializer(): class Service(service.Service): - def __init__(self, topic, server, handlers, binary): + def __init__(self, topic, server, endpoints, binary): super(Service, self).__init__() serializer = _init_serializer() transport = messaging.get_rpc_transport(CONF) access_policy = dispatcher.DefaultRPCAccessPolicy # TODO(asalkeld) add support for version='x.y' target = messaging.Target(topic=topic, server=server) - self._server = messaging.get_rpc_server(transport, target, handlers, + self.endpoints = endpoints + self._server = messaging.get_rpc_server(transport, target, endpoints, executor='eventlet', serializer=serializer, access_policy=access_policy) @@ -60,6 +62,12 @@ class Service(service.Service): def start(self): servicegroup.setup(CONF, self.binary, self.tg) periodic.setup(CONF, self.tg) + for endpoint in self.endpoints: + self.tg.add_dynamic_timer( + endpoint.run_periodic_tasks, + periodic_interval_max=CONF.periodic_interval_max, + context=context.get_admin_context(all_tenants=True) + ) self._server.start() def stop(self): diff --git a/zun/compute/manager.py b/zun/compute/manager.py index 9b1577181..45005a93e 100644 --- a/zun/compute/manager.py +++ b/zun/compute/manager.py @@ -15,6 +15,7 @@ import six from oslo_log import log as logging +from oslo_service import periodic_task from oslo_utils import excutils from oslo_utils import uuidutils @@ -27,16 +28,17 @@ import zun.conf from zun.container import driver from zun.image import driver as image_driver from zun.image.glance import driver as glance +from zun import objects CONF = zun.conf.CONF LOG = logging.getLogger(__name__) -class Manager(object): +class Manager(periodic_task.PeriodicTasks): """Manages the running containers.""" def __init__(self, container_driver=None): - super(Manager, self).__init__() + super(Manager, self).__init__(CONF) self.driver = driver.load_container_driver(container_driver) self.host = CONF.host self._resource_tracker = None @@ -643,3 +645,33 @@ class Manager(object): self.driver) self._resource_tracker = rt return self._resource_tracker + + @periodic_task.periodic_task(run_immediately=True) + def delete_unused_containers(self, context): + """Delete container with status DELETED""" + # NOTE(kiennt): Need to filter with both status (DELETED) and + # task_state (None). If task_state in + # [CONTAINER_DELETING, SANDBOX_DELETING] it may + # raise some errors when try to delete container. + filters = { + 'auto_remove': True, + 'status': consts.DELETED, + 'task_state': None, + } + containers = objects.Container.list(context, + filters=filters) + + if containers: + for container in containers: + try: + msg = ('%(behavior)s deleting container ' + '%(container_name)s with status DELETED') + LOG.info(msg, {'behavior': 'Start', + 'container_name': container.name}) + self.container_delete(context, container, True) + LOG.info(msg, {'behavior': 'Complete', + 'container_name': container.name}) + except exception.DockerError: + return + except Exception: + return diff --git a/zun/db/sqlalchemy/api.py b/zun/db/sqlalchemy/api.py index 8bcc2d0d3..4e965517a 100644 --- a/zun/db/sqlalchemy/api.py +++ b/zun/db/sqlalchemy/api.py @@ -132,7 +132,8 @@ class Connection(object): filters = {} filter_names = ['name', 'image', 'project_id', 'user_id', - 'memory', 'host'] + 'memory', 'host', 'task_state', 'status', + 'auto_remove'] for name in filter_names: if name in filters: query = query.filter_by(**{name: filters[name]}) diff --git a/zun/network/kuryr_network.py b/zun/network/kuryr_network.py index 447b53d9d..243e36ec1 100644 --- a/zun/network/kuryr_network.py +++ b/zun/network/kuryr_network.py @@ -178,16 +178,18 @@ class KuryrNetwork(network.Network): port_id = addr['port'] neutron_ports.add(port_id) - self.docker.disconnect_container_from_network(container_id, - network_name) - for port_id in neutron_ports: - try: - self.neutron.delete_port(port_id) - except exceptions.PortNotFoundClient: - LOG.warning('Maybe your libnetwork distribution do not have' - 'patch https://review.openstack.org/#/c/441024/' - 'or neutron tag extension does not supported or' - ' not enabled.') + try: + self.docker.disconnect_container_from_network(container_id, + network_name) + finally: + for port_id in neutron_ports: + try: + self.neutron.delete_port(port_id) + except exceptions.PortNotFoundClient: + LOG.warning('Maybe your libnetwork distribution do not ' + 'have patch https://review.openstack.org/#/c/' + '441024/ or neutron tag extension does not ' + 'supported or not enabled.') def add_security_groups_to_ports(self, container, security_group_ids): container_id = container.get_sandbox_id() diff --git a/zun/service/periodic.py b/zun/service/periodic.py index 942cadc35..f62a3a975 100644 --- a/zun/service/periodic.py +++ b/zun/service/periodic.py @@ -27,7 +27,8 @@ LOG = log.getLogger(__name__) def set_context(func): @functools.wraps(func) def handler(self, ctx): - ctx = context.get_admin_context(all_tenants=True) + if ctx is None: + ctx = context.get_admin_context(all_tenants=True) func(self, ctx) return handler