Refactor API error handling

Refactor the API error handling to ensure error messages are translated.
Since wsme 0.5b6, the error message doesn't need to be converted to
unicode, wsme handles it for us.

Related bug #1200518

Change-Id: Iec396f045cd3afe817301f0d00917c42c7587b55
This commit is contained in:
Mehdi Abaakouk 2013-10-30 09:54:05 +01:00
parent fe158993bb
commit 4a638fab63
2 changed files with 26 additions and 32 deletions

View File

@ -67,7 +67,13 @@ state_kind_enum = wtypes.Enum(str, *state_kind)
operation_kind = wtypes.Enum(str, 'lt', 'le', 'eq', 'ne', 'ge', 'gt') operation_kind = wtypes.Enum(str, 'lt', 'le', 'eq', 'ne', 'ge', 'gt')
class EntityNotFound(wsme.exc.ClientSideError): class ClientSideError(wsme.exc.ClientSideError):
def __init__(self, error, status_code=400):
pecan.response.translatable_error = error
super(ClientSideError, self).__init__(error, status_code)
class EntityNotFound(ClientSideError):
def __init__(self, entity, id): def __init__(self, entity, id):
super(EntityNotFound, self).__init__( super(EntityNotFound, self).__init__(
_("%(entity)s %(id)s Not Found") % {'entity': entity, _("%(entity)s %(id)s Not Found") % {'entity': entity,
@ -99,14 +105,12 @@ class BoundedInt(wtypes.UserType):
if self.min is not None and value < self.min: if self.min is not None and value < self.min:
error = _('Value %(value)s is invalid (should be greater or equal ' error = _('Value %(value)s is invalid (should be greater or equal '
'to %(min)s)') % dict(value=value, min=self.min) 'to %(min)s)') % dict(value=value, min=self.min)
pecan.response.translatable_error = error raise ClientSideError(error)
raise wsme.exc.ClientSideError(unicode(error))
if self.max is not None and value > self.max: if self.max is not None and value > self.max:
error = _('Value %(value)s is invalid (should be lower or equal ' error = _('Value %(value)s is invalid (should be lower or equal '
'to %(max)s)') % dict(value=value, max=self.max) 'to %(max)s)') % dict(value=value, max=self.max)
pecan.response.translatable_error = error raise ClientSideError(error)
raise wsme.exc.ClientSideError(unicode(error))
return value return value
@ -262,21 +266,21 @@ class Query(_Base):
msg = _('Failed to convert the metadata value %(value)s' msg = _('Failed to convert the metadata value %(value)s'
' to the expected data type %(type)s.') % \ ' to the expected data type %(type)s.') % \
{'value': self.value, 'type': type} {'value': self.value, 'type': type}
raise wsme.exc.ClientSideError(unicode(msg)) raise ClientSideError(msg)
except TypeError: except TypeError:
msg = _('The data type %s is not supported. The supported' msg = _('The data type %s is not supported. The supported'
' data type list is: integer, float, boolean and' ' data type list is: integer, float, boolean and'
' string.') % (type) ' string.') % (type)
raise wsme.exc.ClientSideError(unicode(msg)) raise ClientSideError(msg)
except Exception: except Exception:
msg = _('Unexpected exception converting %(value)s to' msg = _('Unexpected exception converting %(value)s to'
' the expected data type %(type)s.') % \ ' the expected data type %(type)s.') % \
{'value': self.value, 'type': type} {'value': self.value, 'type': type}
raise wsme.exc.ClientSideError(unicode(msg)) raise ClientSideError(msg)
return converted_value return converted_value
class ProjectNotAuthorized(wsme.exc.ClientSideError): class ProjectNotAuthorized(ClientSideError):
def __init__(self, id): def __init__(self, id):
super(ProjectNotAuthorized, self).__init__( super(ProjectNotAuthorized, self).__init__(
_("Not Authorized to access project %s") % id, _("Not Authorized to access project %s") % id,
@ -787,9 +791,7 @@ class MeterController(rest.RestController):
period long of that number of seconds. period long of that number of seconds.
""" """
if period and period < 0: if period and period < 0:
error = _("Period must be positive.") raise ClientSideError(_("Period must be positive."))
pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(unicode(error))
kwargs = _query_to_kwargs(q, storage.SampleFilter.__init__) kwargs = _query_to_kwargs(q, storage.SampleFilter.__init__)
kwargs['meter'] = self._id kwargs['meter'] = self._id
@ -1158,14 +1160,12 @@ class Alarm(_Base):
and alarm.combination_rule == wtypes.Unset): and alarm.combination_rule == wtypes.Unset):
error = _("either threshold_rule or combination_rule " error = _("either threshold_rule or combination_rule "
"must be set") "must be set")
pecan.response.translatable_error = error raise ClientSideError(error)
raise wsme.exc.ClientSideError(unicode(error))
if alarm.threshold_rule and alarm.combination_rule: if alarm.threshold_rule and alarm.combination_rule:
error = _("threshold_rule and combination_rule " error = _("threshold_rule and combination_rule "
"cannot be set at the same time") "cannot be set at the same time")
pecan.response.translatable_error = error raise ClientSideError(error)
raise wsme.exc.ClientSideError(unicode(error))
if alarm.threshold_rule: if alarm.threshold_rule:
# ensure an implicit constraint on project_id is added to # ensure an implicit constraint on project_id is added to
@ -1183,9 +1183,7 @@ class Alarm(_Base):
alarms = list(pecan.request.storage_conn.get_alarms( alarms = list(pecan.request.storage_conn.get_alarms(
alarm_id=id, project=project)) alarm_id=id, project=project))
if not alarms: if not alarms:
error = _("Alarm %s doesn't exist") % id raise ClientSideError(_("Alarm %s doesn't exist") % id)
pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(unicode(error))
return alarm return alarm
@ -1350,9 +1348,7 @@ class AlarmController(rest.RestController):
alarm_in = storage.models.Alarm(**updated_alarm) alarm_in = storage.models.Alarm(**updated_alarm)
except Exception: except Exception:
LOG.exception("Error while putting alarm: %s" % updated_alarm) LOG.exception("Error while putting alarm: %s" % updated_alarm)
error = _("Alarm incorrect") raise ClientSideError(_("Alarm incorrect"))
pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(unicode(error))
alarm = self.conn.update_alarm(alarm_in) alarm = self.conn.update_alarm(alarm_in)
@ -1402,10 +1398,7 @@ class AlarmController(rest.RestController):
# note(sileht): body are not validated by wsme # note(sileht): body are not validated by wsme
# Workaround for https://bugs.launchpad.net/wsme/+bug/1227229 # Workaround for https://bugs.launchpad.net/wsme/+bug/1227229
if state not in state_kind: if state not in state_kind:
error = _("state invalid") raise ClientSideError(_("state invalid"))
pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(unicode(error))
now = timeutils.utcnow() now = timeutils.utcnow()
alarm = self._alarm() alarm = self._alarm()
alarm.state = state alarm.state = state
@ -1488,17 +1481,13 @@ class AlarmsController(rest.RestController):
alarms = list(conn.get_alarms(name=data.name, alarms = list(conn.get_alarms(name=data.name,
project=data.project_id)) project=data.project_id))
if len(alarms) > 0: if len(alarms) > 0:
error = _("Alarm with that name exists") raise ClientSideError(_("Alarm with that name exists"))
pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(unicode(error))
try: try:
alarm_in = storage.models.Alarm(**change) alarm_in = storage.models.Alarm(**change)
except Exception: except Exception:
LOG.exception("Error while posting alarm: %s" % change) LOG.exception("Error while posting alarm: %s" % change)
error = _("Alarm incorrect") raise ClientSideError(_("Alarm incorrect"))
pecan.response.translatable_error = error
raise wsme.exc.ClientSideError(unicode(error))
alarm = conn.create_alarm(alarm_in) alarm = conn.create_alarm(alarm_in)
self._record_creation(conn, change, alarm.alarm_id, now) self._record_creation(conn, change, alarm.alarm_id, now)

View File

@ -16,6 +16,7 @@
"""Test the methods related to query.""" """Test the methods related to query."""
import datetime import datetime
import fixtures
import mock import mock
import wsme import wsme
@ -29,6 +30,10 @@ from ceilometer.tests import base as tests_base
class TestQuery(test.BaseTestCase): class TestQuery(test.BaseTestCase):
def setUp(self):
super(TestQuery, self).setUp()
self.useFixture(fixtures.MonkeyPatch(
'pecan.response', mock.MagicMock()))
def test_get_value_as_type_with_integer(self): def test_get_value_as_type_with_integer(self):
query = Query(field='metadata.size', query = Query(field='metadata.size',