apt module: Add support for installing .deb packages

Support installing .deb packages from the local filesystem.

    apt: deb=/tmp/mypackage.deb
This commit is contained in:
Lorin Hochstein 2014-02-07 19:52:55 -05:00
parent c8a5e0a95e
commit 99ff70e15f

View file

@ -88,6 +88,11 @@ options:
- Options should be supplied as comma separated list - Options should be supplied as comma separated list
required: false required: false
default: 'force-confdef,force-confold' default: 'force-confdef,force-confold'
deb:
description:
- Path to a local .deb package file to install.
required: false
version_added: "1.5"
requirements: [ python-apt, aptitude ] requirements: [ python-apt, aptitude ]
author: Matthew Williams author: Matthew Williams
notes: notes:
@ -125,6 +130,9 @@ EXAMPLES = '''
# Pass options to dpkg on run # Pass options to dpkg on run
- apt: upgrade=dist update_cache=yes dpkg_options='force-confold,force-confdef' - apt: upgrade=dist update_cache=yes dpkg_options='force-confold,force-confdef'
# Install a .deb package
- apt: deb=/tmp/mypackage.deb
''' '''
@ -148,6 +156,7 @@ APT_UPDATE_SUCCESS_STAMP_PATH = "/var/lib/apt/periodic/update-success-stamp"
HAS_PYTHON_APT = True HAS_PYTHON_APT = True
try: try:
import apt import apt
import apt.debfile
import apt_pkg import apt_pkg
except: except:
HAS_PYTHON_APT = False HAS_PYTHON_APT = False
@ -269,12 +278,57 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None,
rc, out, err = m.run_command(cmd) rc, out, err = m.run_command(cmd)
if rc: if rc:
m.fail_json(msg="'apt-get install %s' failed: %s" % (packages, err), stdout=out, stderr=err) return (False, dict(msg="'apt-get install %s' failed: %s" % (packages, err), stdout=out, stderr=err))
else: else:
m.exit_json(changed=True, stdout=out, stderr=err) return (True, dict(changed=True, stdout=out, stderr=err))
else: else:
return (True, dict(changed=False))
def install_deb(m, debfile, cache, force, install_recommends, dpkg_options):
changed=False
pkg = apt.debfile.DebPackage(debfile)
# Check if it's already installed
if pkg.compare_to_version_in_cache() == pkg.VERSION_SAME:
m.exit_json(changed=False) m.exit_json(changed=False)
# Check if package is installable
if not pkg.check():
m.fail_json(msg=pkg._failure_string)
(success, retvals) = install(m=m, pkgspec=pkg.missing_deps,
cache=cache,
install_recommends=install_recommends,
dpkg_options=expand_dpkg_options(dpkg_options))
if not success:
m.fail_json(**retvals)
changed = retvals['changed']
options = ' '.join(["--%s"% x for x in dpkg_options.split(",")])
if m.check_mode:
options += " --simulate"
if force:
options += " --force-yes"
cmd = "dpkg %s -i %s" % (options, debfile)
rc, out, err = m.run_command(cmd)
if "stdout" in retvals:
stdout = retvals["stdout"] + out
else:
stdout = out
if "stderr" in retvals:
stderr = retvals["stderr"] + err
else:
stderr = err
if rc == 0:
m.exit_json(changed=True, stdout=stdout, stderr=stderr)
else:
m.fail_json(msg="%s failed" % cmd, stdout=stdout, stderr=stderr)
def remove(m, pkgspec, cache, purge=False, def remove(m, pkgspec, cache, purge=False,
dpkg_options=expand_dpkg_options(DPKG_OPTIONS)): dpkg_options=expand_dpkg_options(DPKG_OPTIONS)):
packages = "" packages = ""
@ -349,14 +403,15 @@ def main():
cache_valid_time = dict(type='int'), cache_valid_time = dict(type='int'),
purge = dict(default=False, type='bool'), purge = dict(default=False, type='bool'),
package = dict(default=None, aliases=['pkg', 'name']), package = dict(default=None, aliases=['pkg', 'name']),
deb = dict(default=None),
default_release = dict(default=None, aliases=['default-release']), default_release = dict(default=None, aliases=['default-release']),
install_recommends = dict(default='yes', aliases=['install-recommends'], type='bool'), install_recommends = dict(default='yes', aliases=['install-recommends'], type='bool'),
force = dict(default='no', type='bool'), force = dict(default='no', type='bool'),
upgrade = dict(choices=['yes', 'safe', 'full', 'dist']), upgrade = dict(choices=['yes', 'safe', 'full', 'dist']),
dpkg_options = dict(default=DPKG_OPTIONS) dpkg_options = dict(default=DPKG_OPTIONS)
), ),
mutually_exclusive = [['package', 'upgrade']], mutually_exclusive = [['package', 'upgrade', 'deb']],
required_one_of = [['package', 'upgrade', 'update_cache']], required_one_of = [['package', 'upgrade', 'update_cache', 'deb']],
supports_check_mode = True supports_check_mode = True
) )
@ -418,7 +473,7 @@ def main():
if cache_valid is not True: if cache_valid is not True:
cache.update() cache.update()
cache.open(progress=None) cache.open(progress=None)
if not p['package'] and not p['upgrade']: if not p['package'] and not p['upgrade'] and not p['deb']:
module.exit_json(changed=False) module.exit_json(changed=False)
force_yes = p['force'] force_yes = p['force']
@ -426,6 +481,13 @@ def main():
if p['upgrade']: if p['upgrade']:
upgrade(module, p['upgrade'], force_yes, dpkg_options) upgrade(module, p['upgrade'], force_yes, dpkg_options)
if p['deb']:
if p['state'] != "installed":
module.fail_json(msg="deb only supports state=installed")
install_deb(module, p['deb'], cache,
install_recommends=install_recommends,
force=force_yes, dpkg_options=p['dpkg_options'])
packages = p['package'].split(',') packages = p['package'].split(',')
latest = p['state'] == 'latest' latest = p['state'] == 'latest'
for package in packages: for package in packages:
@ -435,14 +497,24 @@ def main():
module.fail_json(msg='version number inconsistent with state=latest: %s' % package) module.fail_json(msg='version number inconsistent with state=latest: %s' % package)
if p['state'] == 'latest': if p['state'] == 'latest':
install(module, packages, cache, upgrade=True, result = install(module, packages, cache, upgrade=True,
default_release=p['default_release'], default_release=p['default_release'],
install_recommends=install_recommends, install_recommends=install_recommends,
force=force_yes, dpkg_options=dpkg_options) force=force_yes, dpkg_options=dpkg_options)
(success, retvals) = result
if success:
module.exit_json(**retvals)
else:
module.fail_json(**retvals)
elif p['state'] in [ 'installed', 'present' ]: elif p['state'] in [ 'installed', 'present' ]:
install(module, packages, cache, default_release=p['default_release'], result = install(module, packages, cache, default_release=p['default_release'],
install_recommends=install_recommends,force=force_yes, install_recommends=install_recommends,force=force_yes,
dpkg_options=dpkg_options) dpkg_options=dpkg_options)
(success, retvals) = result
if success:
module.exit_json(**retvals)
else:
module.fail_json(**retvals)
elif p['state'] in [ 'removed', 'absent' ]: elif p['state'] in [ 'removed', 'absent' ]:
remove(module, packages, cache, p['purge'], dpkg_options) remove(module, packages, cache, p['purge'], dpkg_options)