Glance to handle exceptions from glance_store

After the split glance_store raises its own exceptions, that
have the same names as in glance. Several times those exceptions
aren't caught in glance and it leads to incorrect behaviour.
This code fixed it.

Change-Id: I8600e0813ecbc599b5411e1fc0d0c9b470f68f6b
Closes-Bug: #1469817
This commit is contained in:
Mike Fedosin 2015-07-09 11:04:44 +03:00 committed by Darja Shakhray
parent d4cf5a015b
commit 3fc57a4e0a
8 changed files with 114 additions and 37 deletions

View File

@ -93,3 +93,8 @@ class BaseController(object):
raise webob.exc.HTTPBadRequest(explanation=msg,
request=req,
content_type='text/plain')
except store.NotFound:
msg = _("Data for image_id not found: %s") % image_id
raise webob.exc.HTTPNotFound(explanation=msg,
request=req,
content_type='text/plain')

View File

@ -679,7 +679,7 @@ class Controller(controller.BaseController):
return image_meta_data
except exception.Duplicate:
with excutils.save_and_reraise_exception():
# Delete image data since it has been supersceded by another
# Delete image data since it has been superseded by another
# upload and re-raise.
LOG.debug("duplicate operation - deleting image data for "
" %(id)s (location:%(location)s)" %
@ -715,18 +715,19 @@ class Controller(controller.BaseController):
image_id,
location_data,
from_state='saving')
except Exception as e:
except exception.Duplicate:
raise
except Exception:
with excutils.save_and_reraise_exception():
if not isinstance(e, exception.Duplicate):
# NOTE(zhiyan): Delete image data since it has already
# been added to store by above _upload() call.
LOG.warn(_LW("Failed to activate image %s in "
"registry. About to delete image "
"bits from store and update status "
"to 'killed'.") % image_id)
upload_utils.initiate_deletion(req, location_data,
image_id)
upload_utils.safe_kill(req, image_id, 'saving')
# NOTE(zhiyan): Delete image data since it has already
# been added to store by above _upload() call.
LOG.warn(_LW("Failed to activate image %s in "
"registry. About to delete image "
"bits from store and update status "
"to 'killed'.") % image_id)
upload_utils.initiate_deletion(req, location_data,
image_id)
upload_utils.safe_kill(req, image_id, 'saving')
else:
image_meta = None
@ -1130,7 +1131,7 @@ class Controller(controller.BaseController):
raise HTTPForbidden(explanation=msg,
request=req,
content_type="text/plain")
except exception.InUseByStore as e:
except store.InUseByStore as e:
msg = (_("Image %(id)s could not be deleted because it is in use: "
"%(exc)s")
% {"id": id, "exc": encodeutils.exception_to_unicode(e)})

View File

@ -196,7 +196,7 @@ def upload_data_to_store(req, image_meta, image_data, store, notifier):
raise webob.exc.HTTPGone(explanation=msg, request=req,
content_type='text/plain')
except exception.Duplicate as e:
except (store_api.Duplicate, exception.Duplicate) as e:
msg = (_("Attempt to upload duplicate image: %s") %
encodeutils.exception_to_unicode(e))
LOG.warn(msg)

View File

