From b2d4535064d1ec1231c4b226d806b1d7fe6f24d6 Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Wed, 26 Jun 2013 12:44:58 +0100 Subject: [PATCH] engine : parser.Stack create general stack_task Remove duplication between create_task and suspend_task by refactoring to provide a more general stack_task Change-Id: I81a1a94d70475b0c13c881dea5c6ce7b2c5d7ce1 --- heat/engine/parser.py | 82 ++++++++++++++++------------------- heat/engine/stack_resource.py | 8 +++- heat/tests/test_parser.py | 4 +- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 14b260ae..bde6661d 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -283,39 +283,58 @@ class Stack(object): ''' Create the stack and all of the resources. ''' - creator = scheduler.TaskRunner(self.create_task) + def rollback(): + if not self.disable_rollback and self.state == (self.CREATE, + self.FAILED): + self.delete(action=self.ROLLBACK) + + creator = scheduler.TaskRunner(self.stack_task, + action=self.CREATE, + reverse=False, + post_func=rollback) creator(timeout=self.timeout_secs()) @scheduler.wrappertask - def create_task(self): + def stack_task(self, action, reverse=False, post_func=None): ''' - A task to create the stack and all of the resources. + A task to perform an action on the stack and all of the resources + in forward or reverse dependency order as specfifed by reverse ''' - self.state_set(self.CREATE, self.IN_PROGRESS, 'Stack creation started') + self.state_set(action, self.IN_PROGRESS, + 'Stack %s started' % action) stack_status = self.COMPLETE - reason = 'Stack successfully created' + reason = 'Stack %s completed successfully' % action.lower() res = None - def resource_create(r): - return r.create() + def resource_action(r): + # Find e.g resource.create and call it + action_l = action.lower() + handle = getattr(r, '%s' % action_l, None) + if callable(handle): + return handle() + else: + raise exception.ResourceFailure( + AttributeError(_('Resource action %s not found') % + action_l)) - create_task = scheduler.DependencyTaskGroup(self.dependencies, - resource_create) + action_task = scheduler.DependencyTaskGroup(self.dependencies, + resource_action, + reverse) try: - yield create_task() + yield action_task() except exception.ResourceFailure as ex: stack_status = self.FAILED - reason = 'Resource failed: %s' % str(ex) + reason = 'Resource %s failed: %s' % (action.lower(), str(ex)) except scheduler.Timeout: stack_status = self.FAILED - reason = 'Timed out' + reason = '%s timed out' % action.title() - self.state_set(self.CREATE, stack_status, reason) + self.state_set(action, stack_status, reason) - if stack_status == self.FAILED and not self.disable_rollback: - self.delete(action=self.ROLLBACK) + if callable(post_func): + post_func() def update(self, newstack, action=UPDATE): ''' @@ -436,38 +455,11 @@ class Stack(object): other than move to SUSPEND_COMPLETE, so the resources must implement handle_suspend for this to have any effect. ''' - sus_task = scheduler.TaskRunner(self.suspend_task) + sus_task = scheduler.TaskRunner(self.stack_task, + action=self.SUSPEND, + reverse=True) sus_task(timeout=self.timeout_secs()) - @scheduler.wrappertask - def suspend_task(self): - ''' - A task to suspend the stack, suspends each resource in reverse - dependency order - ''' - logger.info("Stack %s suspend started" % self.name) - self.state_set(self.SUSPEND, self.IN_PROGRESS, 'Stack suspend started') - - stack_status = self.COMPLETE - reason = 'Stack suspend complete' - - def resource_suspend(r): - return r.suspend() - - sus_task = scheduler.DependencyTaskGroup(self.dependencies, - resource_suspend, - reverse=True) - try: - yield sus_task() - except exception.ResourceFailure as ex: - stack_status = self.FAILED - reason = 'Resource failed: %s' % str(ex) - except scheduler.Timeout: - stack_status = self.FAILED - reason = 'Suspend timed out' - - self.state_set(self.SUSPEND, stack_status, reason) - def output(self, key): ''' Get the value of the specified stack output. diff --git a/heat/engine/stack_resource.py b/heat/engine/stack_resource.py index aef449d6..a79b55f9 100644 --- a/heat/engine/stack_resource.py +++ b/heat/engine/stack_resource.py @@ -78,7 +78,8 @@ class StackResource(resource.Resource): nested_id = self._nested.store(self.stack) self.resource_id_set(nested_id) - stack_creator = scheduler.TaskRunner(self._nested.create_task) + stack_creator = scheduler.TaskRunner(self._nested.stack_task, + action=self.CREATE) stack_creator.start(timeout=self._nested.timeout_secs()) return stack_creator @@ -109,7 +110,10 @@ class StackResource(resource.Resource): raise exception.Error(_('Cannot suspend %s, stack not created') % self.name) - suspend_task = scheduler.TaskRunner(self._nested.suspend_task) + suspend_task = scheduler.TaskRunner(self._nested.stack_task, + action=self.SUSPEND, + reverse=True) + suspend_task.start(timeout=self._nested.timeout_secs()) return suspend_task diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py index 51f8789d..3d437309 100644 --- a/heat/tests/test_parser.py +++ b/heat/tests/test_parser.py @@ -634,7 +634,7 @@ class StackTest(HeatTestCase): self.assertEqual(self.stack.state, (self.stack.SUSPEND, self.stack.FAILED)) self.assertEqual(self.stack.status_reason, - 'Resource failed: Exception: foo') + 'Resource suspend failed: Exception: foo') self.m.VerifyAll() @stack_delete_after @@ -1398,7 +1398,7 @@ class StackTest(HeatTestCase): self.assertEqual(stack.state, (parser.Stack.CREATE, parser.Stack.FAILED)) - self.assertEqual(stack.status_reason, 'Timed out') + self.assertEqual(stack.status_reason, 'Create timed out') self.m.VerifyAll() -- 2.45.2