Allow handlers to run in between pre_tasks, roles, tasks, and post_tasks.

pull/2730/head
Michael DeHaan 12 years ago
parent 84781bf185
commit 32fb6c807c

@ -496,15 +496,35 @@ class PlayBook(object):
self.inventory.also_restrict_to(on_hosts) self.inventory.also_restrict_to(on_hosts)
for task in play.tasks(): for task in play.tasks():
if task.meta is not None:
# meta tasks are an internalism and are not valid for end-user playbook usage
# here a meta task is a placeholder that signals handlers should be run
if task.meta == 'flush_handlers':
for handler in play.handlers():
if len(handler.notified_by) > 0:
self.inventory.restrict_to(handler.notified_by)
self._run_task(play, handler, True)
self.inventory.lift_restriction()
for host in handler.notified_by:
handler.notified_by.remove(host)
continue
hosts_count = len(self._list_available_hosts(play.hosts)) hosts_count = len(self._list_available_hosts(play.hosts))
# only run the task if the requested tags match # only run the task if the requested tags match
should_run = False should_run = False
for x in self.only_tags: for x in self.only_tags:
for y in task.tags: for y in task.tags:
if (x==y): if (x==y):
should_run = True should_run = True
break break
if should_run: if should_run:
if not self._run_task(play, task, False): if not self._run_task(play, task, False):
# whether no hosts matched is fatal or not depends if it was on the initial step. # whether no hosts matched is fatal or not depends if it was on the initial step.
@ -523,12 +543,13 @@ class PlayBook(object):
return False return False
# run notify actions # run notify actions
for handler in play.handlers(): #for handler in play.handlers():
if len(handler.notified_by) > 0: # if len(handler.notified_by) > 0:
self.inventory.restrict_to(handler.notified_by) # self.inventory.restrict_to(handler.notified_by)
self._run_task(play, handler, True) # self._run_task(play, handler, True)
self.inventory.lift_restriction() # self.inventory.lift_restriction()
handler.notified_by = [] # handler.notified_by = []
# handler.notified_by = []
self.inventory.lift_also_restriction() self.inventory.lift_also_restriction()

@ -127,7 +127,7 @@ class Play(object):
# and it auto-extends tasks/handlers/vars_files as appropriate if found # and it auto-extends tasks/handlers/vars_files as appropriate if found
if roles is None: if roles is None:
return ds roles = []
if type(roles) != list: if type(roles) != list:
raise errors.AnsibleError("value of 'roles:' must be a list") raise errors.AnsibleError("value of 'roles:' must be a list")
@ -140,6 +140,7 @@ class Play(object):
pre_tasks = [] pre_tasks = []
for x in pre_tasks: for x in pre_tasks:
new_tasks.append(x) new_tasks.append(x)
new_tasks.append(dict(meta='flush_handlers'))
# variables if the role was parameterized (i.e. given as a hash) # variables if the role was parameterized (i.e. given as a hash)
has_dict = {} has_dict = {}
@ -200,14 +201,17 @@ class Play(object):
if type(post_tasks) != list: if type(post_tasks) != list:
post_tasks = [] post_tasks = []
new_tasks.append(dict(meta='flush_handlers'))
new_tasks.extend(tasks) new_tasks.extend(tasks)
new_tasks.append(dict(meta='flush_handlers'))
new_tasks.extend(post_tasks) new_tasks.extend(post_tasks)
new_tasks.append(dict(meta='flush_handlers'))
new_handlers.extend(handlers) new_handlers.extend(handlers)
new_vars_files.extend(vars_files) new_vars_files.extend(vars_files)
ds['tasks'] = new_tasks ds['tasks'] = new_tasks
ds['handlers'] = new_handlers ds['handlers'] = new_handlers
ds['vars_files'] = new_vars_files ds['vars_files'] = new_vars_files
return ds return ds
# ************************************************* # *************************************************
@ -223,6 +227,12 @@ class Play(object):
for x in tasks: for x in tasks:
if not isinstance(x, dict): if not isinstance(x, dict):
raise errors.AnsibleError("expecting dict; got: %s" % x) raise errors.AnsibleError("expecting dict; got: %s" % x)
if 'meta' in x:
if x['meta'] == 'flush_handlers':
results.append(Task(self,x))
continue
task_vars = self.vars.copy() task_vars = self.vars.copy()
task_vars.update(vars) task_vars.update(vars)
if original_file: if original_file:
@ -369,7 +379,8 @@ class Play(object):
# gather all the tags in all the tasks into one list # gather all the tags in all the tasks into one list
all_tags = [] all_tags = []
for task in self._tasks: for task in self._tasks:
all_tags.extend(task.tags) if not task.meta:
all_tags.extend(task.tags)
# compare the lists of tags using sets and return the matched and unmatched # compare the lists of tags using sets and return the matched and unmatched
all_tags_set = set(all_tags) all_tags_set = set(all_tags)

@ -22,7 +22,7 @@ import ansible.utils.template as template
class Task(object): class Task(object):
__slots__ = [ __slots__ = [
'name', 'action', 'only_if', 'when', 'async_seconds', 'async_poll_interval', 'name', 'meta', 'action', 'only_if', 'when', 'async_seconds', 'async_poll_interval',
'notify', 'module_name', 'module_args', 'module_vars', 'notify', 'module_name', 'module_args', 'module_vars',
'play', 'notified_by', 'tags', 'register', 'play', 'notified_by', 'tags', 'register',
'delegate_to', 'first_available_file', 'ignore_errors', 'delegate_to', 'first_available_file', 'ignore_errors',
@ -33,7 +33,7 @@ class Task(object):
# to prevent typos and such # to prevent typos and such
VALID_KEYS = [ VALID_KEYS = [
'name', 'action', 'only_if', 'async', 'poll', 'notify', 'name', 'meta', 'action', 'only_if', 'async', 'poll', 'notify',
'first_available_file', 'include', 'tags', 'register', 'ignore_errors', 'first_available_file', 'include', 'tags', 'register', 'ignore_errors',
'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user', 'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user',
'sudo_pass', 'when', 'connection', 'environment', 'args', 'sudo_pass', 'when', 'connection', 'environment', 'args',
@ -43,6 +43,15 @@ class Task(object):
def __init__(self, play, ds, module_vars=None, additional_conditions=None): def __init__(self, play, ds, module_vars=None, additional_conditions=None):
''' constructor loads from a task or handler datastructure ''' ''' constructor loads from a task or handler datastructure '''
# meta directives are used to tell things like ansible/playbook to run
# operations like handler execution. Meta tasks are not executed
# normally.
if 'meta' in ds:
self.meta = ds['meta']
return
else:
self.meta = None
for x in ds.keys(): for x in ds.keys():
# code to allow for saying "modulename: args" versus "action: modulename args" # code to allow for saying "modulename: args" versus "action: modulename args"

Loading…
Cancel
Save