Merge remote branch 'public/integration'

This commit is contained in:
Michael DeHaan 2012-04-02 20:02:46 -04:00
commit e5d5b072db
5 changed files with 92 additions and 57 deletions

View file

@ -1,4 +1,3 @@
#!/usr/bin/python -tt
# (C) 2012, Michael DeHaan, <michael.dehaan@gmail.com>
# This file is part of Ansible

View file

@ -457,7 +457,7 @@ class PlayBook(object):
SETUP_CACHE[host] = result
if self.extra_vars:
extra_vars = utils.parse_kv(shlex.split(self.extra_vars))
extra_vars = utils.parse_kv(self.extra_vars)
for h in self.host_list:
try:
SETUP_CACHE[h].update(extra_vars)

View file

@ -160,6 +160,9 @@ class Runner(object):
cmd.extend(['--extra-vars', extra_vars])
cmd = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
out, err = cmd.communicate()
rc = cmd.returncode
if rc:
raise errors.AnsibleError("%s: %s" % (host_list, err))
try:
groups = utils.json_loads(out)
except:

View file

@ -28,7 +28,8 @@ import shlex
import subprocess
import traceback
APT = "/usr/bin/apt-get"
APT_PATH = "/usr/bin/apt-get"
APT = "DEBIAN_PRIORITY=critical %s" % APT_PATH
def debug(msg):
# ansible ignores stderr, so it's safe to use for debug
@ -44,7 +45,6 @@ def fail_json(**kwargs):
exit_json(rc=1, **kwargs)
def run_apt(command):
debug(command)
try:
cmd = subprocess.Popen(command, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -57,65 +57,44 @@ def run_apt(command):
rc = 1
err = traceback.format_exc()
out = ''
if out is None:
out = ''
if err is None:
err = ''
else:
rc = cmd.returncode
debug(err)
return rc, out, err
return rc, out, err
def get_cache():
# TODO: Only update the cache if it's old.
cache = apt.Cache()
cache.update()
cache.open(None)
return cache
def package_installed(pkgspec):
cache = get_cache()
def package_status(pkgspec, cache):
try:
pkg = cache[pkgspec]
except:
fail_json(msg="No package matching '%s' is available" % pkgspec)
return bool(pkg.is_installed)
return (pkg.is_installed, pkg.is_upgradable)
def install(pkgspec):
installed = package_installed(pkgspec)
debug("installed: %d" % installed)
if installed:
def install(pkgspec, cache, upgrade=False):
(installed, upgradable) = package_status(pkgspec, cache)
if installed or not upgrade or not upgradable:
return False
else:
cmd = "%s -q -y install '%s'" % (APT, pkgspec)
rc, out, err = run_apt(cmd)
# TODO: Ensure the package was really installed.
if rc:
json_fail(msg="'apt-get install %s' failed: %s" % (pkgspec, err))
return True
def remove(pkgspec):
installed = package_installed(pkgspec)
debug("installed: %d" % installed)
def remove(pkgspec, cache, purge=False):
(installed, upgradable) = package_status(pkgspec, cache)
if not installed:
return False
else:
cmd = "%s -q -y remove '%s'" % (APT, pkgspec)
purge = '--purge' if purge else ''
cmd = "%s -q -y %s remove '%s'" % (APT, purge, pkgspec)
rc, out, err = run_apt(cmd)
# TODO: Ensure the package was really removed.
if rc:
json_fail(msg="'apt-get remove %s' failed: %s" % (pkgspec, err))
return True
def update(args):
# TODO: generic update routine
pass
def remove_only(pkgspec):
# TODO: remove this pkg and only this pkg - fail if it will require more to remove
pass
# ===========================================
if not os.path.exists(APT):
if not os.path.exists(APT_PATH):
fail_json(msg="Cannot find apt-get")
argfile = sys.argv[1]
@ -131,18 +110,31 @@ for x in items:
(k, v) = x.split("=")
params[k] = v
state = params.get('state','installed')
package = params.get('pkg', None)
state = params.get('state','installed')
package = params.get('pkg', None)
update_cache = params.get('update-cache', 'no')
purge = params.get('purge', 'no')
if state not in ['installed', 'removed']:
if state not in ['installed', 'latest', 'removed']:
fail_json(msg='invalid state')
if package is None:
fail_json(msg='pkg is required')
if update_cache not in ['yes', 'no']:
fail_json(msg='invalid value for update_cache (requires yes or no -- default is no')
if purge not in ['yes', 'no']:
fail_json(msg='invalid value for purge (requires yes or no -- default is no)')
if package is None and update-cache != 'yes':
fail_json(msg='pkg=name and/or update-cache=yes is required')
cache = apt.Cache()
if update_cache == 'yes':
cache.update()
cache.open()
if state == 'latest':
changed = install(package, cache, upgrade=True)
if state == 'installed':
changed = install(package)
changed = install(package, cache)
elif state == 'removed':
changed = remove(package)
changed = remove(package, cache, purge == 'yes')
exit_json(changed=changed)

View file

@ -55,7 +55,9 @@ def add_path_info(kwargs):
st = os.stat(path)
kwargs['mode'] = stat.S_IMODE(st[stat.ST_MODE])
# secontext not yet supported
if os.path.isfile(path):
if os.path.islink(path):
kwargs['state'] = 'link'
elif os.path.isfile(path):
kwargs['state'] = 'file'
else:
kwargs['state'] = 'directory'
@ -80,6 +82,8 @@ for x in items:
state = params.get('state','file')
path = params.get('path', params.get('dest', params.get('name', None)))
src = params.get('src', None)
dest = params.get('dest', None)
mode = params.get('mode', None)
owner = params.get('owner', None)
group = params.get('group', None)
@ -90,10 +94,13 @@ recurse = params.get('recurse', 'false')
# presently unused, implement (FIXME)
secontext = params.get('secontext', None)
if state not in [ 'file', 'directory', 'absent' ]:
fail_json(msg='invalid state')
if path is None:
fail_json(msg='path is required')
if state not in [ 'file', 'directory', 'link', 'absent']:
fail_json(msg='invalid state: %s' % state)
if state = 'link' and (src is None or dest is None):
fail_json(msg='src and dest are required for "link" state')
elif path is None:
fail_json(msg='path is required for "%s" state' % state)
changed = False
@ -152,7 +159,7 @@ def set_mode_if_different(path, mode, changed):
return changed
try:
# FIXME: support English modes
mode = int("0%s" % mode)
mode = int(mode, 8)
except Exception, e:
fail_json(path=path, msg='mode needs to be something octalish', details=str(e))
@ -175,6 +182,7 @@ def set_mode_if_different(path, mode, changed):
return True
return changed
def rmtree_error(func, path, exc_info):
fail_json(path=path, msg='failed to remove directory')
@ -183,7 +191,9 @@ def rmtree_error(func, path, exc_info):
prev_state = 'absent'
if os.path.exists(path):
if os.path.isfile(path):
if os.path.islink(path):
prev_state = 'link'
elif os.path.isfile(path):
prev_state = 'file'
else:
prev_state = 'directory'
@ -204,7 +214,7 @@ if prev_state != 'absent' and state == 'absent':
sys.exit(0)
if prev_state != 'absent' and prev_state != state:
fail_json(path=path, msg='refusing to convert between file and directory')
fail_json(path=path, msg='refusing to convert between %s and %s' % (prev_state, state))
if prev_state == 'absent' and state == 'absent':
exit_json(path=path, changed=False)
@ -233,11 +243,42 @@ elif state == 'directory':
# set modes owners and context as needed
changed = set_context_if_different(path, secontext, changed)
changed = set_owner_if_different(path, owner, changed)
changed = set_group_if_different(path, owner, changed)
changed = set_mode_if_different(path, owner, changed)
changed = set_group_if_different(path, group, changed)
changed = set_mode_if_different(path, mode, changed)
exit_json(path=path, changed=changed)
elif state == 'link':
if os.path.isabs(src):
abs_src = src
else:
abs_src = os.path.join(os.path.dirname(dest))
if not os.path.exists(abssrc):
fail_json(dest=dest, src=src, msg='src file does not exist')
if prev_state == 'absent':
os.symlink(src, dest)
changed = True
elif prev_state == 'link':
old_src = os.readlink(dest)
if not os.path.isabs(old_src):
old_src = os.path.join(os.path.dirname(dest), old_src)
if old_src != src:
os.unlink(dest)
os.symlink(src, dest)
else:
fail_json(dest=dest, src=src, msg='unexpected position reached')
# set modes owners and context as needed
changed = set_context_if_different(dest, secontext, changed)
changed = set_owner_if_different(dest, owner, changed)
changed = set_group_if_different(dest, group, changed)
changed = set_mode_if_different(dest, mode, changed)
exit_json(dest=dest, src=src, changed=changed)
fail_json(path=path, msg='unexpected position reached')
sys.exit(0)