ansible/library/apt
Nikhil Singh daf44331c4 Code review changes
1. Passing the module to the various functions so that they can use module.fail_json and module.exit_json methods inside.
2. Because of point 1, install and remove methods do not return anything. Instead, they use the module functions itself.
3. Move the import statement (for apt and apt_pkg) inside main function so on import error, we can use module.fail_json to print the error.
2012-07-26 17:29:15 +05:30

173 lines
6 KiB
Python
Executable file

#!/usr/bin/python -tt
# (c) 2012, Flowroute LLC
# Written by Matthew Williams <matthew@flowroute.com>
# Based on yum module written by Seth Vidal <skvidal at fedoraproject.org>
#
# 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 <http://www.gnu.org/licenses/>.
#
import traceback
# added to stave off future warnings about apt api
import warnings;
warnings.filterwarnings('ignore', "apt API not stable yet", FutureWarning)
# APT related constants
APT_PATH = "/usr/bin/apt-get"
APT = "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical %s" % APT_PATH
def run_apt(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 = ''
else:
rc = cmd.returncode
return rc, out, err
def package_split(pkgspec):
parts = pkgspec.split('=')
if len(parts) > 1:
return parts[0], parts[1]
else:
return parts[0], None
def package_status(m, pkgname, version, cache):
try:
pkg = cache[pkgname]
except KeyError:
m.fail_json(msg="No package matching '%s' is available" % pkgname)
if version:
try :
return pkg.is_installed and pkg.installed.version == version, False
except AttributeError:
#assume older version of python-apt is installed
return pkg.isInstalled and pkg.installedVersion == version, False
else:
try :
return pkg.is_installed, pkg.is_upgradable
except AttributeError:
#assume older version of python-apt is installed
return pkg.isInstalled, pkg.isUpgradable
def install(m, pkgspec, cache, upgrade=False, default_release=None, install_recommends=True, force=False):
name, version = package_split(pkgspec)
installed, upgradable = package_status(m, name, version, cache)
if not installed or (upgrade and upgradable):
if force:
force_yes = '--force-yes'
else:
force_yes = ''
cmd = "%s --option Dpkg::Options::=--force-confold -q -y %s install '%s'" % (APT, force_yes, pkgspec)
if default_release:
cmd += " -t '%s'" % (default_release,)
if not install_recommends:
cmd += " --no-install-recommends"
rc, out, err = run_apt(cmd)
if rc:
m.fail_json(msg="'apt-get install %s' failed: %s" % (pkgspec, err))
else:
m.exit_json(changed=True)
else:
m.exit_json(changed=False)
def remove(m, pkgspec, cache, purge=False):
name, version = package_split(pkgspec)
installed, upgradable = package_status(m, name, version, cache)
if not installed:
m.exit_json(changed=False)
else:
purge = '--purge' if purge else ''
cmd = "%s -q -y %s remove '%s'" % (APT, purge, name)
rc, out, err = run_apt(cmd)
if rc:
m.fail_json(msg="'apt-get remove %s' failed: %s" % (name, err))
m.exit_json(changed=True)
def main():
module = AnsibleModule(
argument_spec = dict(
state = dict(default='installed', choices=['installed', 'latest', 'removed']),
update_cache = dict(default='no', choices=['yes', 'no']),
purge = dict(default='no', choices=['yes', 'no']),
package = dict(default=None, aliases=['pkg', 'name']),
default_release = dict(default=None, aliases=['default-release']),
install_recommends = dict(default='yes', aliases=['install-recommends'], choices=['yes', 'no']),
force = dict(default='no', choices=['yes', 'no'])
)
)
try:
import apt, apt_pkg
except:
module.fail_json("Could not import python modules: apt, apt_pkg. Please install python-apt package.")
if not os.path.exists(APT_PATH):
module.fail_json(msg="Cannot find apt-get")
p = module.params
if p['package'] is None and p['update_cache'] != 'yes':
module.fail_json(msg='pkg=name and/or update-cache=yes is required')
install_recommends = (p['install_recommends'] == 'yes')
cache = apt.Cache()
if p['default_release']:
apt_pkg.config['APT::Default-Release'] = p['default_release']
# reopen cache w/ modified config
cache.open(progress=None)
if p['update_cache'] == 'yes':
cache.update()
cache.open(progress=None)
if p['package'] == None:
module.exit_json(changed=False)
if p['force'] == 'yes':
force_yes = True
else:
force_yes = False
if p['package'].count('=') > 1:
module.fail_json(msg='invalid package spec')
if p['state'] == 'latest':
if '=' in p['package']:
module.fail_json(msg='version number inconsistent with state=latest')
install(module, p['package'], cache, upgrade=True,
default_release=p['default_release'],
install_recommends=install_recommends,
force=force_yes)
elif p['state'] == 'installed':
install(module, p['package'], cache, default_release=p['default_release'],
install_recommends=install_recommends,force=force_yes)
elif p['state'] == 'removed':
remove(module, p['package'], cache, purge == 'yes')
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()