diff --git a/lib/ansible/playbook.py b/lib/ansible/playbook.py index 0eb0e4d685..c75d27213f 100755 --- a/lib/ansible/playbook.py +++ b/lib/ansible/playbook.py @@ -436,24 +436,17 @@ class PlayBook(object): else: self.callbacks.on_setup_primary() - # first run the setup task on every node, which gets the variables - # written to the JSON file and will also bubble facts back up via - # magic in Runner() - push_var_str='' - for (k,v) in vars.iteritems(): - push_var_str += "%s=\"%s\" " % (k,v) - host_list = [ h for h in self.host_list if not (h in self.stats.failures or h in self.stats.dark) ] # push any variables down to the system setup_results = ansible.runner.Runner( pattern=pattern, groups=self.groups, module_name='setup', - module_args=push_var_str, host_list=host_list, + module_args=vars, host_list=host_list, forks=self.forks, module_path=self.module_path, timeout=self.timeout, remote_user=user, remote_pass=self.remote_pass, remote_port=self.remote_port, setup_cache=SETUP_CACHE, - callbacks=self.runner_callbacks, sudo=sudo, + callbacks=self.runner_callbacks, sudo=sudo, debug=self.debug, ).run() self.stats.compute(setup_results, setup=True) diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index b2cf3518b9..ad7574452b 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -113,8 +113,8 @@ class Runner(object): self.basedir = basedir self.sudo = sudo - if type(self.module_args) != str: - raise Exception("module_args must be a string: %s" % self.module_args) + if type(self.module_args) != str and type(self.module_args) != dict: + raise Exception("module_args must be a string or dict: %s" % self.module_args) self._tmp_paths = {} random.seed() @@ -271,6 +271,9 @@ class Runner(object): def _transfer_str(self, conn, tmp, name, args_str): ''' transfer arguments as a single file to be fed to the module. ''' + if type(args_str) == dict: + args_str = utils.smjson(args_str) + args_fd, args_file = tempfile.mkstemp() args_fo = os.fdopen(args_fd, 'w') args_fo.write(args_str) @@ -316,23 +319,43 @@ class Runner(object): def _add_setup_vars(self, inject, args): ''' setup module variables need special handling ''' + is_dict = False + if type(args) == dict: + is_dict = True + + # TODO: keep this as a dict through the whole path to simplify this code for (k,v) in inject.iteritems(): if not k.startswith('facter_') and not k.startswith('ohai_'): - if str(v).find(" ") != -1: - v = "\"%s\"" % v - args += " %s=%s" % (k, str(v).replace(" ","~~~")) + if not is_dict: + if str(v).find(" ") != -1: + v = "\"%s\"" % v + args += " %s=%s" % (k, str(v).replace(" ","~~~")) + else: + args[k]=v return args # ***************************************************** def _add_setup_metadata(self, args): ''' automatically determine where to store variables for the setup module ''' + + is_dict = False + if type(args) == dict: + is_dict = True - if args.find("metadata=") == -1: - if self.remote_user == 'root': - args = "%s metadata=/etc/ansible/setup" % args - else: - args = "%s metadata=/home/%s/.ansible/setup" % (args, self.remote_user) + # TODO: keep this as a dict through the whole path to simplify this code + if not is_dict: + if args.find("metadata=") == -1: + if self.remote_user == 'root': + args = "%s metadata=/etc/ansible/setup" % args + else: + args = "%s metadata=/home/%s/.ansible/setup" % (args, self.remote_user) + else: + if not 'metadata' in args: + if self.remote_user == 'root': + args['metadata'] = '/etc/ansible/setup' + else: + args['metadata'] = "/home/%s/.ansible/setup" % (self.remote_user) return args # ***************************************************** @@ -352,9 +375,11 @@ class Runner(object): args = self._add_setup_vars(inject, args) args = self._add_setup_metadata(args) + if type(args) == dict: + args = utils.bigjson(args) args = utils.template(args, inject) + module_name_tail = remote_module_path.split("/")[-1] - client_executed_str = "%s %s" % (module_name_tail, args.strip()) argsfile = self._transfer_str(conn, tmp, 'arguments', args) if async_jid is None: @@ -368,6 +393,7 @@ class Runner(object): res, err = self._exec_command(conn, cmd, tmp, sudoable=True) + client_executed_str = "%s %s" % (module_name_tail, args.strip()) return ( res, err, client_executed_str ) # ***************************************************** diff --git a/library/setup b/library/setup index a2b90b7400..6efb5e973c 100755 --- a/library/setup +++ b/library/setup @@ -23,6 +23,7 @@ import sys import os import shlex import subprocess +import traceback try: import json @@ -34,18 +35,22 @@ 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()) +setup_options = open(argfile).read().strip() +try: + setup_options = json.loads(setup_options) +except: + list_options = shlex.split(setup_options) + setup_options = {} + for opt in list_options: + (k,v) = opt.split("=") + setup_options[k]=v -# 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_file = setup_options.get('metadata', DEFAULT_ANSIBLE_SETUP) ansible_dir = os.path.dirname(ansible_file) # create the config dir if it doesn't exist @@ -74,7 +79,7 @@ if os.path.exists("/usr/bin/facter"): facter = False if facter: for (k,v) in facter_ds.items(): - new_options["facter_%s" % k] = v + setup_options["facter_%s" % k] = v # ditto for ohai, but just top level string keys # because it contains a lot of nested stuff we can't use for @@ -93,13 +98,13 @@ if os.path.exists("/usr/bin/ohai"): for (k,v) in ohai_ds.items(): if type(v) == str or type(v) == unicode: k2 = "ohai_%s" % k - new_options[k2] = v + setup_options[k2] = v # write the template/settings file using # instructions from server f = open(ansible_file, "w+") -reformat = json.dumps(new_options, sort_keys=True, indent=4) +reformat = json.dumps(setup_options, sort_keys=True, indent=4) f.write(reformat) f.close() @@ -108,9 +113,9 @@ md5sum2 = os.popen("md5sum %s" % ansible_file).read().split()[0] if md5sum != md5sum2: changed = True -new_options['written'] = ansible_file -new_options['changed'] = changed -new_options['md5sum'] = md5sum2 +setup_options['written'] = ansible_file +setup_options['changed'] = changed +setup_options['md5sum'] = md5sum2 -print json.dumps(new_options) +print json.dumps(setup_options) diff --git a/test/playbook1.events b/test/playbook1.events index b8ab78e634..e5e9cd489b 100644 --- a/test/playbook1.events +++ b/test/playbook1.events @@ -15,7 +15,7 @@ "answer": "Wuh, I think so, Brain, but if we didn't have ears, we'd look like weasels.", "changed": true, "metadata": "/etc/ansible/setup", - "port": "5150", + "port": 5150, "written": "/etc/ansible/setup" } ] @@ -44,7 +44,7 @@ "cow": "moo", "duck": "quack", "metadata": "/etc/ansible/setup", - "port": "5150", + "port": 5150, "testing": "default", "written": "/etc/ansible/setup" } @@ -228,6 +228,21 @@ "127.0.0.2" ] ], + [ + "ok", + [ + "127.0.0.2", + { + "started": 1 + } + ] + ], + [ + "async poll", + [ + "127.0.0.2" + ] + ], [ "ok", [