'A task to perform an action on the stack.
All of the resources are traversed in forward or reverse dependency
order.
:param action: action that should be executed with stack resources
:param reverse: define 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 aggregate_exceptions: define 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'

@scheduler.wrappertask
def stack_task(self, action, reverse=False, post_func=None, aggregate_exceptions=False, pre_completion_func=None):

    try:
        lifecycle_plugin_utils.do_pre_ops(self.context, self, None, action)
    except Exception as e:
        self.state_set(action, self.FAILED, (e.args[0] if e.args else ('Failed    stack    pre-ops:    %s' % six.text_type(e))))
        if callable(post_func):
            post_func()
        return
    self.state_set(action, self.IN_PROGRESS, ('Stack    %s    started' % action))
    stack_status = self.COMPLETE
    reason = ('Stack    %s    completed    successfully' % action)
    action_method = action.lower()
    handle_kwargs = getattr(self, ('_%s_kwargs' % action_method), (lambda x: {}))
    @functools.wraps(getattr(resource.Resource, action_method))
    @scheduler.wrappertask
    def resource_action(r):
        handle = getattr(r, action_method)
        (yield handle(**handle_kwargs(r)))
        if (action == self.CREATE):
            stk_defn.update_resource_data(self.defn, r.name, r.node_data())
    def get_error_wait_time(resource):
        return resource.cancel_grace_period()
    action_task = scheduler.DependencyTaskGroup(self.dependencies, resource_action, reverse, error_wait_time=get_error_wait_time, aggregate_exceptions=aggregate_exceptions)
    try:
        (yield action_task())
    except scheduler.Timeout:
        stack_status = self.FAILED
        reason = ('%s    timed    out' % action.title())
    except Exception as ex:
        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):
        post_func()
    lifecycle_plugin_utils.do_post_ops(self.context, self, None, action, (self.status == self.FAILED))
