From d0b07885f00ac3227fc54ce4669acaf9ddbefec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dav=C3=AD=C3=B0=20Steinn=20Geirsson?= Date: Tue, 7 Jul 2020 21:04:35 +0000 Subject: [PATCH] pkgng: Add support for upgrading all installed packages (#569) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pkgng: Add support for upgrading all installed packages Adds support for ``name: "*", state: latest`` to upgrade all installed packages, similar to other package providers. Co-authored-by: Felix Fontein * pkgng: Improve wording for warning in example, fix formatting * pkgng.py: Fix capitalization Co-authored-by: Felix Fontein Co-authored-by: Davíð Steinn Geirsson Co-authored-by: Felix Fontein --- .../569-pkgng-add-upgrade-action.yaml | 6 +++ plugins/modules/packaging/os/pkgng.py | 52 ++++++++++++++++--- 2 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/569-pkgng-add-upgrade-action.yaml diff --git a/changelogs/fragments/569-pkgng-add-upgrade-action.yaml b/changelogs/fragments/569-pkgng-add-upgrade-action.yaml new file mode 100644 index 0000000000..0078c18865 --- /dev/null +++ b/changelogs/fragments/569-pkgng-add-upgrade-action.yaml @@ -0,0 +1,6 @@ +--- +minor_changes: + - "pkgng - added support for upgrading all packages using ``name: *, state: latest``, similar to other package providers (https://github.com/ansible-collections/community.general/pull/569)." +breaking_changes: + - "pkgng - passing ``name: *`` with ``state: latest`` or ``state: present`` will no longer install every package from the configured package repositories. Instead, ``name: *, state: latest`` will upgrade all already-installed packages, and ``name: *, state: present`` is a noop. (https://github.com/ansible-collections/community.general/pull/569)." + - "pkgng - passing ``name: *`` with ``state: absent`` will no longer remove every installed package from the system. It is now a noop. (https://github.com/ansible-collections/community.general/pull/569)." diff --git a/plugins/modules/packaging/os/pkgng.py b/plugins/modules/packaging/os/pkgng.py index f6321fff80..82f79375bd 100644 --- a/plugins/modules/packaging/os/pkgng.py +++ b/plugins/modules/packaging/os/pkgng.py @@ -23,6 +23,13 @@ options: name: description: - Name or list of names of packages to install/remove. + - "With I(name=*), I(state: latest) will operate, but I(state: present) and I(state: absent) will be noops." + - > + Warning: In Ansible 2.9 and earlier this module had a misfeature + where I(name=*) with I(state: latest) or I(state: present) would + install every package from every package repository, filling up + the machines disk. Avoid using them unless you are certain that + your role will only be used with newer versions. required: true aliases: [pkg] type: list @@ -111,6 +118,11 @@ EXAMPLES = ''' pkgng: name: baz state: latest + +- name: Upgrade all installed packages (see warning for the name option first!) + pkgng: + name: "*" + state: latest ''' @@ -161,6 +173,24 @@ def pkgng_older_than(module, pkgng_path, compare_version): return not new_pkgng +def upgrade_packages(module, pkgng_path, dir_arg): + # Run a 'pkg upgrade', updating all packages. + upgraded_c = 0 + + cmd = "%s %s upgrade -y" % (pkgng_path, dir_arg) + if module.check_mode: + cmd += " -n" + rc, out, err = module.run_command(cmd) + + match = re.search('^Number of packages to be upgraded: ([0-9]+)', out, re.MULTILINE) + if match: + upgraded_c = int(match.group(1)) + + if upgraded_c > 0: + return (True, "updated %s package(s)" % upgraded_c, out, err) + return (False, "no packages need upgrades", out, err) + + def remove_packages(module, pkgng_path, packages, dir_arg): remove_c = 0 stdout = "" @@ -391,18 +421,28 @@ def main(): if p["jail"] != "": dir_arg = '--jail %s' % (p["jail"]) - if p["state"] in ("present", "latest"): - _changed, _msg, _stdout, _stderr = install_packages(module, pkgng_path, pkgs, p["cached"], p["pkgsite"], dir_arg, p["state"]) + if pkgs == ['*'] and p["state"] == 'latest': + # Operate on all installed packages. Only state: latest makes sense here. + _changed, _msg, _stdout, _stderr = upgrade_packages(module, pkgng_path, dir_arg) changed = changed or _changed stdout += _stdout stderr += _stderr msgs.append(_msg) - elif p["state"] == "absent": - _changed, _msg, _stdout, _stderr = remove_packages(module, pkgng_path, pkgs, dir_arg) + # Operate on named packages + named_packages = [pkg for pkg in pkgs if pkg != '*'] + if p["state"] in ("present", "latest") and named_packages: + _changed, _msg, _out, _err = install_packages(module, pkgng_path, named_packages, p["cached"], p["pkgsite"], dir_arg, p["state"]) + stdout += _out + stderr += _err + changed = changed or _changed + msgs.append(_msg) + + elif p["state"] == "absent" and named_packages: + _changed, _msg, _out, _err = remove_packages(module, pkgng_path, named_packages, dir_arg) + stdout += _out + stderr += _err changed = changed or _changed - stdout += _stdout - stderr += _stderr msgs.append(_msg) if p["autoremove"]: