Skip to content
This repository has been archived by the owner on Dec 28, 2024. It is now read-only.

Commit

Permalink
updates for ansible 1.5 compatibility; update --version option
Browse files Browse the repository at this point in the history
  • Loading branch information
spencergibb committed Mar 11, 2014
1 parent 14e083c commit 441c30b
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 35 deletions.
15 changes: 12 additions & 3 deletions bin/battle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import os
import sys
import subprocess

import ansible.constants as AC
import battleschool.constants as C
Expand All @@ -16,6 +15,7 @@ from ansible import callbacks
from ansible import errors
from ansible import utils

from battleschool.__init__ import __version__
from battleschool.printing import *
from battleschool.source.git import Git
from battleschool.source.local import Local
Expand Down Expand Up @@ -91,6 +91,7 @@ def main(args):
diff_opts=True,
output_opts=True
)
parser.version = "%s %s" % ("battleschool", __version__)
parser.add_option('-e', '--extra-vars', dest="extra_vars", default=None,
help="set additional key=value variables from the CLI")
parser.add_option('--tags', dest='tags', default='all',
Expand All @@ -111,8 +112,9 @@ def main(args):
help="update playbooks from sources(git, url, etc...)")

options, args = parser.parse_args(args)
# options.connection = 'local'

playbooks_to_run = [C.DEFAULT_PLAYBOOK]
playbooks_to_run = []#[C.DEFAULT_PLAYBOOK]

#-----------------------------------------------------------
# setup inventory
Expand All @@ -129,7 +131,9 @@ def main(args):
if not options.listhosts and not options.syntax and not options.listtasks:
options.ask_pass = AC.DEFAULT_ASK_PASS
options.ask_sudo_pass = options.ask_sudo_pass or AC.DEFAULT_ASK_SUDO_PASS
( sshpass, sudopass ) = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass)
passwds = utils.ask_passwords(ask_pass=options.ask_pass, ask_sudo_pass=options.ask_sudo_pass)
sshpass = passwds[0]
sudopass = passwds[1]
# if options.sudo_user or options.ask_sudo_pass:
# options.sudo = True
options.sudo_user = AC.DEFAULT_SUDO_USER
Expand Down Expand Up @@ -169,6 +173,8 @@ def main(args):
else:
options.cache_dir = "%s/cache" % battleschool_dir

os.environ["BATTLESCHOOL_CACHE_DIR"] = options.cache_dir

#-----------------------------------------------------------
# setup extra_vars for later use
if extra_vars is None:
Expand Down Expand Up @@ -216,6 +222,9 @@ def main(args):

runner_cb = BattleschoolRunnerCallbacks()
playbook_cb = BattleschoolCallbacks()
#TODO: option to use default callbacks
# runner_cb = callbacks.PlaybookRunnerCallbacks(stats, verbose=utils.VERBOSITY)
# playbook_cb = callbacks.PlaybookCallbacks(verbose=utils.VERBOSITY)

if options.step:
playbook_cb.step = options.step
Expand Down
2 changes: 1 addition & 1 deletion lib/battleschool/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = '0.2.2'
__version__ = '0.3.0'
__author__ = 'Spencer Gibb'
17 changes: 11 additions & 6 deletions lib/battleschool/printing.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,14 @@ def banner(msg):
class BattleschoolRunnerCallbacks(DefaultRunnerCallbacks):
""" callbacks for use by battles """

def get_play(self):
if self.task:
return self.task
return self.play

def on_failed(self, host, res, ignore_errors=False):
if not ignore_errors:
display("\tTask FAILED: %s %s" % (self.task.name, res['msg']), color="red")
display("\tTask FAILED: %s %s" % (self.get_play().name, res['msg']), color="red")
super(BattleschoolRunnerCallbacks, self).on_failed(host, res, ignore_errors=ignore_errors)

def on_ok(self, host, res):
Expand All @@ -86,8 +91,8 @@ def on_ok(self, host, res):
msg = ''

try:
if self.task:
display("\tTask OK: %s%s" % (self.task.name, msg))
if self.get_play():
display("\tTask OK: %s%s" % (self.get_play().name, msg))
except AttributeError:
invocation = res['invocation']
msg = invocation['module_args']
Expand Down Expand Up @@ -117,15 +122,15 @@ def on_unreachable(self, host, results):
super(BattleschoolRunnerCallbacks, self).on_unreachable(host, results)

def on_skipped(self, host, item=None):
display("\tTask skipped: %s" % self.task.name, color="yellow")
display("\tTask skipped: %s" % self.get_play().name, color="yellow")
super(BattleschoolRunnerCallbacks, self).on_skipped(host, item)

def on_error(self, host, err):
display("\tTask ERROR: %s%s" % (self.task.name, err), color="red")
display("\tTask ERROR: %s%s" % (self.get_play().name, err), color="red")
super(BattleschoolRunnerCallbacks, self).on_error(host, err)

