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:
parent
1e396dd43f
commit
be92134f2c
@ -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):
|
||||
|
@ -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'
|
||||
}
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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'):
|
||||
|
@ -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'):
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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.
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user