Add "only_if" capability, which allows task steps to be skipped if they do not match a conditional.

This commit is contained in:
Michael DeHaan 2012-03-20 19:55:04 -04:00
parent 149cc57b0f
commit dfbe591cc0
3 changed files with 42 additions and 13 deletions

View file

@ -77,6 +77,7 @@ class PlayBook(object):
self.changed = {}
self.invocations = {}
self.failures = {}
self.skipped = {}
# playbook file can be passed in as a path or
# as file contents (to support API usage)
@ -158,8 +159,13 @@ class PlayBook(object):
'resources' : self.invocations.get(host, 0),
'changed' : self.changed.get(host, 0),
'dark' : self.dark.get(host, 0),
'failed' : self.failures.get(host, 0)
'failed' : self.failures.get(host, 0),
'skipped' : self.skipped.get(host, 0)
}
# FIXME: TODO: use callback to reinstate per-host summary
# and add corresponding code in /bin/ansible-playbook
# print results
return results
def _prune_failed_hosts(self, host_list):
@ -175,12 +181,12 @@ class PlayBook(object):
for (host, res) in results['contacted'].iteritems():
# FIXME: make polling pattern in /bin/ansible match
# move to common function in utils
if not 'finished' in res and 'started' in res:
if not 'finished' in res and not 'skipped' in res and 'started' in res:
hosts.append(host)
return hosts
def _async_poll(self, runner, async_seconds, async_poll_interval):
def _async_poll(self, runner, async_seconds, async_poll_interval, only_if):
''' launch an async job, if poll_interval is set, wait for completion '''
# TODO: refactor this function
@ -197,6 +203,8 @@ class PlayBook(object):
if 'failed' in host_result:
self.callbacks.on_failed(host, host_result)
self.failures[host] = 1
if 'skipped' in host_result:
self.skipped[host] = self.skipped.get(host, 0) + 1
if async_poll_interval <= 0:
# if not polling, playbook requested fire and forget
@ -248,6 +256,11 @@ class PlayBook(object):
if 'failed' in host_result:
self.callbacks.on_failed(host, host_result)
self.failures[host] = 1
if 'skipped' in host_result:
# NOTE: callbacks on skipped? should not really
# happen at this point in the loop
self.skipped[host] = self.skipped.get(host, 0) + 1
for (host, host_result) in poll_results['contacted'].iteritems():
results['contacted'][host] = host_result
@ -267,7 +280,7 @@ class PlayBook(object):
return results
def _run_module(self, pattern, module, args, hosts, remote_user,
async_seconds, async_poll_interval):
async_seconds, async_poll_interval, only_if):
''' run a particular module step in a playbook '''
runner = ansible.runner.Runner(
@ -281,13 +294,14 @@ class PlayBook(object):
timeout=self.timeout,
remote_user=remote_user,
setup_cache=SETUP_CACHE,
basedir=self.basedir
basedir=self.basedir,
conditionally_execute_if=only_if
)
if async_seconds == 0:
rc = runner.run()
else:
rc = self._async_poll(runner, async_seconds, async_poll_interval)
rc = self._async_poll(runner, async_seconds, async_poll_interval, only_if)
dark_hosts = rc.get('dark',{})
for (host, error) in dark_hosts.iteritems():
@ -314,13 +328,12 @@ class PlayBook(object):
host_list = self._prune_failed_hosts(host_list)
# load the module name and parameters from the task entry
name = task['name']
action = task['action']
name = task['name'] # FIXME: error if not set
action = task['action'] # FIXME: error if not set
only_if = task.get('only_if', 'True')
async_seconds = int(task.get('async', 0)) # not async by default
async_poll_interval = int(task.get('poll', 10)) # default poll = 10 seconds
# comment = task.get('comment', '')
tokens = shlex.split(action)
module_name = tokens[0]
module_args = tokens[1:]
@ -336,7 +349,7 @@ class PlayBook(object):
# run the task in parallel
results = self._run_module(pattern, module_name,
module_args, host_list, remote_user,
async_seconds, async_poll_interval)
async_seconds, async_poll_interval, only_if)
# if no hosts are matched, carry on, unlike /bin/ansible
# which would warn you about this
@ -357,7 +370,8 @@ class PlayBook(object):
self.dark[host] = 1
else:
self.dark[host] = self.dark[host] + 1
# FIXME: refactor
for host, results in contacted.iteritems():
self.processed[host] = 1
@ -378,6 +392,12 @@ class PlayBook(object):
self.changed[host] = 1
else:
self.changed[host] = self.changed[host] + 1
# TODO: verify/test that async steps are skippable
if results.get('skipped', False):
if not host in self.changed:
self.skipped[host] = 1
else:
self.skipped[host] = self.skipped[host] + 1
# flag which notify handlers need to be run
# this will be on a SUBSET of the actual host list. For instance