def on_no_hosts(self):
display("\tTask NO HOSTS: %s" % self.task.name, color="red")
display("\tTask NO HOSTS: %s" % self.get_play().name, color="red")
super(BattleschoolRunnerCallbacks, self).on_no_hosts()

def on_async_poll(self, host, res, jid, clock):
Expand Down
3 changes: 0 additions & 3 deletions share/defaults/battleschool.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@
tasks:
- name: print from playbook
debug: msg="in battleschool.yml"

#- include: {{item}}
# with_items: playbooks
118 changes: 96 additions & 22 deletions share/library/mac_pkg
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,65 @@ import abc
import hashlib
import os
import shutil
import subprocess
import tempfile
import traceback

from os import path


def run_command(module, args, check_rc=False, close_fds=False, executable=None, data=None, cwd=None):
'''
Execute a command, returns rc, stdout, and stderr.
args is the command to run
If args is a list, the command will be run with shell=False.
Otherwise, the command will be run with shell=True when args is a string.
Other arguments:
- check_rc (boolean) Whether to call fail_json in case of
non zero RC. Default is False.
- close_fds (boolean) See documentation for subprocess.Popen().
Default is False.
- executable (string) See documentation for subprocess.Popen().
Default is None.
- cwd (string) See documentation for subprocess.Popen().
Default is None.
'''
if isinstance(args, list):
shell = False
elif isinstance(args, basestring):
shell = True
else:
msg = "Argument 'args' to run_command must be list or string"
module.fail_json(rc=257, cmd=args, msg=msg)
rc = 0
msg = None
st_in = None
if data:
st_in = subprocess.PIPE
try:
cmd = subprocess.Popen(args,
executable=executable,
shell=shell,
close_fds=close_fds,
stdin=st_in,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=cwd)
if data:
cmd.stdin.write(data)
cmd.stdin.write('\n')
out, err = cmd.communicate()
rc = cmd.returncode
except (OSError, IOError), e:
module.fail_json(rc=e.errno, msg=str(e), cmd=args)
except:
module.fail_json(rc=257, msg=traceback.format_exc(), cmd=args)
if rc != 0 and check_rc:
msg = err.rstrip()
module.fail_json(cmd=args, rc=rc, stdout=out, stderr=err, msg=msg)
return rc, out, err


class Archive(object):

__metaclass__ = abc.ABCMeta
Expand All @@ -42,6 +96,7 @@ class Archive(object):
self.curl_path = module.get_bin_path('curl', True, ['/usr/bin'])
self.chown_path = module.get_bin_path('chown', True)
self.pkg = pkg
self._pkg_path = None
return

@abc.abstractmethod
Expand All @@ -62,6 +117,12 @@ class Archive(object):
return self.params['url']


def chown_dir(self, chown_user, target_path):
if chown_user is not None:
rc, out, err = self.module.run_command("%s -R %s %s" % (self.chown_path, chown_user, target_path))
if rc > 0:
self.module.fail_json(msg="failed to install %s: %s\n\t%s" % (self.pkg.name(), out, err))

def acquire(self):
acquired = False
if exists(self.params, 'src'):
Expand All @@ -83,35 +144,40 @@ class Archive(object):
if exists(self.params, 'curl_opts'):
curl_opts = self.params['curl_opts']

#TODO: use environment variable to override cachedir
download_dir = path.expanduser("~/.battleschool/cache/downloads")
if not path.exists(download_dir):
os.makedirs(download_dir)

#TODO: make chown optional?
if exists(os.environ, 'SUDO_USER'):
chown_user = os.environ['SUDO_USER']
else:
chown_user = None
# self.module.exit_json(changed=False, msg="chown_user %s" % chown_user)

#TODO: use environment variable to override cachedir
download_dir = path.expanduser("~/.battleschool/cache/downloads")
if not path.exists(download_dir):
os.makedirs(download_dir)
#TODO: only chown downloaded item, only chown if just downloaded
self.chown_dir(chown_user, download_dir)
# self.module.exit_json(changed=False, msg="download_dir %s" % download_dir)
# self.module.exit_json(changed=False, msg="BATTLESCHOOL_CACHE_DIR %s" % os.environ.get('BATTLESCHOOL_CACHE_DIR', ""))

#TODO: verify write perms of dest parent
if exists(self.params, 'dest'):
dest = self.params['dest']

if not path.isabs(dest):
dest = "%s/%s" % (download_dir, dest)

pre_cmd = ""
cwd = None
output_opts = "--output %s" % dest
do_download = not path.exists(dest)
else:
sha1 = hashlib.sha1(url).hexdigest()
dest = "%s/%s" % (download_dir, sha1)
if not path.exists(dest):
os.makedirs(dest)
self.chown_dir(chown_user, dest)
do_download = not os.listdir(dest)
pre_cmd = "cd %s && " % dest
cwd = dest
output_opts = "--remote-name --remote-header-name"

# self.module.exit_json(changed=False, msg="pre_cmd %s, output_opts %s, curl_opts %s, do_download %s"
Expand All @@ -129,29 +195,30 @@ class Archive(object):
os.unlink(file_path)

