From 788e11f1db42fb4f21b3342822fbb5b498596e42 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Fri, 5 Oct 2012 14:31:13 -0700 Subject: [PATCH 1/5] Merge commits from copperlight's branch ansible-pull_playbook_parameter branch Merged commits: 3cd25b5 and ed9fc76. Some massaging of changes applied. --- bin/ansible-pull | 98 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/bin/ansible-pull b/bin/ansible-pull index f139c4e099..6268bf0d02 100755 --- a/bin/ansible-pull +++ b/bin/ansible-pull @@ -1,15 +1,5 @@ #!/usr/bin/env python -# ansible-pull is a script that runs ansible in local mode -# after checking out a playbooks directory from git. There is an -# example playbook to bootstrap this script in the examples/ dir which -# installs ansible and sets it up to run on cron. -# -# usage: -# ansible-pull -d /var/ansible/local -U http://wherever/content.git -C production -# -# the git repo must contain a playbook named 'local.yml' - # (c) 2012, Stephen Fromm # # Ansible is free software: you can redistribute it and/or modify @@ -24,10 +14,33 @@ # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . +# ansible-pull is a script that runs ansible in local mode +# after checking out a playbooks directory from git. There is an +# example playbook to bootstrap this script in the examples/ dir which +# installs ansible and sets it up to run on cron. + +# usage: +# ansible-pull -d /var/lib/ansible \ +# -U http://example.net/content.git [-C production] \ +# [path/playbook.yml] +# +# the -d and -U arguments are required; the -C argument is optional. +# +# ansible-pull accepts an optional argument to specify a playbook +# location underneath the workdir and then searches the git repo +# for playbooks in the following order, stopping at the first match: +# +# 1. $workdir/path/playbook.yml, if specified +# 2. $workdir/$hostname.yml +# 3. $workdir/local.yml +# +# the git repo must contain at least one of these playbooks. import os import subprocess import sys +import datetime +import platform from optparse import OptionParser DEFAULT_PLAYBOOK = 'local.yml' @@ -43,27 +56,78 @@ def _run(cmd): def main(args): """ Set up and run a local playbook """ - usage = "%prog [options]" - parser = OptionParser() + usage = "%prog [options] [path/playbook.yml]" + parser = OptionParser(usage=usage) parser.add_option('-d', '--directory', dest='dest', default=None, - help='Directory to checkout git repository') - parser.add_option('-U', '--url', dest='url', - default=None, + help='Directory to checkout git repository to') + parser.add_option('-U', '--url', dest='url', default=None, help='URL of git repository') parser.add_option('-C', '--checkout', dest='checkout', default="HEAD", help='Branch/Tag/Commit to checkout. Defaults to HEAD.') options, args = parser.parse_args(args) + if not options.dest: + parser.error("Missing required directory argument") + return 1 + + if not options.url: + parser.error("URL for git repo not specified, use -h for help") + return 1 + + now = datetime.datetime.now() + print now.strftime("ansible-pull_started: %Y%m%d-%H%M-%S"), "\n" + + hostname = "%s.yml" % platform.node() + + if not args: + try: + with open('%s/%s' % (options.dest, hostname)) as f: pass + playbook = hostname + print 'using playbook %s/%s' % (options.dest, hostname) + except IOError as e: + print 'playbook %s/%s does not exist, falling back to %s' % (options.dest, hostname, DEFAULT_PLAYBOOK) + try: + with open('%s/%s' % (options.dest, DEFAULT_PLAYBOOK)) as f: pass + playbook = DEFAULT_PLAYBOOK + print 'using playbook %s/%s' % (options.dest, DEFAULT_PLAYBOOK) + except IOError as e: + print 'playbook %s/%s does not exist, no playbooks to run; use -h for help' % (options.dest, DEFAULT_PLAYBOOK) + return 1 + else: + try: + with open('%s/%s' % (options.dest, args[0])) as f: pass + playbook = args[0] + print 'using playbook %s/%s' % (options.dest, args[0]) + except IOError as e: + print 'playbook %s/%s does not exist, falling back to %s' % (options.dest, args[0], hostname) + try: + with open('%s/%s' % (options.dest, hostname)) as f: pass + playbook = hostname + print 'using playbook %s/%s' % (options.dest, hostname) + except IOError as e: + print 'playbook %s/%s does not exist, falling back to %s' % (options.dest, hostname, DEFAULT_PLAYBOOK) + try: + with open('%s/%s' % (options.dest, DEFAULT_PLAYBOOK)) as f: pass + playbook = DEFAULT_PLAYBOOK + print 'using playbook %s/%s' % (options.dest, DEFAULT_PLAYBOOK) + except IOError as e: + print 'playbook %s/%s does not exist, no playbooks to run; use -h for help' % (options.dest, DEFAULT_PLAYBOOK) + return 1 + + print + git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout) cmd = 'ansible all -c local -m git -a "%s"' % git_opts - print "cmd=%s" % cmd + print "cmd=%s" % cmd, "\n" rc = _run(cmd) if rc != 0: return rc + + cmd = 'ansible-playbook -c local %s' % playbook + print "cmd=%s" % cmd os.chdir(options.dest) - cmd = 'ansible-playbook -c local %s' % DEFAULT_PLAYBOOK rc = _run(cmd) return rc From 2b24131baad53123513779c92f1e238273bcd955 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Wed, 12 Sep 2012 20:07:02 -0400 Subject: [PATCH 2/5] fetch the git repo before trying to find a playbook --- bin/ansible-pull | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bin/ansible-pull b/bin/ansible-pull index 6268bf0d02..284139f043 100755 --- a/bin/ansible-pull +++ b/bin/ansible-pull @@ -78,6 +78,13 @@ def main(args): now = datetime.datetime.now() print now.strftime("ansible-pull_started: %Y%m%d-%H%M-%S"), "\n" + git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout) + cmd = 'ansible all -c local -m git -a "%s"' % git_opts + print "cmd=%s" % cmd, "\n" + rc = _run(cmd) + if rc != 0: + return rc + hostname = "%s.yml" % platform.node() if not args: @@ -117,14 +124,6 @@ def main(args): print - git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout) - cmd = 'ansible all -c local -m git -a "%s"' % git_opts - print "cmd=%s" % cmd, "\n" - rc = _run(cmd) - if rc != 0: - return rc - - cmd = 'ansible-playbook -c local %s' % playbook print "cmd=%s" % cmd os.chdir(options.dest) From 0841ed4796fe5db279ae290438ecbc227ce30799 Mon Sep 17 00:00:00 2001 From: Matthew Johnson Date: Thu, 13 Sep 2012 02:42:54 -0400 Subject: [PATCH 3/5] change method of obtaining hostname to match ansible/library/setup --- bin/ansible-pull | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ansible-pull b/bin/ansible-pull index 284139f043..677bf60b02 100755 --- a/bin/ansible-pull +++ b/bin/ansible-pull @@ -40,7 +40,7 @@ import os import subprocess import sys import datetime -import platform +import socket from optparse import OptionParser DEFAULT_PLAYBOOK = 'local.yml' @@ -85,7 +85,7 @@ def main(args): if rc != 0: return rc - hostname = "%s.yml" % platform.node() + hostname = "%s.yml" % socket.getfqdn() if not args: try: From 034e8f59eda6c55f5f801c979e7a5d97a8c17548 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Fri, 12 Oct 2012 07:35:21 -0700 Subject: [PATCH 4/5] Clean up auto-selection of playbook and miscellaneous changes Direct any ansible-pull specific messages to stderr. Introduce try_playbook() and select_playbook() to remove try/except-y. --- bin/ansible-pull | 93 ++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/bin/ansible-pull b/bin/ansible-pull index 677bf60b02..271542050c 100755 --- a/bin/ansible-pull +++ b/bin/ansible-pull @@ -44,22 +44,56 @@ import socket from optparse import OptionParser DEFAULT_PLAYBOOK = 'local.yml' +PLAYBOOK_ERRORS = { 1: 'File does not exist', + 2: 'File is not readable' } def _run(cmd): + print >>sys.stderr, "Running: '%s'" % cmd cmd = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = cmd.communicate() print out if cmd.returncode != 0: - print err + print >>sys.stderr, err return cmd.returncode +def try_playbook(path): + if not os.path.exists(path): + return 1 + if not os.access(path, os.R_OK): + return 2 + return 0 + +def select_playbook(path, args): + playbook = None + if len(args) > 0 and args[0] is not None: + playbook = "%s/%s" % (path, args[0]) + rc = try_playbook(playbook) + if rc != 0: + print >>sys.stderr, "%s: %s" % (playbook, PLAYBOOK_ERRORS[rc]) + return None + return playbook + else: + hostpb = "%s/%s.yml" % (path, socket.getfqdn()) + localpb = "%s/%s" % (path, DEFAULT_PLAYBOOK) + errors = [] + for pb in [hostpb, localpb]: + rc = try_playbook(pb) + if rc == 0: + playbook = pb + break + else: + errors.append("%s: %s" % (pb, PLAYBOOK_ERRORS[rc])) + if playbook is None: + print >>sys.stderr, "\n".join(errors) + return playbook + def main(args): """ Set up and run a local playbook """ - usage = "%prog [options] [path/playbook.yml]" + usage = "%prog [options] [playbook.yml]" parser = OptionParser(usage=usage) parser.add_option('-d', '--directory', dest='dest', default=None, - help='Directory to checkout git repository to') + help='Directory to clone git repository to') parser.add_option('-U', '--url', dest='url', default=None, help='URL of git repository') parser.add_option('-C', '--checkout', dest='checkout', @@ -68,64 +102,29 @@ def main(args): options, args = parser.parse_args(args) if not options.dest: - parser.error("Missing required directory argument") - return 1 + parser.error("Missing required directory argument") + return 1 if not options.url: - parser.error("URL for git repo not specified, use -h for help") - return 1 + parser.error("URL for git repo not specified, use -h for help") + return 1 now = datetime.datetime.now() - print now.strftime("ansible-pull_started: %Y%m%d-%H%M-%S"), "\n" + print >>sys.stderr, now.strftime("Starting ansible-pull at %F %T") git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout) cmd = 'ansible all -c local -m git -a "%s"' % git_opts - print "cmd=%s" % cmd, "\n" rc = _run(cmd) if rc != 0: return rc - hostname = "%s.yml" % socket.getfqdn() + playbook = select_playbook(options.dest, args) - if not args: - try: - with open('%s/%s' % (options.dest, hostname)) as f: pass - playbook = hostname - print 'using playbook %s/%s' % (options.dest, hostname) - except IOError as e: - print 'playbook %s/%s does not exist, falling back to %s' % (options.dest, hostname, DEFAULT_PLAYBOOK) - try: - with open('%s/%s' % (options.dest, DEFAULT_PLAYBOOK)) as f: pass - playbook = DEFAULT_PLAYBOOK - print 'using playbook %s/%s' % (options.dest, DEFAULT_PLAYBOOK) - except IOError as e: - print 'playbook %s/%s does not exist, no playbooks to run; use -h for help' % (options.dest, DEFAULT_PLAYBOOK) - return 1 - else: - try: - with open('%s/%s' % (options.dest, args[0])) as f: pass - playbook = args[0] - print 'using playbook %s/%s' % (options.dest, args[0]) - except IOError as e: - print 'playbook %s/%s does not exist, falling back to %s' % (options.dest, args[0], hostname) - try: - with open('%s/%s' % (options.dest, hostname)) as f: pass - playbook = hostname - print 'using playbook %s/%s' % (options.dest, hostname) - except IOError as e: - print 'playbook %s/%s does not exist, falling back to %s' % (options.dest, hostname, DEFAULT_PLAYBOOK) - try: - with open('%s/%s' % (options.dest, DEFAULT_PLAYBOOK)) as f: pass - playbook = DEFAULT_PLAYBOOK - print 'using playbook %s/%s' % (options.dest, DEFAULT_PLAYBOOK) - except IOError as e: - print 'playbook %s/%s does not exist, no playbooks to run; use -h for help' % (options.dest, DEFAULT_PLAYBOOK) - return 1 - - print + if playbook is None: + print >>sys.stderr, "Could not find a playbook to run." + return 1 cmd = 'ansible-playbook -c local %s' % playbook - print "cmd=%s" % cmd os.chdir(options.dest) rc = _run(cmd) return rc From 60d3e9f3de7b4dd985f0659810c6a81310a60a06 Mon Sep 17 00:00:00 2001 From: Stephen Fromm Date: Fri, 12 Oct 2012 07:53:56 -0700 Subject: [PATCH 5/5] Add --purge option to ansible-pull Removes git checkout after playbook run. --- bin/ansible-pull | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/ansible-pull b/bin/ansible-pull index 271542050c..7863d3b695 100755 --- a/bin/ansible-pull +++ b/bin/ansible-pull @@ -37,6 +37,7 @@ # the git repo must contain at least one of these playbooks. import os +import shutil import subprocess import sys import datetime @@ -92,6 +93,8 @@ def main(args): """ Set up and run a local playbook """ usage = "%prog [options] [playbook.yml]" parser = OptionParser(usage=usage) + parser.add_option('--purge', default=False, action='store_true', + help='Purge git checkout after playbook run') parser.add_option('-d', '--directory', dest='dest', default=None, help='Directory to clone git repository to') parser.add_option('-U', '--url', dest='url', default=None, @@ -127,6 +130,14 @@ def main(args): cmd = 'ansible-playbook -c local %s' % playbook os.chdir(options.dest) rc = _run(cmd) + + if options.purge: + os.chdir('/') + try: + shutil.rmtree(options.dest) + except Exception, e: + print >>sys.stderr, "Failed to remove %s: %s" % (options.dest, str(e)) + return rc if __name__ == '__main__':