From 42e3d02dbf311e6e0d6ce87ccfb218499b09a4a9 Mon Sep 17 00:00:00 2001 From: Thomas Herve Date: Wed, 17 May 2017 16:06:33 +0200 Subject: [PATCH] Fix restore with convergence Handle the restore operation as a normal convergence update instead of a legacy one. Change-Id: I6ee46cdf7a8fdf89c58c9812d08af21c97fb0f9e Related-Bug: #1687006 --- heat/engine/check_resource.py | 3 ++- heat/engine/service.py | 11 +++++++++-- heat/engine/stack.py | 24 ++++++++++++++---------- heat/tests/test_convg_stack.py | 7 ++++--- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/heat/engine/check_resource.py b/heat/engine/check_resource.py index 3972b9cac1..695e5b7f1d 100644 --- a/heat/engine/check_resource.py +++ b/heat/engine/check_resource.py @@ -77,7 +77,8 @@ class CheckResource(object): return False if (not stack.disable_rollback and - stack.action in (stack.CREATE, stack.ADOPT, stack.UPDATE)): + stack.action in (stack.CREATE, stack.ADOPT, stack.UPDATE, + stack.RESTORE)): self._trigger_rollback(stack) else: stack.purge_db() diff --git a/heat/engine/service.py b/heat/engine/service.py index 57f039cd9c..be21ef1cf4 100644 --- a/heat/engine/service.py +++ b/heat/engine/service.py @@ -2113,8 +2113,15 @@ class EngineService(service.ServiceBase): # FIXME(pas-ha) has to be amended to deny restoring stacks # that have disallowed for current user - self.thread_group_mgr.start_with_lock(cnxt, stack, self.engine_id, - _stack_restore, stack, snapshot) + if stack.convergence: + new_stack, tmpl = stack.restore_data(snapshot) + stack.thread_group_mgr = self.thread_group_mgr + stack.converge_stack(template=tmpl, + action=stack.RESTORE, + new_stack=new_stack) + else: + self.thread_group_mgr.start_with_lock( + cnxt, stack, self.engine_id, _stack_restore, stack, snapshot) @context.request_context def stack_list_snapshots(self, cnxt, stack_identity): diff --git a/heat/engine/stack.py b/heat/engine/stack.py index 06d8d93768..53ea731c22 100644 --- a/heat/engine/stack.py +++ b/heat/engine/stack.py @@ -922,7 +922,7 @@ class Stack(collections.Mapping): if self.convergence and action in ( self.UPDATE, self.DELETE, self.CREATE, - self.ADOPT, self.ROLLBACK): + self.ADOPT, self.ROLLBACK, self.RESTORE): # if convergence and stack operation is create/update/rollback/ # delete, stack lock is not used, hence persist state updated = self._persist_state() @@ -940,7 +940,7 @@ class Stack(collections.Mapping): # or action == UPDATE/DELETE/ROLLBACK. Else, it would # be done before releasing the stack lock. if status == self.IN_PROGRESS or action in ( - self.UPDATE, self.DELETE, self.ROLLBACK): + self.UPDATE, self.DELETE, self.ROLLBACK, self.RESTORE): self._persist_state() def _log_status(self): @@ -1908,14 +1908,7 @@ class Stack(collections.Mapping): data = snapshot.data['resources'].get(name) scheduler.TaskRunner(rsrc.delete_snapshot, data)() - @profiler.trace('Stack.restore', hide_args=False) - @reset_state_on_error - def restore(self, snapshot): - """Restore the given snapshot. - - Invokes handle_restore on all resources. - """ - self.updated_time = oslo_timeutils.utcnow() + def restore_data(self, snapshot): env = environment.Environment(snapshot.data['environment']) files = snapshot.data['files'] template = tmpl.Template(snapshot.data['template'], @@ -1935,6 +1928,17 @@ class Stack(collections.Mapping): newstack.parameters.set_stack_id(self.identifier()) + return newstack, template + + @reset_state_on_error + def restore(self, snapshot): + """Restore the given snapshot. + + Invokes handle_restore on all resources. + """ + self.updated_time = oslo_timeutils.utcnow() + newstack = self.restore_data(snapshot)[0] + updater = scheduler.TaskRunner(self.update_task, newstack, action=self.RESTORE) updater() diff --git a/heat/tests/test_convg_stack.py b/heat/tests/test_convg_stack.py index 12621dd66b..a6a0ebfdce 100644 --- a/heat/tests/test_convg_stack.py +++ b/heat/tests/test_convg_stack.py @@ -663,15 +663,16 @@ class TestConvgStackStateSet(common.HeatTestCase): self.assertIsNone(ret_val) def test_state_set_stack_restore(self, mock_ps): + mock_ps.return_value = 'updated' ret_val = self.stack.state_set( self.stack.RESTORE, self.stack.IN_PROGRESS, 'Restore started') self.assertTrue(mock_ps.called) - self.assertIsNone(ret_val) + self.assertEqual('updated', ret_val) mock_ps.reset_mock() ret_val = self.stack.state_set( self.stack.RESTORE, self.stack.COMPLETE, 'Restore complete') - self.assertFalse(mock_ps.called) - self.assertIsNone(ret_val) + self.assertTrue(mock_ps.called) + self.assertEqual('updated', ret_val) class TestConvgStackRollback(common.HeatTestCase):