Adds image delete to server side

This patch adds image delete to server side for deleting
pulled image in docker img or glance image.

Implements: blueprint support-image-delete

https://blueprints.launchpad.net/zun/+spec/support-image-delete

Change-Id: I735783aa57925c7593c52a63d590fe93cf22d7c4
This commit is contained in:
caishan 2018-03-08 01:36:53 -08:00
parent 1e396dd43f
commit be92134f2c
12 changed files with 90 additions and 9 deletions

View File

@ -65,6 +65,14 @@ class ImagesController(base.Controller):
'search': ['GET']
}
@pecan.expose('json')
@exception.wrap_pecan_controller_exception
@validation.validate_query_param(pecan.request, schema.query_param_search)
def delete(self, image_id):
context = pecan.request.context
image = utils.get_image(image_id)
return pecan.request.compute_api.image_delete(context, image)
@pecan.expose('json')
@exception.wrap_pecan_controller_exception
def get_all(self, **kwargs):

View File

@ -69,6 +69,17 @@ rules = [
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=IMAGE % 'delete',
check_str=base.RULE_ADMIN_API,
description='Delete an image.',
operations=[
{
'path': '/v1/images/{image_ident}',
'method': 'DELETE'
}
]
)
]

View File

@ -163,6 +163,9 @@ class API(object):
self._record_action_start(context, container, container_actions.COMMIT)
return self.rpcapi.container_commit(context, container, *args)
def image_delete(self, context, image):
return self.rpcapi.image_delete(context, image)
def image_pull(self, context, image):
return self.rpcapi.image_pull(context, image)

View File

@ -909,6 +909,14 @@ class Manager(periodic_task.PeriodicTasks):
container_image_id,
container_image, tag)
def image_delete(self, context, image):
utils.spawn_n(self._do_image_delete, context, image)
def _do_image_delete(self, context, image):
LOG.debug('Deleting image...')
image_driver.delete_image(context, image.image_id)
image.destroy(context, image.uuid)
def image_pull(self, context, image):
utils.spawn_n(self._do_image_pull, context, image)

View File

@ -167,6 +167,10 @@ class API(rpc_service.API):
return self._cast(container.host, 'remove_security_group',
container=container, security_group=security_group)
def image_delete(self, context, image):
host = None
self._cast(host, 'image_delete', image=image)
def image_pull(self, context, image):
# NOTE(hongbin): Image API doesn't support multiple compute nodes
# scenario yet, so we temporarily set host to None and rpc will

View File

@ -275,6 +275,12 @@ def list_zun_services_by_binary(context, binary):
return _get_dbdriver_instance().list_zun_services_by_binary(binary)
@profiler.trace("db")
def destroy_image(context, image_uuid):
"""Destroy a image"""
return _get_dbdriver_instance().destroy_image(context, image_uuid)
@profiler.trace("db")
def pull_image(context, values):
"""Create a new image.

View File

@ -365,6 +365,17 @@ class EtcdAPI(object):
six.text_type(e))
raise
@lockutils.synchronized('etcd_image')
def destroy_image(self, context, img_id):
try:
self.client.delete('/images/' + img_id)
except etcd.EtcdKeyNotFound:
raise exception.ImageNotFound(image=img_id)
except Exception as e:
LOG.error('Error occurred while deleting image: %s',
six.text_type(e))
raise
@lockutils.synchronized('etcd_image')
def pull_image(self, context, values):
if not values.get('uuid'):

View File

@ -385,6 +385,15 @@ class Connection(object):
query = query.filter_by(binary=binary)
return _paginate_query(models.ZunService, query=query)
def destroy_image(self, context, uuid):
session = get_session()
with session.begin():
query = model_query(models.Image, session=session)
query = add_identity_filter(query, uuid)
count = query.delete()
if count != 1:
raise exception.ImageNotFound(uuid)
def pull_image(self, context, values):
# ensure defaults are present for new images
if not values.get('uuid'):

View File

@ -33,6 +33,20 @@ class DockerDriver(driver.ContainerImageDriver):
def __init__(self):
super(DockerDriver, self).__init__()
def delete_image(self, context, img_id):
LOG.debug('Delete an image %s in docker', img_id)
with docker_utils.docker_client() as docker:
try:
docker.remove_image(img_id)
except errors.APIError as api_error:
raise exception.ZunException(str(api_error))
except Exception as e:
LOG.exception('Unknown exception occurred while deleting '
'image %s in glance:%s',
img_id,
six.text_type(e))
raise exception.ZunException(six.text_type(e))
def _search_image_on_host(self, repo, tag):
with docker_utils.docker_client() as docker:
image = repo + ":" + tag

View File

@ -136,13 +136,14 @@ def upload_image_data(context, image, image_tag, image_data,
def delete_image(context, img_id, image_driver):
try:
image_driver.delete_image(context, img_id)
except Exception as e:
LOG.exception('Unknown exception occurred while deleting image %s: %s',
img_id,
six.text_type(e))
raise exception.ZunException(six.text_type(e))
image_driver_list = CONF.image_driver_list
for driver in image_driver_list:
try:
image_driver = load_image_driver(driver)
image_driver.delete_image(context, img_id)
except exception.ZunException:
LOG.exception('Unknown exception occurred while deleting image %s',
img_id)
class ContainerImageDriver(object):

View File

@ -19,7 +19,8 @@ from zun.objects import base
@base.ZunObjectRegistry.register
class Image(base.ZunPersistentObject, base.ZunObject):
# Version 1.0: Initial version
VERSION = '1.0'
# Version = '1.1': Add delete image
VERSION = '1.1'
fields = {
'id': fields.IntegerField(),
@ -82,6 +83,11 @@ class Image(base.ZunPersistentObject, base.ZunObject):
filters=filters)
return Image._from_db_object_list(db_images, cls, context)
@base.remotable
def destroy(self, context, image_uuid):
dbapi.destroy_image(context, image_uuid)
self.obj_reset_changes()
@base.remotable
def pull(self, context=None):
"""Create an image record in the DB.

View File

@ -346,7 +346,7 @@ class TestObject(test_base.TestCase, _TestObject):
object_data = {
'Container': '1.25-545ae961a844ea755b930c6da066eb02',
'VolumeMapping': '1.1-50df6202f7846a136a91444c38eba841',
'Image': '1.0-0b976be24f4f6ee0d526e5c981ce0633',
'Image': '1.1-330e6205c80b99b59717e1cfc6a79935',
'MyObj': '1.0-34c4b1aadefd177b13f9a2f894cc23cd',
'NUMANode': '1.0-cba878b70b2f8b52f1e031b41ac13b4e',
'NUMATopology': '1.0-b54086eda7e4b2e6145ecb6ee2c925ab',