Use handle_update_cancel() to cancel nested stack updates
The code designed to deal with the case where an in-progress StackResource update is cancelled by stopping the update of the nested stack has never worked because it was erroneously trying to catch StopIteration exceptions instead of the actual exception raised when a generator is closed, GeneratorExit. This change moves the handling code to the new handle_update_cancel() mechanism instead. Using this mechanism also means that StackResources will be cancelled immediately, rather than waiting for up to error_wait_time before cancelling the nested stack update. The previous patch adds a grace period for IN_PROGRESS resources within the nested stack to complete, so we want to notify it straight away to begin that period (and to not start any new work). Since the grace period on the child stack means that the child is likely to still be IN_PROGRESS at the time we want to roll back, handle rollback by sending an update-cancel with rollback message to the child. Only if the child is no longer IN_PROGRESS will we start an update with the previous template. If it is still IN_PROGRESS then just wait for it to reach ROLLBACK_COMPLETE. Change-Id: Ide210f695446fe8de2057b3b74c276165a6f9f3f Closes-Bug: #1591337 Closes-Bug: #1446252
This commit is contained in:
parent
e7a9e03132
commit
97a3670462
|
@ -22,6 +22,7 @@ import six
|
|||
|
||||
from heat.common import exception
|
||||
from heat.common.i18n import _
|
||||
from heat.common.i18n import _LI
|
||||
from heat.common.i18n import _LW
|
||||
from heat.common import identifier
|
||||
from heat.common import template_format
|
||||
|
@ -110,19 +111,6 @@ class StackResource(resource.Resource):
|
|||
|
||||
return True
|
||||
|
||||
@scheduler.wrappertask
|
||||
def update(self, after, before=None, prev_resource=None):
|
||||
try:
|
||||
yield super(StackResource, self).update(after, before,
|
||||
prev_resource)
|
||||
except StopIteration:
|
||||
with excutils.save_and_reraise_exception():
|
||||
stack_identity = self.nested_identifier()
|
||||
self.rpc_client().stack_cancel_update(
|
||||
self.context,
|
||||
dict(stack_identity),
|
||||
cancel_with_rollback=False)
|
||||
|
||||
def nested_identifier(self):
|
||||
if self.resource_id is None:
|
||||
return None
|
||||
|
@ -423,12 +411,41 @@ class StackResource(resource.Resource):
|
|||
def check_adopt_complete(self, cookie=None):
|
||||
return self._check_status_complete(self.ADOPT)
|
||||
|
||||
def _try_rollback(self):
|
||||
stack_identity = self.nested_identifier()
|
||||
if stack_identity is None:
|
||||
return False
|
||||
|
||||
self.rpc_client().stack_cancel_update(
|
||||
self.context,
|
||||
dict(stack_identity),
|
||||
cancel_with_rollback=True)
|
||||
|
||||
try:
|
||||
data = stack_object.Stack.get_status(self.context,
|
||||
self.resource_id)
|
||||
except exception.NotFound:
|
||||
return False
|
||||
|
||||
action, status, status_reason, updated_time = data
|
||||
|
||||
# If nested stack is still in progress, it should eventually roll
|
||||
# itself back due to stack_cancel_update(), so we just need to wait
|
||||
# for that to complete
|
||||
return status == self.stack.IN_PROGRESS
|
||||
|
||||
def update_with_template(self, child_template, user_params=None,
|
||||
timeout_mins=None):
|
||||
"""Update the nested stack with the new template."""
|
||||
if self.id is None:
|
||||
self._store()
|
||||
|
||||
if self.stack.action == self.stack.ROLLBACK:
|
||||
if self._try_rollback():
|
||||
LOG.info(_LI('Triggered nested stack %s rollback'),
|
||||
self.physical_resource_name())
|
||||
return {'target_action': self.stack.ROLLBACK}
|
||||
|
||||
nested_stack = self.nested()
|
||||
if nested_stack is None:
|
||||
# if the create failed for some reason and the nested
|
||||
|
@ -469,9 +486,22 @@ class StackResource(resource.Resource):
|
|||
return cookie
|
||||
|
||||
def check_update_complete(self, cookie=None):
|
||||
return self._check_status_complete(self.UPDATE,
|
||||
if cookie is not None and 'target_action' in cookie:
|
||||
target_action = cookie['target_action']
|
||||
cookie = None
|
||||
else:
|
||||
target_action = self.stack.UPDATE
|
||||
return self._check_status_complete(target_action,
|
||||
cookie=cookie)
|
||||
|
||||
def handle_update_cancel(self, cookie):
|
||||
stack_identity = self.nested_identifier()
|
||||
if stack_identity is not None:
|
||||
self.rpc_client().stack_cancel_update(
|
||||
self.context,
|
||||
dict(stack_identity),
|
||||
cancel_with_rollback=False)
|
||||
|
||||
def delete_nested(self):
|
||||
"""Delete the nested stack."""
|
||||
stack = self.nested()
|
||||
|
|
Loading…
Reference in New Issue