diff --git a/examples/playbooks/playbook4.yml b/examples/playbooks/playbook4.yml index 7fb6673cb0d..62cc0bc1cff 100644 --- a/examples/playbooks/playbook4.yml +++ b/examples/playbooks/playbook4.yml @@ -9,17 +9,39 @@ favcolor: "red" ssn: 8675309 +# Below we're going to define some expressions. +# +# Not only can we assign variables for reuse, but we can also assign conditional +# expressions. By keeping these in 'vars', the task section remains +# extraordinarily clean, and not littered with programming language +# constructs -- so it's easily skimmed by humans. +# +# Remember to quote any variables if they are not numbers! +# +# Interesting fact: aside from the $variables, these expressions are actually +# tiny bits of Python. They are evaluated in the context of each host, so different +# steps can be skipped on different hosts! They should evaluate to either True +# or False + + is_favcolor_blue: "'$favcolor' == 'blue'" +# is_centos: "'$facter_operatingsystem' == 'CentOS'" + +# NOTE: +# # facter and ohai variables can be used in only_if statements too -# ex: "$facter_operatingsystem == 'CentOS'", which bubble up automatically +# ex: "'$facter_operatingsystem' == 'CentOS'", which bubble up automatically # from the managed machines +# +# this example won't do that though, as you might not have facter or ohai, +# but you get the idea... tasks: - name: "do this if my favcolor is blue" action: shell /bin/false - only_if: "'$favcolor' == 'blue'" + only_if: '$is_favcolor_blue' - - name: "do this if my favcolor is red" - action: shell /bin/false - only_if: "'$favcolor' == 'red'" + - name: "do this if my favcolor is not blue" + action: shell /bin/true + only_if: 'not ($is_favcolor_blue)' diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index 0607bd39188..3e11700fdae 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -27,6 +27,7 @@ import random import traceback import tempfile import subprocess +import urllib import ansible.constants as C import ansible.connection @@ -295,16 +296,26 @@ class Runner(object): args = module_args if type(args) == list: - args = " ".join([ str(x) for x in module_args ]) - + if remote_module_path.endswith('setup'): + # briefly converting arguments to strings before file transfer + # causes some translation errors. This is a workaround only + # needed for the setup module + args = " ".join([ "\"%s\"" % str(x) for x in module_args ]) + else: + args = " ".join([ str(x) for x in module_args ]) + # by default the args to substitute in the action line are those from the setup cache inject_vars = self.setup_cache.get(conn.host,{}) # see if we really need to run this or not... - conditional = utils.template(self.conditionally_execute_if, inject_vars) - if not eval(conditional): - return utils.smjson(dict(skipped=True)) + # doubly templated so we can store a conditional expression in a variable! + conditional = utils.template( + utils.template(self.conditionally_execute_if, inject_vars), + inject_vars + ) + if not eval(conditional): + return [ utils.smjson(dict(skipped=True)), 'skipped' ] # if the host file was an external script, execute it with the hostname # as a first parameter to get the variables to use for the host @@ -333,7 +344,7 @@ class Runner(object): if not k.startswith('facter_') and not k.startswith('ohai_'): if str(v).find(" ") != -1: v = "\"%s\"" % v - args += " %s=%s" % (k, v) + args += " %s=%s" % (k, str(v).replace(" ","~~~")) # the metadata location for the setup module is transparently managed # since it's an 'internals' module, kind of a black box. See playbook diff --git a/library/setup b/library/setup index 6ab82f1a9d0..a2b90b7400d 100755 --- a/library/setup +++ b/library/setup @@ -33,12 +33,18 @@ except ImportError: if len(sys.argv) == 1: sys.exit(1) + argfile = sys.argv[1] if not os.path.exists(argfile): sys.exit(1) + input_data = shlex.split(open(argfile, 'r').read()) -new_options = dict([ x.split('=') for x in input_data ]) +# turn urlencoded k=v string (space delimited) to regular k=v directionary +splitted = [x.split('=',1) for x in input_data ] +splitted = [ (x[0], x[1].replace("~~~"," ")) for x in splitted ] +new_options = dict(splitted) + ansible_file = new_options.get('metadata', DEFAULT_ANSIBLE_SETUP) ansible_dir = os.path.dirname(ansible_file) diff --git a/test/playbook1.events b/test/playbook1.events index a4385a7d8fd..993b069d813 100644 --- a/test/playbook1.events +++ b/test/playbook1.events @@ -263,4 +263,3 @@ } } } -