Replace message with msg_fmt for custom exceptions

The custom exceptions were defining the message format string as the
'message' attribute, which was confusing as 'message' is also being used
as an input argument to the class.  This combined with the fact that the
the 'message' attribute of Python's BaseException has been deprecated,
msg_fmt replaces message to hold the message format of the exception.

The root cause of the bug in question was caused by the __unicode__
method returning self.message, which did not have the kwargs substituted
into the actual message format.  The fix is to use self.args[0] instead,
which will contain the message format with the kwargs substituted in
since that is passed to the super's (Exception) __init__ method.  See
PEP 0352 for more information on how Exception and BaseException work.

The _cleanse_dict method is also removed as it is not used anywhere.

Change-Id: Ie8ac96afaecc732693a184d0e06e77c56ca8eeb9
Closes-Bug: #1535473
This commit is contained in:
Taylor Peoples
2016-01-19 04:00:03 +01:00
parent 65cf19a7e4
commit 7fcb683404

View File

@@ -40,20 +40,15 @@ CONF = cfg.CONF
CONF.register_opts(exc_log_opts) CONF.register_opts(exc_log_opts)
def _cleanse_dict(original):
"""Strip all admin_password, new_pass, rescue_pass keys from a dict"""
return dict((k, v) for k, v in original.items() if "_pass" not in k)
class WatcherException(Exception): class WatcherException(Exception):
"""Base Watcher Exception """Base Watcher Exception
To correctly use this class, inherit from it and define To correctly use this class, inherit from it and define
a 'message' property. That message will get printf'd a 'msg_fmt' property. That msg_fmt will get printf'd
with the keyword arguments provided to the constructor. with the keyword arguments provided to the constructor.
""" """
message = _("An unknown exception occurred") msg_fmt = _("An unknown exception occurred")
code = 500 code = 500
headers = {} headers = {}
safe = False safe = False
@@ -69,10 +64,9 @@ class WatcherException(Exception):
if not message: if not message:
try: try:
message = self.message % kwargs message = self.msg_fmt % kwargs
except Exception as e: except Exception as e:
# kwargs doesn't match a variable in the message # kwargs doesn't match a variable in msg_fmt
# log the issue and the kwargs # log the issue and the kwargs
LOG.exception(_LE('Exception in string format operation')) LOG.exception(_LE('Exception in string format operation'))
for name, value in kwargs.items(): for name, value in kwargs.items():
@@ -81,8 +75,8 @@ class WatcherException(Exception):
if CONF.fatal_exception_format_errors: if CONF.fatal_exception_format_errors:
raise e raise e
else: else:
# at least get the core message out if something happened # at least get the core msg_fmt out if something happened
message = self.message message = self.msg_fmt
super(WatcherException, self).__init__(message) super(WatcherException, self).__init__(message)
@@ -94,7 +88,7 @@ class WatcherException(Exception):
return self.args[0] return self.args[0]
def __unicode__(self): def __unicode__(self):
return self.message return unicode(self.args[0])
def format_message(self): def format_message(self):
if self.__class__.__name__.endswith('_Remote'): if self.__class__.__name__.endswith('_Remote'):
@@ -104,114 +98,114 @@ class WatcherException(Exception):
class NotAuthorized(WatcherException): class NotAuthorized(WatcherException):
message = _("Not authorized") msg_fmt = _("Not authorized")
code = 403 code = 403
class OperationNotPermitted(NotAuthorized): class OperationNotPermitted(NotAuthorized):
message = _("Operation not permitted") msg_fmt = _("Operation not permitted")
class Invalid(WatcherException): class Invalid(WatcherException):
message = _("Unacceptable parameters") msg_fmt = _("Unacceptable parameters")
code = 400 code = 400
class ObjectNotFound(WatcherException): class ObjectNotFound(WatcherException):
message = _("The %(name)s %(id)s could not be found") msg_fmt = _("The %(name)s %(id)s could not be found")
class Conflict(WatcherException): class Conflict(WatcherException):
message = _('Conflict') msg_fmt = _('Conflict')
code = 409 code = 409
class ResourceNotFound(ObjectNotFound): class ResourceNotFound(ObjectNotFound):
message = _("The %(name)s resource %(id)s could not be found") msg_fmt = _("The %(name)s resource %(id)s could not be found")
code = 404 code = 404
class InvalidIdentity(Invalid): class InvalidIdentity(Invalid):
message = _("Expected an uuid or int but received %(identity)s") msg_fmt = _("Expected an uuid or int but received %(identity)s")
class InvalidGoal(Invalid): class InvalidGoal(Invalid):
message = _("Goal %(goal)s is not defined in Watcher configuration file") msg_fmt = _("Goal %(goal)s is not defined in Watcher configuration file")
# Cannot be templated as the error syntax varies. # Cannot be templated as the error syntax varies.
# msg needs to be constructed when raised. # msg needs to be constructed when raised.
class InvalidParameterValue(Invalid): class InvalidParameterValue(Invalid):
message = _("%(err)s") msg_fmt = _("%(err)s")
class InvalidUUID(Invalid): class InvalidUUID(Invalid):
message = _("Expected a uuid but received %(uuid)s") msg_fmt = _("Expected a uuid but received %(uuid)s")
class InvalidName(Invalid): class InvalidName(Invalid):
message = _("Expected a logical name but received %(name)s") msg_fmt = _("Expected a logical name but received %(name)s")
class InvalidUuidOrName(Invalid): class InvalidUuidOrName(Invalid):
message = _("Expected a logical name or uuid but received %(name)s") msg_fmt = _("Expected a logical name or uuid but received %(name)s")
class AuditTemplateNotFound(ResourceNotFound): class AuditTemplateNotFound(ResourceNotFound):
message = _("AuditTemplate %(audit_template)s could not be found") msg_fmt = _("AuditTemplate %(audit_template)s could not be found")
class AuditTemplateAlreadyExists(Conflict): class AuditTemplateAlreadyExists(Conflict):
message = _("An audit_template with UUID %(uuid)s or name %(name)s " msg_fmt = _("An audit_template with UUID %(uuid)s or name %(name)s "
"already exists") "already exists")
class AuditTemplateReferenced(Invalid): class AuditTemplateReferenced(Invalid):
message = _("AuditTemplate %(audit_template)s is referenced by one or " msg_fmt = _("AuditTemplate %(audit_template)s is referenced by one or "
"multiple audit") "multiple audit")
class AuditNotFound(ResourceNotFound): class AuditNotFound(ResourceNotFound):
message = _("Audit %(audit)s could not be found") msg_fmt = _("Audit %(audit)s could not be found")
class AuditAlreadyExists(Conflict): class AuditAlreadyExists(Conflict):
message = _("An audit with UUID %(uuid)s already exists") msg_fmt = _("An audit with UUID %(uuid)s already exists")
class AuditReferenced(Invalid): class AuditReferenced(Invalid):
message = _("Audit %(audit)s is referenced by one or multiple action " msg_fmt = _("Audit %(audit)s is referenced by one or multiple action "
"plans") "plans")
class ActionPlanNotFound(ResourceNotFound): class ActionPlanNotFound(ResourceNotFound):
message = _("ActionPlan %(action plan)s could not be found") msg_fmt = _("ActionPlan %(action plan)s could not be found")
class ActionPlanAlreadyExists(Conflict): class ActionPlanAlreadyExists(Conflict):
message = _("An action plan with UUID %(uuid)s already exists") msg_fmt = _("An action plan with UUID %(uuid)s already exists")
class ActionPlanReferenced(Invalid): class ActionPlanReferenced(Invalid):
message = _("Action Plan %(action_plan)s is referenced by one or " msg_fmt = _("Action Plan %(action_plan)s is referenced by one or "
"multiple actions") "multiple actions")
class ActionNotFound(ResourceNotFound): class ActionNotFound(ResourceNotFound):
message = _("Action %(action)s could not be found") msg_fmt = _("Action %(action)s could not be found")
class ActionAlreadyExists(Conflict): class ActionAlreadyExists(Conflict):
message = _("An action with UUID %(uuid)s already exists") msg_fmt = _("An action with UUID %(uuid)s already exists")
class ActionReferenced(Invalid): class ActionReferenced(Invalid):
message = _("Action plan %(action_plan)s is referenced by one or " msg_fmt = _("Action plan %(action_plan)s is referenced by one or "
"multiple goals") "multiple goals")
class ActionFilterCombinationProhibited(Invalid): class ActionFilterCombinationProhibited(Invalid):
message = _("Filtering actions on both audit and action-plan is " msg_fmt = _("Filtering actions on both audit and action-plan is "
"prohibited") "prohibited")
@@ -220,7 +214,7 @@ class HTTPNotFound(ResourceNotFound):
class PatchError(Invalid): class PatchError(Invalid):
message = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s") msg_fmt = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s")
# decision engine # decision engine
@@ -274,30 +268,30 @@ class NoDataFound(BaseException):
class KeystoneFailure(WatcherException): class KeystoneFailure(WatcherException):
message = _("'Keystone API endpoint is missing''") msg_fmt = _("'Keystone API endpoint is missing''")
class ClusterEmpty(WatcherException): class ClusterEmpty(WatcherException):
message = _("The list of hypervisor(s) in the cluster is empty") msg_fmt = _("The list of hypervisor(s) in the cluster is empty")
class MetricCollectorNotDefined(WatcherException): class MetricCollectorNotDefined(WatcherException):
message = _("The metrics resource collector is not defined") msg_fmt = _("The metrics resource collector is not defined")
class ClusterStateNotDefined(WatcherException): class ClusterStateNotDefined(WatcherException):
message = _("the cluster state is not defined") msg_fmt = _("the cluster state is not defined")
# Model # Model
class InstanceNotFound(WatcherException): class InstanceNotFound(WatcherException):
message = _("The instance '%(name)s' is not found") msg_fmt = _("The instance '%(name)s' is not found")
class HypervisorNotFound(WatcherException): class HypervisorNotFound(WatcherException):
message = _("The hypervisor is not found") msg_fmt = _("The hypervisor is not found")
class LoadingError(WatcherException): class LoadingError(WatcherException):
message = _("Error loading plugin '%(name)s'") msg_fmt = _("Error loading plugin '%(name)s'")