From 7320374a1971f33586e01b8761f78fa1820bce7b Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Fri, 2 Aug 2013 14:48:54 +0200 Subject: [PATCH] Include the resource and action in ResourceFailure exceptions An update operation performs 3 different kinds of actions on resources (update, create and delete), and we may want to handle failures differently depending on the action. Change-Id: Icf60a1aea882251150a1507183cf2d23da92675f --- heat/common/exception.py | 4 +++- heat/engine/resource.py | 49 ++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/heat/common/exception.py b/heat/common/exception.py index eb236a5a..62da7969 100644 --- a/heat/common/exception.py +++ b/heat/common/exception.py @@ -267,10 +267,12 @@ class WatchRuleNotFound(OpenstackException): class ResourceFailure(OpenstackException): message = _("%(exc_type)s: %(message)s") - def __init__(self, exception): + def __init__(self, exception, resource, action=None): if isinstance(exception, ResourceFailure): exception = getattr(exception, 'exc', exception) self.exc = exception + self.resource = resource + self.action = action exc_type = type(exception).__name__ super(ResourceFailure, self).__init__(exc_type=exc_type, message=str(exception)) diff --git a/heat/engine/resource.py b/heat/engine/resource.py index f23ce1cf..147584b0 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -370,7 +370,7 @@ class Resource(object): yield except Exception as ex: logger.exception('%s : %s' % (action, str(self))) - failure = exception.ResourceFailure(ex) + failure = exception.ResourceFailure(ex, self, action) self.state_set(action, self.FAILED, str(failure)) raise failure except: @@ -388,10 +388,11 @@ class Resource(object): Create the resource. Subclasses should provide a handle_create() method to customise creation. ''' + action = self.CREATE if (self.action, self.status) != (self.INIT, self.COMPLETE): exc = exception.Error('State %s invalid for create' % str(self.state)) - raise exception.ResourceFailure(exc) + raise exception.ResourceFailure(exc, self, action) logger.info('creating %s' % str(self)) @@ -404,25 +405,27 @@ class Resource(object): self.t.get('Properties', {}), self.stack.resolve_runtime_data, self.name) - return self._do_action(self.CREATE, self.properties.validate) + return self._do_action(action, self.properties.validate) def update(self, after, before=None): ''' update the resource. Subclasses should provide a handle_update() method to customise update, the base-class handle_update will fail by default. ''' + action = self.UPDATE + if before is None: before = self.parsed_template() if (self.action, self.status) in ((self.CREATE, self.IN_PROGRESS), - (self.UPDATE, self.IN_PROGRESS)): - raise exception.ResourceFailure(Exception( - 'Resource update already requested')) + (self.UPDATE, self.IN_PROGRESS)): + exc = Exception('Resource update already requested') + raise exception.ResourceFailure(exc, self, action) logger.info('updating %s' % str(self)) try: - self.state_set(self.UPDATE, self.IN_PROGRESS) + self.state_set(action, self.IN_PROGRESS) properties = Properties(self.properties_schema, after.get('Properties', {}), self.stack.resolve_runtime_data, @@ -437,40 +440,44 @@ class Resource(object): raise except Exception as ex: logger.exception('update %s : %s' % (str(self), str(ex))) - failure = exception.ResourceFailure(ex) - self.state_set(self.UPDATE, self.FAILED, str(failure)) + failure = exception.ResourceFailure(ex, self, action) + self.state_set(action, self.FAILED, str(failure)) raise failure else: self.t = self.stack.resolve_static_data(after) - self.state_set(self.UPDATE, self.COMPLETE) + self.state_set(action, self.COMPLETE) def suspend(self): ''' Suspend the resource. Subclasses should provide a handle_suspend() method to implement suspend ''' + action = self.SUSPEND + # Don't try to suspend the resource unless it's in a stable state if (self.action == self.DELETE or self.status != self.COMPLETE): exc = exception.Error('State %s invalid for suspend' % str(self.state)) - raise exception.ResourceFailure(exc) + raise exception.ResourceFailure(exc, self, action) logger.info('suspending %s' % str(self)) - return self._do_action(self.SUSPEND) + return self._do_action(action) def resume(self): ''' Resume the resource. Subclasses should provide a handle_resume() method to implement resume ''' + action = self.RESUME + # Can't resume a resource unless it's SUSPEND_COMPLETE if self.state != (self.SUSPEND, self.COMPLETE): exc = exception.Error('State %s invalid for resume' % str(self.state)) - raise exception.ResourceFailure(exc) + raise exception.ResourceFailure(exc, self, action) logger.info('resuming %s' % str(self)) - return self._do_action(self.RESUME) + return self._do_action(action) def physical_resource_name(self): if self.id is None: @@ -502,6 +509,8 @@ class Resource(object): Delete the resource. Subclasses should provide a handle_delete() method to customise deletion. ''' + action = self.DELETE + if (self.action, self.status) == (self.DELETE, self.COMPLETE): return # No need to delete if the resource has never been created @@ -513,7 +522,7 @@ class Resource(object): logger.info('deleting %s' % str(self)) try: - self.state_set(self.DELETE, self.IN_PROGRESS) + self.state_set(action, self.IN_PROGRESS) deletion_policy = self.t.get('DeletionPolicy', 'Delete') if deletion_policy == 'Delete': @@ -524,18 +533,18 @@ class Resource(object): self.handle_snapshot_delete(initial_state) except Exception as ex: logger.exception('Delete %s', str(self)) - failure = exception.ResourceFailure(ex) - self.state_set(self.DELETE, self.FAILED, str(failure)) + failure = exception.ResourceFailure(ex, self, self.action) + self.state_set(action, self.FAILED, str(failure)) raise failure except: with excutils.save_and_reraise_exception(): try: - self.state_set(self.DELETE, self.FAILED, + self.state_set(action, self.FAILED, 'Deletion aborted') except Exception: logger.exception('Error marking resource deletion failed') else: - self.state_set(self.DELETE, self.COMPLETE) + self.state_set(action, self.COMPLETE) def destroy(self): ''' @@ -702,7 +711,7 @@ class Resource(object): self.handle_signal(details) except Exception as ex: logger.exception('signal %s : %s' % (str(self), str(ex))) - failure = exception.ResourceFailure(ex) + failure = exception.ResourceFailure(ex, self) raise failure def handle_update(self, json_snippet=None, tmpl_diff=None, prop_diff=None): -- 2.45.2