Avoid serializing CinderExceptions before they are translated

CinderExceptions were being unicode()'d when being wrapped in an
HTTPException, and this was causing the delayed translation to fail for
those errors.

Also, CinderExceptions have a 'message' class attribute that holds the
generic error message template, e.g. "Backup  %(backup_id)s is not
found", unfortunately, because the names are the same, it was
overshadowing the actual exception instance 'message', e.g. "Backup 1 is
not found", when translating. This patch puts the exception's actual
message in a new field called 'msg'.

Fixes Bug: #1214102

Change-Id: Ied9abcc3d05454852c0a5891432eb181220a744e
This commit is contained in:
Luis A. Garcia
2013-08-19 20:19:57 +00:00
parent 5d6c11facc
commit 2bec15e185
11 changed files with 40 additions and 35 deletions

View File

@@ -131,7 +131,7 @@ class BackupsController(wsgi.Controller):
try:
backup = self.backup_api.get(context, backup_id=id)
except exception.BackupNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
return self._view_builder.detail(req, backup)
@@ -145,9 +145,9 @@ class BackupsController(wsgi.Controller):
try:
self.backup_api.delete(context, id)
except exception.BackupNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
except exception.InvalidBackup as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
return webob.Response(status_int=202)
@@ -207,11 +207,11 @@ class BackupsController(wsgi.Controller):
new_backup = self.backup_api.create(context, name, description,
volume_id, container)
except exception.InvalidVolume as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.VolumeNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
except exception.ServiceNotFound as error:
raise exc.HTTPInternalServerError(explanation=unicode(error))
raise exc.HTTPInternalServerError(explanation=error.msg)
retval = self._view_builder.summary(req, dict(new_backup.iteritems()))
return retval
@@ -244,21 +244,21 @@ class BackupsController(wsgi.Controller):
backup_id=id,
volume_id=volume_id)
except exception.InvalidInput as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.InvalidVolume as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.InvalidBackup as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.BackupNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
except exception.VolumeNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
except exception.VolumeSizeExceedsAvailableQuota as error:
raise exc.HTTPRequestEntityTooLarge(
explanation=error.message, headers={'Retry-After': 0})
explanation=error.msg, headers={'Retry-After': 0})
except exception.VolumeLimitExceeded as error:
raise exc.HTTPRequestEntityTooLarge(
explanation=error.message, headers={'Retry-After': 0})
explanation=error.msg, headers={'Retry-After': 0})
retval = self._view_builder.restore_summary(
req, dict(new_restore.iteritems()))

View File