@ -155,7 +155,7 @@ class ImagesController(object):
image_repo.save(image)
except exception.NotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.msg)
except exception.Invalid as e:
except (exception.Invalid, exception.BadStoreUri) as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)
except exception.Forbidden as e:
LOG.debug("User not permitted to update image '%s'", image_id)
@ -232,15 +232,15 @@ class ImagesController(object):
image = image_repo.get(image_id)
image.delete()
image_repo.remove(image)
except exception.Forbidden as e:
except (glance_store.Forbidden, exception.Forbidden) as e:
LOG.debug("User not permitted to delete image '%s'", image_id)
raise webob.exc.HTTPForbidden(explanation=e.msg)
except exception.NotFound as e:
except (glance_store.NotFound, exception.NotFound) as e:
msg = (_("Failed to find image %(image_id)s to delete") %
{'image_id': image_id})
LOG.warn(msg)
raise webob.exc.HTTPNotFound(explanation=msg)
except exception.InUseByStore as e:
except glance_store.exceptions.InUseByStore as e:
msg = (_("Image %(id)s could not be deleted "
"because it is in use: %(exc)s") %
{"id": image_id,

View File

@ -163,6 +163,8 @@ class ArtifactsController(object):
raise webob.exc.HTTPConflict(explanation=dupex.msg)
except exception.Invalid as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)
except exception.NotAuthenticated as e:
raise webob.exc.HTTPUnauthorized(explanation=e.msg)
@utils.mutating
def update_property(self, req, id, type_name, type_version, path, data,
@ -191,6 +193,8 @@ class ArtifactsController(object):
raise webob.exc.HTTPBadRequest(explanation=e.msg)
except exception.NotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.msg)
except exception.NotAuthenticated as e:
raise webob.exc.HTTPUnauthorized(explanation=e.msg)
@utils.mutating
def update(self, req, id, type_name, type_version, changes, **kwargs):
@ -223,6 +227,8 @@ class ArtifactsController(object):
except exception.LimitExceeded as e:
raise webob.exc.HTTPRequestEntityTooLarge(
explanation=e.msg, request=req, content_type='text/plain')
except exception.NotAuthenticated as e:
raise webob.exc.HTTPUnauthorized(explanation=e.msg)
@utils.mutating
def delete(self, req, id, type_name, type_version, **kwargs):
@ -234,16 +240,18 @@ class ArtifactsController(object):
artifact_repo.remove(artifact)
except exception.Invalid as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)
except exception.Forbidden as e:
except (glance_store.Forbidden, exception.Forbidden) as e:
raise webob.exc.HTTPForbidden(explanation=e.msg)
except exception.NotFound as e:
except (glance_store.NotFound, exception.NotFound) as e:
msg = (_("Failed to find artifact %(artifact_id)s to delete") %
{'artifact_id': id})
raise webob.exc.HTTPNotFound(explanation=msg)
except exception.InUseByStore as e:
except glance_store.exceptions.InUseByStore as e:
msg = (_("Artifact %s could not be deleted "
"because it is in use: %s") % (id, e.msg)) # noqa
raise webob.exc.HTTPConflict(explanation=msg)
except exception.NotAuthenticated as e:
raise webob.exc.HTTPUnauthorized(explanation=e.msg)
@utils.mutating
def publish(self, req, id, type_name, type_version, **kwargs):
@ -259,6 +267,8 @@ class ArtifactsController(object):
raise webob.exc.HTTPNotFound(explanation=e.msg)
except exception.Invalid as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)
except exception.NotAuthenticated as e:
raise webob.exc.HTTPUnauthorized(explanation=e.msg)
def _upload_list_property(self, method, blob_list, index, data, size):
if method == 'PUT' and not index and len(blob_list) > 0:
@ -281,6 +291,7 @@ class ArtifactsController(object):
def upload(self, req, id, type_name, type_version, attr, size, data,
index, **kwargs):
artifact_repo = self.gateway.get_artifact_repo(req.context)
artifact = None
try:
artifact = self._get_artifact_with_dependencies(artifact_repo,
id,
@ -302,16 +313,82 @@ class ArtifactsController(object):
artifact_repo.save(artifact)
return artifact
except ValueError as e:
LOG.debug("Cannot save data for artifact %(id)s: %(e)s",
{'id': id, 'e': utils.exception_to_str(e)})
self._restore(artifact_repo, artifact)
raise webob.exc.HTTPBadRequest(
explanation=utils.exception_to_str(e))
except glance_store.StoreAddDisabled:
msg = _("Error in store configuration. Adding artifacts to store "
"is disabled.")
LOG.exception(msg)
self._restore(artifact_repo, artifact)
raise webob.exc.HTTPGone(explanation=msg, request=req,
content_type='text/plain')
except (glance_store.Duplicate,
exception.InvalidImageStatusTransition) as e:
msg = utils.exception_to_str(e)
LOG.exception(msg)
raise webob.exc.HTTPConflict(explanation=e.msg, request=req)
except exception.Forbidden as e:
raise webob.exc.HTTPForbidden(explanation=e.msg)
msg = ("Not allowed to upload data for artifact %s" %
id)
LOG.debug(msg)
raise webob.exc.HTTPForbidden(explanation=msg, request=req)
except exception.NotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.msg)
except exception.Invalid as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)
except Exception as e:
# TODO(mfedosin): add more exception handlers here
except glance_store.StorageFull as e:
msg = _("Artifact storage media "
"is full: %s") % utils.exception_to_str(e)
LOG.error(msg)
self._restore(artifact_repo, artifact)
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg,
request=req)
except exception.StorageQuotaFull as e:
msg = _("Artifact exceeds the storage "
"quota: %s") % utils.exception_to_str(e)
LOG.error(msg)
self._restore(artifact_repo, artifact)
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg,
request=req)
except exception.ImageSizeLimitExceeded as e:
msg = _("The incoming artifact blob is "
"too large: %s") % utils.exception_to_str(e)
LOG.error(msg)
self._restore(artifact_repo, artifact)
raise webob.exc.HTTPRequestEntityTooLarge(explanation=msg,
request=req)
except glance_store.StorageWriteDenied as e:
msg = _("Insufficient permissions on artifact "
"storage media: %s") % utils.exception_to_str(e)
LOG.error(msg)
self._restore(artifact_repo, artifact)
raise webob.exc.HTTPServiceUnavailable(explanation=msg,
request=req)
except webob.exc.HTTPGone as e:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Failed to upload image data due to "
LOG.error(_LE("Failed to upload artifact blob data due to"
" HTTP error"))
except webob.exc.HTTPError as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Failed to upload artifact blob data due to HTTP"
" error"))
self._restore(artifact_repo, artifact)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.exception(_LE("Failed to upload artifact blob data due to "
"internal error"))
self._restore(artifact_repo, artifact)
@ -340,9 +417,9 @@ class ArtifactsController(object):
raise webob.exc.HTTPBadRequest(explanation=message)
except exception.Forbidden as e:
raise webob.exc.HTTPForbidden(explanation=e.msg)
except exception.NotFound as e:
except (glance_store.NotFound, exception.NotFound) as e:
raise webob.exc.HTTPNotFound(explanation=e.msg)
except exception.Invalid as e:
except (glance_store.Invalid, exception.Invalid) as e:
raise webob.exc.HTTPBadRequest(explanation=e.msg)
def _restore(self, artifact_repo, artifact):

