From 05a128c2be2fb452a11a31d8ec06daed8aa4afeb Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Fri, 10 Aug 2012 01:13:37 -0400 Subject: [PATCH] Add ability to store and access module results later on in the play. See examples/playbooks/register_logic for details. --- CHANGELOG.md | 2 +- examples/playbooks/register_logic.yml | 29 +++++++++++++++++++++++++++ lib/ansible/playbook/__init__.py | 3 ++- lib/ansible/playbook/task.py | 5 +++-- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 examples/playbooks/register_logic.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 596a7088ad2..2cd35fd8a03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ Ansible Changes By Release * allow variables in parameterized task include parameters (regression) * make remote_md5 internal function work with non-bash shells * allow user to be passed in via --extra-vars (regression) -* ${last_result} variable stores the last result for each host +* add ability to store the result of any command in a register (see examples/playbooks/register_logic.yml) 0.6 "Cabo" -- August 6, 2012 diff --git a/examples/playbooks/register_logic.yml b/examples/playbooks/register_logic.yml new file mode 100644 index 00000000000..d9582c45ff5 --- /dev/null +++ b/examples/playbooks/register_logic.yml @@ -0,0 +1,29 @@ +# here's a cool advanced topic about how to perform conditional logic in ansible without resorting +# to writing your own module that defines facts. You can do that too, and it's easy to do, but +# often you just want to run a command and then decide whether to run some steps or not. That's +# easy to do, and here we'll show you how. + +- name: test playbook + user: root + hosts: all + + tasks: + + # it is possible to save the result of any command in a named register. This variable will be made + # available to tasks and templates made further down in the execution flow. Here we save the result + # of a simple 'cat' command in a variable called 'motd_contents' + + - action: shell cat /etc/motd + register: motd_contents + + # and here we access the register. Note that motd_contents as a variable is structured data because + # it is a return from the command module. The shell module makes available variables such as + # as 'stdout', 'stderr', and 'rc'. Here's a rather trivial example that runs an arbitrary step + # if and only if the motd file contained the word 'hi'. Remember that only_if statements are + # Python expressions. This is as complicated as Ansible syntax is going to get, and the only + # time python really seeps into ansible's language. + + - action: shell echo "motd contains the word hi" + only_if: "'${motd_contents.stdout}'.find('hi') != -1" + + diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py index f162428c18c..b6685926747 100644 --- a/lib/ansible/playbook/__init__.py +++ b/lib/ansible/playbook/__init__.py @@ -224,7 +224,8 @@ class PlayBook(object): for host, result in results['contacted'].iteritems(): facts = result.get('ansible_facts', {}) self.SETUP_CACHE[host].update(facts) - self.SETUP_CACHE[host]['last_result'] = result + if task.register: + self.SETUP_CACHE[host][task.register] = result # flag which notify handlers need to be run if len(task.notify) > 0: diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 3e4da8551f3..d861c0ebd8f 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -23,13 +23,13 @@ class Task(object): __slots__ = [ 'name', 'action', 'only_if', 'async_seconds', 'async_poll_interval', 'notify', 'module_name', 'module_args', 'module_vars', - 'play', 'notified_by', 'tags', 'with_items', 'first_available_file', 'ignore_errors' + 'play', 'notified_by', 'tags', 'register', 'with_items', 'first_available_file', 'ignore_errors' ] # to prevent typos and such VALID_KEYS = [ 'name', 'action', 'only_if', 'async', 'poll', 'notify', 'with_items', 'first_available_file', - 'include', 'tags', 'ignore_errors' + 'include', 'tags', 'register', 'ignore_errors' ] def __init__(self, play, ds, module_vars=None): @@ -46,6 +46,7 @@ class Task(object): self.name = ds.get('name', None) self.action = ds.get('action', '') self.tags = [ 'all' ] + self.register = ds.get('register', None) # notified by is used by Playbook code to flag which hosts # need to run a notifier