@@ -64,7 +64,7 @@ class VolumeTypeExtraSpecsController(wsgi.Controller):
try:
volume_types.get_volume_type(context, type_id)
except exception.NotFound as ex:
raise webob.exc.HTTPNotFound(explanation=unicode(ex))
raise webob.exc.HTTPNotFound(explanation=ex.msg)
@wsgi.serializers(xml=VolumeTypeExtraSpecsTemplate)
def index(self, req, type_id):
@@ -138,7 +138,7 @@ class VolumeTypeExtraSpecsController(wsgi.Controller):
try:
db.volume_type_extra_specs_delete(context, type_id, id)
except exception.VolumeTypeExtraSpecsNotFound as error:
raise webob.exc.HTTPNotFound(explanation=unicode(error))
raise webob.exc.HTTPNotFound(explanation=error.msg)
notifier_info = dict(type_id=type_id, id=id)
notifier_api.notify(context, 'volumeTypeExtraSpecs',

View File

@@ -183,7 +183,7 @@ class VolumeActionsController(wsgi.Controller):
try:
volume = self.volume_api.get(context, id)
except exception.VolumeNotFound as error:
raise webob.exc.HTTPNotFound(explanation=unicode(error))
raise webob.exc.HTTPNotFound(explanation=error.msg)
authorize(context, "upload_image")
image_metadata = {"container_format": params.get("container_format",
"bare"),
@@ -195,7 +195,7 @@ class VolumeActionsController(wsgi.Controller):
image_metadata,
force)
except exception.InvalidVolume as error:
raise webob.exc.HTTPBadRequest(explanation=unicode(error))
raise webob.exc.HTTPBadRequest(explanation=error.msg)
except ValueError as error:
raise webob.exc.HTTPBadRequest(explanation=unicode(error))
except rpc_common.RemoteError as error:

View File

@@ -113,7 +113,7 @@ class VolumeTransferController(wsgi.Controller):
try:
transfer = self.transfer_api.get(context, transfer_id=id)
except exception.TransferNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
return self._view_builder.detail(req, transfer)
@@ -168,9 +168,9 @@ class VolumeTransferController(wsgi.Controller):
try:
new_transfer = self.transfer_api.create(context, volume_id, name)
except exception.InvalidVolume as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.VolumeNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
transfer = self._view_builder.create(req,
dict(new_transfer.iteritems()))
@@ -203,9 +203,9 @@ class VolumeTransferController(wsgi.Controller):
auth_key)
except exception.VolumeSizeExceedsAvailableQuota as error:
raise exc.HTTPRequestEntityTooLarge(
explanation=error.message, headers={'Retry-After': 0})
explanation=error.msg, headers={'Retry-After': 0})
except exception.InvalidVolume as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
transfer = \
self._view_builder.summary(req,
@@ -221,7 +221,7 @@ class VolumeTransferController(wsgi.Controller):
try:
self.transfer_api.delete(context, transfer_id=id)
except exception.TransferNotFound as error:
raise exc.HTTPNotFound(explanation=unicode(error))
raise exc.HTTPNotFound(explanation=error.msg)
return webob.Response(status_int=202)

View File

@@ -55,7 +55,7 @@ class VolumeTypeEncryptionController(wsgi.Controller):
try:
volume_types.get_volume_type(context, type_id)
except exception.NotFound as ex:
raise webob.exc.HTTPNotFound(explanation=unicode(ex))
raise webob.exc.HTTPNotFound(explanation=ex.msg)
def _check_encryption_input(self, encryption, create=True):
if 'key_size' in encryption.keys():

View File

@@ -588,11 +588,10 @@ class ResourceExceptionHandler(object):
return True
if isinstance(ex_value, exception.NotAuthorized):
msg = unicode(ex_value)
raise Fault(webob.exc.HTTPForbidden(explanation=msg))
raise Fault(webob.exc.HTTPForbidden(explanation=ex_value.msg))
elif isinstance(ex_value, exception.Invalid):
raise Fault(exception.ConvertedException(
code=ex_value.code, explanation=unicode(ex_value)))
code=ex_value.code, explanation=ex_value.msg))
elif isinstance(ex_value, TypeError):
exc_info = (ex_type, ex_value, ex_traceback)
LOG.error(_(

View File

@@ -124,10 +124,10 @@ class Controller(object):
raise exc.HTTPBadRequest(explanation=msg)
except exception.InvalidVolumeMetadata as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.InvalidVolumeMetadataSize as error:
raise exc.HTTPRequestEntityTooLarge(explanation=unicode(error))
raise exc.HTTPRequestEntityTooLarge(explanation=error.msg)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, snapshot_id, id):

View File

@@ -124,10 +124,10 @@ class Controller(object):
raise exc.HTTPBadRequest(explanation=msg)
except exception.InvalidVolumeMetadata as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.InvalidVolumeMetadataSize as error:
raise exc.HTTPRequestEntityTooLarge(explanation=unicode(error))
raise exc.HTTPRequestEntityTooLarge(explanation=error.msg)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, volume_id, id):

View File

@@ -124,10 +124,10 @@ class Controller(object):
raise exc.HTTPBadRequest(explanation=msg)
except exception.InvalidVolumeMetadata as error:
raise exc.HTTPBadRequest(explanation=unicode(error))
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.InvalidVolumeMetadataSize as error:
raise exc.HTTPRequestEntityTooLarge(explanation=unicode(error))
raise exc.HTTPRequestEntityTooLarge(explanation=error.msg)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, snapshot_id, id):

View File

@@ -119,8 +119,15 @@ class CinderException(Exception):
# at least get the core message out if something happened
message = self.message
# NOTE(luisg): We put the actual message in 'msg' so that we can access
# it, because if we try to access the message via 'message' it will be
# overshadowed by the class' message attribute
self.msg = message
super(CinderException, self).__init__(message)
def __unicode__(self):
return unicode(self.msg)
class GlanceConnectionFailed(CinderException):
message = _("Connection to glance failed") + ": %(reason)s"

View File

@@ -914,8 +914,7 @@ class BackupsAPITestCase(test.TestCase):
self.assertEqual(res.status_int, 413)
self.assertEqual(res_dict['overLimit']['code'], 413)
self.assertEqual(res_dict['overLimit']['message'],
'Maximum number of volumes allowed '
'(%(allowed)d) exceeded')
'Maximum number of volumes allowed (1) exceeded')
def test_restore_backup_to_undersized_volume(self):
backup_size = 10