dnf: Add autoremove option

This allow users to write better playbooks by replacing

- shell: dnf autoremove -y
with
- dnf: autoremove=yes

Fixes #18815

Signed-off-by: Alberto Murillo Silva <alberto.murillo.silva@intel.com>
pull/24262/head
Alberto Murillo Silva 8 years ago committed by Toshio Kuratomi
parent 02057f481b
commit 136a6eec9e

@ -97,7 +97,16 @@ options:
version_added: "2.3" version_added: "2.3"
default: "/" default: "/"
notes: [] autoremove:
description:
- If C(yes), removes all "leaf" packages from the system that were originally
installed as dependencies of user-installed packages but which are no longer
required by any such package. Should be used alone or when state is I(absent)
required: false
choices: [ "yes", "no" ]
version_added: "2.4"
notes: ["autoremove requires dnf >= 2.0.1"]
# informational: requirements for nodes # informational: requirements for nodes
requirements: requirements:
- "python >= 2.6" - "python >= 2.6"
@ -144,11 +153,20 @@ EXAMPLES = '''
dnf: dnf:
name: '@Development tools' name: '@Development tools'
state: present state: present
- name: Autoremove unneeded packages installed as dependencies
dnf:
autoremove: yes
- name: Uninstall httpd but keep its dependencies
dnf:
name: httpd
state: absent
autoremove: no
''' '''
import os import os
try: try:
import dnf
import dnf import dnf
import dnf.cli import dnf.cli
import dnf.const import dnf.const
@ -161,6 +179,7 @@ except ImportError:
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import PY2 from ansible.module_utils.six import PY2
from distutils.version import LooseVersion
def _ensure_dnf(module): def _ensure_dnf(module):
@ -314,11 +333,18 @@ def _install_remote_rpms(base, filenames):
base.package_install(pkg) base.package_install(pkg)
def ensure(module, base, state, names): def ensure(module, base, state, names, autoremove):
# Accumulate failures. Package management modules install what they can # Accumulate failures. Package management modules install what they can
# and fail with a message about what they can't. # and fail with a message about what they can't.
failures = [] failures = []
allow_erasing = False allow_erasing = False
# Autoremove is called alone
# Jump to remove path where base.autoremove() is run
if not names and autoremove is not None:
names = []
state = 'absent'
if names == ['*'] and state == 'latest': if names == ['*'] and state == 'latest':
base.upgrade_all() base.upgrade_all()
else: else:
@ -398,6 +424,9 @@ def ensure(module, base, state, names):
else: else:
# state == absent # state == absent
if autoremove is not None:
base.conf.clean_requirements_on_remove = autoremove
if filenames: if filenames:
module.fail_json( module.fail_json(
msg="Cannot remove paths -- please specify package name.") msg="Cannot remove paths -- please specify package name.")
@ -425,6 +454,9 @@ def ensure(module, base, state, names):
# packages # packages
allow_erasing = True allow_erasing = True
if autoremove:
base.autoremove()
if not base.resolve(allow_erasing=allow_erasing): if not base.resolve(allow_erasing=allow_erasing):
if failures: if failures:
module.fail_json(msg='Failed to install some of the ' module.fail_json(msg='Failed to install some of the '
@ -460,7 +492,6 @@ def main():
argument_spec=dict( argument_spec=dict(
name=dict(aliases=['pkg'], type='list'), name=dict(aliases=['pkg'], type='list'),
state=dict( state=dict(
default='installed',
choices=[ choices=[
'absent', 'present', 'installed', 'removed', 'latest']), 'absent', 'present', 'installed', 'removed', 'latest']),
enablerepo=dict(type='list', default=[]), enablerepo=dict(type='list', default=[]),
@ -469,14 +500,28 @@ def main():
conf_file=dict(default=None, type='path'), conf_file=dict(default=None, type='path'),
disable_gpg_check=dict(default=False, type='bool'), disable_gpg_check=dict(default=False, type='bool'),
installroot=dict(default='/', type='path'), installroot=dict(default='/', type='path'),
autoremove=dict(type='bool'),
), ),
required_one_of=[['name', 'list']], required_one_of=[['name', 'list', 'autoremove']],
mutually_exclusive=[['name', 'list']], mutually_exclusive=[['name', 'list'], ['autoremove', 'list']],
supports_check_mode=True) supports_check_mode=True)
params = module.params params = module.params
_ensure_dnf(module) _ensure_dnf(module)
# Check if autoremove is called correctly
if params['autoremove'] is not None:
if LooseVersion(dnf.__version__) < LooseVersion('2.0.1'):
module.fail_json(msg="Autoremove requires dnf>=2.0.1. Current dnf version is %s" % dnf.__version__)
if params['state'] not in ["absent", None]:
module.fail_json(msg="Autoremove should be used alone or with state=absent")
# Set state as installed by default
# This is not set in AnsibleModule() because the following shouldn't happend
# - dnf: autoremove=yes state=installed
if params['state'] is None:
params['state'] = 'installed'
if params['list']: if params['list']:
base = _base( base = _base(
module, params['conf_file'], params['disable_gpg_check'], module, params['conf_file'], params['disable_gpg_check'],
@ -491,7 +536,7 @@ def main():
module, params['conf_file'], params['disable_gpg_check'], module, params['conf_file'], params['disable_gpg_check'],
params['disablerepo'], params['enablerepo'], params['installroot']) params['disablerepo'], params['enablerepo'], params['installroot'])
ensure(module, base, params['state'], params['name']) ensure(module, base, params['state'], params['name'], params['autoremove'])
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save