Save snapshot to db before stack snapshot complete
When executing stack snapshot heat do not release stack lock some undefined amount of time because it needs to prepare some data for stack snapshot. It leads to situation when stack snapshot is complete(from user perspective) but nobody can do any operations with stack. So the fix executes snapshot saving to DB right before stack becomes complete. Change-Id: Id011142498fee49fee9ec1437fc0816b25780e48 Closes-bug: #1456672
This commit is contained in:
parent
60300b0149
commit
3433be5426
|
@ -1277,13 +1277,18 @@ class EngineService(service.Service):
|
|||
@context.request_context
|
||||
def stack_snapshot(self, cnxt, stack_identity, name):
|
||||
def _stack_snapshot(stack, snapshot):
|
||||
LOG.debug("snapshotting stack %s" % stack.name)
|
||||
stack.snapshot()
|
||||
data = stack.prepare_abandon()
|
||||
snapshot_object.Snapshot.update(
|
||||
cnxt, snapshot.id,
|
||||
{'data': data, 'status': stack.status,
|
||||
'status_reason': stack.status_reason})
|
||||
|
||||
def save_snapshot(stack, action, status, reason):
|
||||
"""Function that saves snapshot before snapshot complete."""
|
||||
data = stack.prepare_abandon()
|
||||
data["status"] = status
|
||||
snapshot_object.Snapshot.update(
|
||||
cnxt, snapshot.id,
|
||||
{'data': data, 'status': status,
|
||||
'status_reason': reason})
|
||||
|
||||
LOG.debug("Snapshotting stack %s" % stack.name)
|
||||
stack.snapshot(save_snapshot_func=save_snapshot)
|
||||
|
||||
s = self._get_stack(cnxt, stack_identity)
|
||||
|
||||
|
|
|
@ -777,10 +777,22 @@ class Stack(collections.Mapping):
|
|||
@scheduler.wrappertask
|
||||
def stack_task(self, action, reverse=False, post_func=None,
|
||||
error_wait_time=None,
|
||||
aggregate_exceptions=False):
|
||||
aggregate_exceptions=False, pre_completion_func=None):
|
||||
'''
|
||||
A task to perform an action on the stack and all of the resources
|
||||
in forward or reverse dependency order as specified by reverse
|
||||
|
||||
:param action action that should be executed with stack resources
|
||||
:param reverse defines if action on the resources need to be executed
|
||||
in reverse order (resources - first and then res dependencies )
|
||||
:param post_func function that need to be executed after
|
||||
action complete on the stack
|
||||
:param error_wait_time time to wait before cancelling all execution
|
||||
threads when an error occurred
|
||||
:param aggregate_exceptions defines if exceptions should be aggregated
|
||||
:param pre_completion_func function that need to be executed right
|
||||
before action completion. Uses stack ,action, status and reason as
|
||||
input parameters
|
||||
'''
|
||||
try:
|
||||
lifecycle_plugin_utils.do_pre_ops(self.context, self,
|
||||
|
@ -829,6 +841,9 @@ class Stack(collections.Mapping):
|
|||
stack_status = self.FAILED
|
||||
reason = 'Resource %s failed: %s' % (action, six.text_type(ex))
|
||||
|
||||
if pre_completion_func:
|
||||
pre_completion_func(self, action, stack_status, reason)
|
||||
|
||||
self.state_set(action, stack_status, reason)
|
||||
|
||||
if callable(post_func):
|
||||
|
@ -1431,12 +1446,12 @@ class Stack(collections.Mapping):
|
|||
sus_task(timeout=self.timeout_secs())
|
||||
|
||||
@profiler.trace('Stack.snapshot', hide_args=False)
|
||||
def snapshot(self):
|
||||
def snapshot(self, save_snapshot_func):
|
||||
'''Snapshot the stack, invoking handle_snapshot on all resources.'''
|
||||
self.updated_time = datetime.datetime.utcnow()
|
||||
sus_task = scheduler.TaskRunner(self.stack_task,
|
||||
action=self.SNAPSHOT,
|
||||
reverse=False)
|
||||
sus_task = scheduler.TaskRunner(self.stack_task, action=self.SNAPSHOT,
|
||||
reverse=False,
|
||||
pre_completion_func=save_snapshot_func)
|
||||
sus_task(timeout=self.timeout_secs())
|
||||
|
||||
@profiler.trace('Stack.delete_snapshot', hide_args=False)
|
||||
|
|
|
@ -1034,7 +1034,7 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
|
|||
|
||||
self.assertEqual((stack.CREATE, stack.COMPLETE), stack.state)
|
||||
|
||||
scheduler.TaskRunner(stack.snapshot)()
|
||||
scheduler.TaskRunner(stack.snapshot, None)()
|
||||
|
||||
self.assertEqual((stack.SNAPSHOT, stack.COMPLETE), stack.state)
|
||||
|
||||
|
|
|
@ -3280,7 +3280,7 @@ class ServersTest(common.HeatTestCase):
|
|||
|
||||
self.assertEqual((stack.CREATE, stack.COMPLETE), stack.state)
|
||||
|
||||
scheduler.TaskRunner(stack.snapshot)()
|
||||
scheduler.TaskRunner(stack.snapshot, None)()
|
||||
|
||||
self.assertEqual((stack.SNAPSHOT, stack.COMPLETE), stack.state)
|
||||
|
||||
|
|
|
@ -1796,6 +1796,21 @@ class StackTest(common.HeatTestCase):
|
|||
'(AResource Bar) is incorrect.',
|
||||
six.text_type(ex))
|
||||
|
||||
def test_snapshot_save_called_first(self):
|
||||
def snapshotting_called_first(stack, action, status, reason):
|
||||
self.assertEqual(stack.status, stack.IN_PROGRESS)
|
||||
self.assertEqual(stack.action, stack.SNAPSHOT)
|
||||
|
||||
tmpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||
'Resources': {
|
||||
'A': {'Type': 'GenericResourceType'},
|
||||
'B': {'Type': 'GenericResourceType'}}}
|
||||
self.stack = stack.Stack(self.ctx, 'stack_details_test',
|
||||
template.Template(tmpl))
|
||||
self.stack.store()
|
||||
self.stack.create()
|
||||
self.stack.snapshot(save_snapshot_func=snapshotting_called_first)
|
||||
|
||||
def test_restore(self):
|
||||
tmpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||
'Resources': {
|
||||
|
|
Loading…
Reference in New Issue