diff --git a/library/apt b/library/apt new file mode 100755 index 00000000000..9e77a8156d4 --- /dev/null +++ b/library/apt @@ -0,0 +1,148 @@ +#!/usr/bin/python -tt +# (c) 2012, Flowroute LLC +# Written by Matthew Williams +# Based on yum module written by Seth Vidal +# +# This module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software. If not, see . +# + +try: + import json +except ImportError: + import simplejson as json +import os +import sys +import apt +import shlex +import subprocess +import traceback + +APT = "/usr/bin/apt-get" + +def debug(msg): + # ansible ignores stderr, so it's safe to use for debug + print >>sys.stderr, msg + #pass + +def exit_json(rc=0, **kwargs): + print json.dumps(kwargs) + sys.exit(rc) + +def fail_json(**kwargs): + kwargs['failed'] = True + exit_json(rc=1, **kwargs) + +def run_apt(command): + debug(command) + try: + cmd = subprocess.Popen(command, shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = cmd.communicate() + except (OSError, IOError), e: + rc = 1 + err = str(e) + out = '' + except: + 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 + +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() + try: + pkg = cache[pkgspec] + except: + fail_json(msg="No package matching '%s' is available" % pkgspec) + return bool(pkg.is_installed) + +def install(pkgspec): + installed = package_installed(pkgspec) + debug("installed: %d" % installed) + if installed: + return False + else: + cmd = "%s -q -y install '%s'" % (APT, pkgspec) + rc, out, err = run_apt(cmd) + # TODO: Ensure the package was really installed. + return True + +def remove(pkgspec): + installed = package_installed(pkgspec) + debug("installed: %d" % installed) + if not installed: + return False + else: + cmd = "%s -q -y remove '%s'" % (APT, pkgspec) + rc, out, err = run_apt(cmd) + # TODO: Ensure the package was really removed. + 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): + fail_json(msg="Cannot find apt-get") + +argfile = sys.argv[1] +args = open(argfile, 'r').read() +items = shlex.split(args) + +if not len(items): + fail_json(msg='the module requires arguments -a') + sys.exit(1) + +params = {} +for x in items: + (k, v) = x.split("=") + params[k] = v + +state = params.get('state','installed') +package = params.get('pkg', None) + +if state not in ['installed', 'removed']: + fail_json(msg='invalid state') +if package is None: + fail_json(msg='pkg is required') + +if state == 'installed': + changed = install(package) +elif state == 'removed': + changed = remove(package) +exit_json(changed=changed) + +