From a7eca15f006bac3398b41f03e776c5652f3fcf11 Mon Sep 17 00:00:00 2001 From: Fei Long Wang Date: Wed, 16 Nov 2016 14:33:58 +1300 Subject: [PATCH] Avoid deleting location data if current image is not the owner Change-Id: Ia949818a75b9162b8cace07a24f6276e3492a503 --- glance/db/simple/api.py | 17 +++++++++++++++++ glance/db/sqlalchemy/api.py | 13 +++++++++++++ glance/location.py | 20 ++++++++++++++++---- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/glance/db/simple/api.py b/glance/db/simple/api.py index fd3d5ee..a24123f 100644 --- a/glance/db/simple/api.py +++ b/glance/db/simple/api.py @@ -619,6 +619,23 @@ def image_location_delete(context, image_id, location_id, status, raise exception.NotFound(msg) +def image_locations_with_url(context, location): + locations = [] + try: + for loc in DATA['locations']: + if loc['url'] == location['url']: + locations.append(loc) + keyfn = lambda x: (x[sort_key] if x[sort_key] is not None else '', + x['created_at'], x['id']) + locations.sort(key=keyfn) + return locations + except sa_orm.exc.NoResultFound: + msg = (_("No location found with url %(loc)s") % + dict(loc=location['url'])) + LOG.warn(msg) + return locations + + def _image_locations_set(context, image_id, locations): # NOTE(zhiyan): 1. Remove records from DB for deleted locations used_loc_ids = [loc['id'] for loc in locations if loc.get('id')] diff --git a/glance/db/sqlalchemy/api.py b/glance/db/sqlalchemy/api.py index 77ab684..5424b08 100644 --- a/glance/db/sqlalchemy/api.py +++ b/glance/db/sqlalchemy/api.py @@ -938,6 +938,19 @@ def image_location_delete(context, image_id, location_id, status, raise exception.NotFound(msg) +def image_locations_with_url(context, location, session=None): + try: + session = session or get_session() + locations = session.query(models.ImageLocation).filter_by( + value=location['url']).order_by(models.ImageLocation.created_at).all() + return locations + except sa_orm.exc.NoResultFound: + msg = (_("No location found with url %(loc)s") % + dict(loc=location['url'])) + LOG.warn(msg) + return [] + + def _image_locations_set(context, image_id, locations, session=None): # NOTE(zhiyan): 1. Remove records from DB for deleted locations session = session or get_session() diff --git a/glance/location.py b/glance/location.py index f7f2250..9ebc6c0 100644 --- a/glance/location.py +++ b/glance/location.py @@ -400,10 +400,22 @@ class ImageProxy(glance.domain.proxy.Image): self.image.delete() if self.image.locations: for location in self.image.locations: - self.store_utils.delete_image_location_from_backend( - self.context, - self.image.image_id, - location) + locs = self.image.db_api.image_locations_with_url(self.context, + location) + # NOTE(flwang): 1. If current image is the "owner" of this + # location, the location can be deleted, no matter if there + # is another image using it. 2. If current image is not the + # "owner" of this location, the location's back end data can't + # be deleted. + # The locations list returned by function + # "image_locations_with_url" are sorted by the creation time + # of the location, because technically, the location owner is + # the image who created the location at the first time. + if len(locs) > 0 and locs[0].image_id == self.image.image_id: + self.store_utils.delete_image_location_from_backend( + self.context, + self.image.image_id, + location) def set_data(self, data, size=None): if size is None: -- 1.9.1