Merge "Merge before/after 'requires' list on update failure"

This commit is contained in:
Zuul 2018-04-30 07:31:11 +00:00 committed by Gerrit Code Review
commit cff24227f0
2 changed files with 37 additions and 42 deletions

View File

@ -1421,18 +1421,9 @@ class Resource(status.ResourceStatus):
resource_data and existing resource's requires, then updates the
resource by invoking the scheduler TaskRunner.
"""
def update_templ_id_and_requires(persist=True):
self.current_template_id = template_id
self.requires = list(
set(data.primary_key for data in resource_data.values()
if data is not None)
)
if not persist:
return
self.store(lock=self.LOCK_RESPECT)
self._calling_engine_id = engine_id
new_requires = set(data.primary_key for data in resource_data.values()
if data is not None)
# Check that the resource type matches. If the type has changed by a
# legitimate substitution, the load()ed resource will already be of
@ -1456,18 +1447,10 @@ class Resource(status.ResourceStatus):
six.text_type(failure))
raise failure
runner = scheduler.TaskRunner(
self.update, new_res_def,
update_templ_func=update_templ_id_and_requires)
try:
runner(timeout=timeout, progress_callback=progress_callback)
except UpdateReplace:
raise
except exception.UpdateInProgress:
raise
except BaseException:
with excutils.save_and_reraise_exception():
update_templ_id_and_requires(persist=True)
runner = scheduler.TaskRunner(self.update, new_res_def,
new_template_id=template_id,
new_requires=new_requires)
runner(timeout=timeout, progress_callback=progress_callback)
def preview_update(self, after, before, after_props, before_props,
prev_resource, check_init_complete=False):
@ -1584,9 +1567,24 @@ class Resource(status.ResourceStatus):
return is_substituted
return False
def _persist_update_no_change(self, new_template_id):
"""Persist an update where the resource is unchanged."""
if new_template_id is not None:
self.current_template_id = new_template_id
lock = (self.LOCK_RESPECT if self.stack.convergence
else self.LOCK_NONE)
if self.status == self.FAILED:
status_reason = _('Update status to COMPLETE for '
'FAILED resource neither update '
'nor replace.')
self.state_set(self.action, self.COMPLETE,
status_reason, lock=lock)
elif new_template_id is not None:
self.store(lock=lock)
@scheduler.wrappertask
def update(self, after, before=None, prev_resource=None,
update_templ_func=None):
new_template_id=None, new_requires=None):
"""Return a task to update the resource.
Subclasses should provide a handle_update() method to customise update,
@ -1607,8 +1605,7 @@ class Resource(status.ResourceStatus):
raise exception.ResourceFailure(exc, self, action)
elif after_external_id is not None:
LOG.debug("Skip update on external resource.")
if update_templ_func is not None:
update_templ_func(persist=True)
self._persist_update_no_change(new_template_id)
return
after_props, before_props = self._prepare_update_props(after, before)
@ -1640,17 +1637,7 @@ class Resource(status.ResourceStatus):
raise failure
if not needs_update:
is_failed = self.status == self.FAILED
if update_templ_func is not None:
update_templ_func(persist=not is_failed)
if is_failed:
status_reason = _('Update status to COMPLETE for '
'FAILED resource neither update '
'nor replace.')
lock = (self.LOCK_RESPECT if self.stack.convergence
else self.LOCK_NONE)
self.state_set(self.action, self.COMPLETE,
status_reason, lock=lock)
self._persist_update_no_change(new_template_id)
return
if not self.stack.convergence:
@ -1665,10 +1652,14 @@ class Resource(status.ResourceStatus):
self.updated_time = datetime.utcnow()
if new_requires is not None:
self.requires = list(set(self.requires) | new_requires)
with self._action_recorder(action, UpdateReplace):
after_props.validate()
self.properties = before_props
tmpl_diff = self.update_template_diff(after.freeze(), before)
old_template_id = self.current_template_id
try:
if tmpl_diff and self.needs_replace_with_tmpl_diff(tmpl_diff):
@ -1676,19 +1667,23 @@ class Resource(status.ResourceStatus):
prop_diff = self.update_template_diff_properties(after_props,
before_props)
if new_template_id is not None:
self.current_template_id = new_template_id
yield self.action_handler_task(action,
args=[after, tmpl_diff,
prop_diff])
except UpdateReplace:
with excutils.save_and_reraise_exception():
self.current_template_id = old_template_id
self._prepare_update_replace(action)
self.t = after
self.reparse()
self._update_stored_properties()
if update_templ_func is not None:
# template/requires will be persisted by _action_recorder()
update_templ_func(persist=False)
if new_requires is not None:
self.requires = list(new_requires)
yield self._break_if_required(
self.UPDATE, environment.HOOK_POST_UPDATE)

View File

@ -2322,10 +2322,10 @@ class ResourceTest(common.HeatTestCase):
self.assertEqual(new_temp.id, res.current_template_id)
# check if requires was updated
self.assertItemsEqual([3, 4], res.requires)
self.assertItemsEqual([2, 3, 4], res.requires)
self.assertEqual(res.action, resource.Resource.UPDATE)
self.assertEqual(res.status, resource.Resource.FAILED)
self._assert_resource_lock(res.id, None, 3)
self._assert_resource_lock(res.id, None, 2)
def test_update_resource_convergence_update_replace(self):
tmpl = template.Template({