View File

@ -290,11 +290,6 @@ class UnsupportedHeaderFeature(GlanceException):
message = _("Provided header feature is unsupported: %(feature)s")
class InUseByStore(GlanceException):
message = _("The image cannot be deleted because it is in use through "
"the backend store outside of Glance.")
class ImageSizeLimitExceeded(GlanceException):
message = _("The provided image is too large.")

View File

@ -77,12 +77,11 @@ def _check_location_uri(context, store_api, store_utils, uri):
:param uri: location's uri string
"""
is_ok = True
try:
# NOTE(zhiyan): Some stores return zero when it catch exception
is_ok = (store_utils.validate_external_location(uri) and
store_api.get_size_from_backend(uri, context=context) > 0)
except (store.UnknownScheme, store.NotFound):
except (store.UnknownScheme, store.NotFound, store.BadStoreUri):
is_ok = False
if not is_ok:
reason = _('Invalid location')

View File

@ -2000,7 +2000,7 @@ class TestImagesController(base.IsolatedUnitTest):
def test_delete_in_use(self):
def fake_safe_delete_from_backend(self, *args, **kwargs):
raise exception.InUseByStore()
raise store.exceptions.InUseByStore()
self.stubs.Set(self.store_utils, 'safe_delete_from_backend',
fake_safe_delete_from_backend)
request = unit_test_utils.get_fake_request()