if do_download:
rc, out, err = self.module.run_command("%s %s --insecure --silent --location %s %s %s" %
(pre_cmd, self.curl_path, output_opts, curl_opts, url))
download_cmd = "%s --insecure --silent --location %s %s %s" % (
self.curl_path, output_opts, curl_opts, url)
# self.module.exit_json(changed=False, msg="download_cmd %s" % download_cmd)
rc, out, err = run_command(self.module, download_cmd, cwd=cwd)
if rc > 0:
self.module.fail_json(msg="failed to install %s: %s\n\t%s" % (self.pkg.name(), out, err))
acquired = True

if not exists(self.params, 'dest'):
# need to find out the path of the downloaded file
files = os.listdir(dest)
# self.module.exit_json(changed=False, msg="files %s" % files)
num_files = len(files)

if num_files != 1:
self.module.fail_json(msg="failed to locate download for %s: %s file(s) found in %s"
% (self.pkg.name(), num_files, dest))

dest = "%s/%s" % (dest, files[0])
# self.module.exit_json(changed=False, msg="dest %s" % dest)
# self.module.exit_json(changed=False, msg="dest %s" % dest)

#TODO: only chown downloaded item, only chown if just downloaded
if chown_user is not None:
rc, out, err = self.module.run_command("%s -R %s %s" % (self.chown_path, chown_user, download_dir))
if rc > 0:
self.module.fail_json(msg="failed to install %s: %s\n\t%s" % (self.pkg.name(), out, err))
#TODO: only chown downloaded item
if do_download and acquired:
self.chown_dir(chown_user, download_dir)

self._pkg_path = dest

Expand Down Expand Up @@ -196,8 +263,9 @@ class DmgArchive(Archive):

#if dmg mount and record volume path
#hdiutil attach Vagrant-1.3.0.dmg | grep Volumes | awk '{print $3}'
command = "%s %s attach %s %s " % (hdi_pre, self.hdiutil_path, self._pkg_path, hdi_post)
rc, out, err = self.module.run_command(command)
command = "%s %s attach \"%s\" %s " % (hdi_pre, self.hdiutil_path, self._pkg_path, hdi_post)
# self.module.exit_json(changed=False, msg="hdicmd: %s" % command)
rc, out, err = run_command(self.module, command)
if rc > 0:
self.module.fail_json(msg="failed to install %s: rc: %s, %s, err: %s" % (self.pkg.name(), rc, out, err))

Expand Down Expand Up @@ -256,14 +324,17 @@ class PkgPackage(Package):
self.pkgutil_path = module.get_bin_path('pkgutil', True, ['/usr/sbin'])
#TODO: add creates which would override pkg_version

#find installed version
self._pkg_name = self.params['pkg_name']
rc, out, err = module.run_command("%s --pkg-info=%s 2>&1 |grep version| awk '{print $2}'" %
(self.pkgutil_path, self._pkg_name))
#find installed version
self._version = self.find_version(module)
# self.module.exit_json(changed=False, msg="_version %s, _pkg_name %s" % (self._version, self._pkg_name))

def find_version(self, module):
rc, out, err = run_command(self.module, "%s --pkg-info=%s 2>&1 |grep version| awk '{print $2}'" %
(self.pkgutil_path, self._pkg_name))
if rc > 0:
module.fail_json(msg="failed to install %s: %s %s" % (self._pkg_name, out, err))

self._version = out.strip()
return out.strip()

def install(self, pkg_path):
#install package file
Expand All @@ -273,6 +344,8 @@ class PkgPackage(Package):
if rc > 0:
return out, err

#no error, update the version from pkg_util
self._version = self.find_version(self.module)
return False

def is_installed(self):
Expand Down Expand Up @@ -366,6 +439,7 @@ class Installer(object):

def install(self, acquire_only):
pkg = self._instantiate('pkg_type', 'Package')
# self.module.exit_json(changed=False, msg="params %s" % self.params)

if pkg.is_installed() and not acquire_only:
self.module.exit_json(changed=False, version=pkg.version(), msg="package %s already present" % pkg.name())
Expand Down
8 changes: 8 additions & 0 deletions test/test_pkg_vagrant.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
MODULE_PARAMS="pkg_name=com.vagrant.vagrant"
MODULE_PARAMS="$MODULE_PARAMS pkg_version=1.5.0"
MODULE_PARAMS="$MODULE_PARAMS archive_type=dmg"
MODULE_PARAMS="$MODULE_PARAMS archive_path=Vagrant.pkg"
#MODULE_PARAMS="$MODULE_PARAMS force=true"
MODULE_PARAMS="$MODULE_PARAMS url=https://dl.bintray.com/mitchellh/vagrant/vagrant_1.5.0.dmg"
#echo $MODULE_PARAMS
~/workspace/32degrees/ansible/hacking/test-module -m share/library/mac_pkg -a "$MODULE_PARAMS"

0 comments on commit 441c30b

Please sign in to comment.