From e5f62f20b13d0d22d92e431b20733d8829e6a662 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Sun, 26 Feb 2012 19:21:44 -0500 Subject: [PATCH] make copy & template module take key/value parameters so we're consistent. Only the command module works differently now starter manpage for modules allow template file location to be passed into template & setup modules --- docs/man/man5/ansible-modules.1.asciidoc | 14 ++++++------- examples/playbook.yml | 16 ++++++++++----- lib/ansible/constants.py | 1 + lib/ansible/runner.py | 20 ++++++++++++++----- library/copy | 25 ++++++++++++++++++------ library/setup | 19 +++++++++--------- library/template | 19 +++++++++++++++--- 7 files changed, 79 insertions(+), 35 deletions(-) diff --git a/docs/man/man5/ansible-modules.1.asciidoc b/docs/man/man5/ansible-modules.1.asciidoc index 26d9fa9968..e4ae511768 100644 --- a/docs/man/man5/ansible-modules.1.asciidoc +++ b/docs/man/man5/ansible-modules.1.asciidoc @@ -40,8 +40,9 @@ This module does not support change hooks. Returns the return code from the program as well as timing information. -Async command running and command execution time limits are in plan. - +Async command running and command execution time limits are in plan. These will probably +be special keyvalue parameters expressed on the end of the command line, like ANSTIMEOUT=1 +and ANS_ASYNC=1 or similar. copy ---- @@ -128,10 +129,8 @@ first step in your playbook. *metadata=*:: Optionally overrides the default JSON file location of /etc/ansible/setup. -If used, also supply the metadata parameter to 'template'. - - -Does not support change hooks yet, but in plan. +If used, also supply the metadata parameter to 'template'. Change if +running as a non-root remote user who does not have permissions on /etc/ansible. template @@ -152,7 +151,8 @@ location to render the template on the remote server *metadata*:: location of a JSON file to use to supply template data. Default is /etc/ansible/setup -which can be easily created using the 'setup' module. +which is the same as the default for the setup module. Change if running as a non-root +remote user who does not have permissions on /etc/ansible. This module also returns md5sum information about the resultant file. diff --git a/examples/playbook.yml b/examples/playbook.yml index 9f102a9b5e..e9b6d9b795 100644 --- a/examples/playbook.yml +++ b/examples/playbook.yml @@ -2,21 +2,27 @@ hosts: '/etc/ansible/hosts' tasks: - do: - - configure template & module variables + - configure template & module variables for future template calls - setup a=2 b=3 c=4 - do: - - copy a file - - copy /srv/a /srv/b + - copy a file from the local disk to the remote + - copy src=/srv/a dest=/srv/b notify: - restart apache - do: - template from local file template.j2 to remote location /srv/file.out - - template /srv/template.j2 /srv/file.out + - template src=/srv/template.j2 dest=/srv/file.out notify: - restart apache - quack like a duck - do: - - something that will fail + - if running as non-root whne you template, you should specify the MD file (1) + - setup a=3 b=4 c=5 metadata=/tmp/metadata.json + - do: + - if running as non-root when you template, you should specify the MD file (2) + - template src=/srv/template.j2 dest=/srv/file2.out metadata=/tmp/metadata.json + - do: + - call something that will fail just to demo failure counts and such - command /bin/false handlers: - do: diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 15ad18de6b..0b759b0eb6 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -1,3 +1,4 @@ +# control side (aka 'overlord') DEFAULT_HOST_LIST = '/etc/ansible/hosts' DEFAULT_MODULE_PATH = '/usr/share/ansible' DEFAULT_MODULE_NAME = 'ping' diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index 414a8c6600..8c4f755245 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -139,12 +139,21 @@ class Runner(object): result = self._execute_module(conn, module) return self._return_from_module(conn, host, result) + def _parse_kv(self, args): + options = {} + for x in args: + if x.find("=") != -1: + k, v = x.split("=") + options[k]=v + return options + def _execute_copy(self, conn, host): ''' handler for file transfer operations ''' # transfer the file to a remote tmp location - source = self.module_args[0] - dest = self.module_args[1] + options = self._parse_kv(self.module_args) + source = options['src'] + dest = options['dest'] tmp_dest = self._get_tmp_path(conn, dest.split("/")[-1]) self._transfer_file(conn, source, tmp_dest) @@ -161,9 +170,10 @@ class Runner(object): def _execute_template(self, conn, host): ''' handler for template operations ''' - source = self.module_args[0] - dest = self.module_args[1] - metadata = '/etc/ansible/setup' + options = self._parse_kv(self.module_args) + source = options['src'] + dest = options['dest'] + metadata = options.get('metadata', '/etc/ansible/setup') # first copy the source template over tempname = os.path.split(source)[-1] diff --git a/library/copy b/library/copy index aa944924ef..95b70ee1a4 100644 --- a/library/copy +++ b/library/copy @@ -8,14 +8,27 @@ try: except ImportError: import simplejson as json -source = sys.argv[1] -dest = sys.argv[2] +# =========================================== +# convert arguments of form ensure=running name=foo +# to a dictionary +# FIXME: make more idiomatic + +args = " ".join(sys.argv[1:]) +items = shlex.split(args) +params = {} +for x in items: + (k, v) = x.split("=") + params[k] = v + +src = params['src'] +dest = params['dest'] + -# raise an error if there is no source file -if not os.path.exists(source): +# raise an error if there is no src file +if not os.path.exists(src): print json.dumps({ "failed" : 1, - "msg" : "Source %s failed to transfer" % source + "msg" : "Source %s failed to transfer" % src }) sys.exit(1) @@ -24,7 +37,7 @@ changed = False if os.path.exists(dest): md5sum = os.popen("md5sum %s" % dest).read().split()[0] -os.system("cp %s %s" % (source, dest)) +os.system("cp %s %s" % (src, dest)) md5sum2 = os.popen("md5sum %s" % dest).read().split()[0] diff --git a/library/setup b/library/setup index de52cba709..5e9fccbf35 100755 --- a/library/setup +++ b/library/setup @@ -1,7 +1,6 @@ #!/usr/bin/python -ANSIBLE_DIR = "/etc/ansible" -ANSIBLE_SETUP = "/etc/ansible/setup" +DEFAULT_ANSIBLE_SETUP = "/etc/ansible/setup" import sys import os @@ -15,28 +14,30 @@ except ImportError: # load config & template variables input_data = sys.argv[1:] -new_options = dict([ x.split("=") for x in input_data ]) +new_options = dict([ x.split('=') for x in input_data ]) +ansible_file = new_options.get('metadata', DEFAULT_ANSIBLE_SETUP) +ansible_dir = os.path.dirname(metadata) # create the config dir if it doesn't exist -if not os.path.exists(ANSIBLE_DIR): - os.makedirs(ANSIBLE_DIR) +if not os.path.exists(ansible_dir): + os.makedirs(ansible_dir) changed = False -if not os.path.exists(ANSIBLE_SETUP): +if not os.path.exists(ansible_file): changed = True else: - md5sum = os.popen("md5sum %s" % ANSIBLE_SETUP).read() + md5sum = os.popen("md5sum %s" % ansible_file).read() # write the template/settings file using # instructions from server -f = open(ANSIBLE_SETUP, "w+") +f = open(ansible_file, "w+") reformat = json.dumps(new_options) f.write(reformat) f.close() -md5sum2 = os.popen("md5sum %s" % ANSIBLE_SETUP).read() +md5sum2 = os.popen("md5sum %s" % ansible_file).read() if md5sum != md5sum2: changed = True diff --git a/library/template b/library/template index 3bbcbdfcc3..d77c5cef92 100644 --- a/library/template +++ b/library/template @@ -8,9 +8,22 @@ try: except ImportError: import simplejson as json -source = sys.argv[1] -dest = sys.argv[2] -metadata = sys.argv[3] +# =========================================== +# convert arguments of form ensure=running name=foo +# to a dictionary +# FIXME: make more idiomatic + +args = " ".join(sys.argv[1:]) +items = shlex.split(args) +params = {} +for x in items: + (k, v) = x.split("=") + params[k] = v + +source = params['src'] +dest = params['dest'] +metadata = params.get('metadata', '/etc/ansible/setup') + # raise an error if there is no template metadata if not os.path.exists(metadata):