From e4c0bbf8858612133941c9d5a9bf14f90a62494c Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Thu, 26 May 2022 00:26:02 +1000 Subject: [PATCH] apt: fix virtual package install version detection (#76781) * apt: fix virtual package install version detection Change 4a62c4e3e44b01a904aa86e9b87206a24bd41fbc introduced version matching in installation. The problem stems from if version_installable or version: pkg_list.append("'%s=%s'" % (name, version_installable or version)) When the package is a virtual-package, package_status() is returning the "version_installable" of the package *satisfying* the virtual-package; but then this is trying to install the virtual-package with this version pin. For example, "yaml-mode" is a virtual package satisifed by "elpa-yaml-mode" (currently 0.0.14-1) and trying to install it fails with $ usr/bin/apt-get -y ... install 'yaml-mode=0.0.14-1' ... failed: E: Version '0.0.14-1' for 'yaml-mode' was not found ... In the case of a virtual-package with nothing installed to satisfy it, we should just return blank values to allow apt-get to do it's thing. The tests are updated to install and remove this package. Fixes: #76779 --- changelogs/fragments/apt_virtual_fix.yml | 2 ++ lib/ansible/modules/apt.py | 17 ++++++++++------- test/integration/targets/apt/tasks/apt.yml | 22 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/apt_virtual_fix.yml diff --git a/changelogs/fragments/apt_virtual_fix.yml b/changelogs/fragments/apt_virtual_fix.yml new file mode 100644 index 00000000000..5aa79a7083f --- /dev/null +++ b/changelogs/fragments/apt_virtual_fix.yml @@ -0,0 +1,2 @@ +bugfixes: + - apt module now correctly handles virtual packages. diff --git a/lib/ansible/modules/apt.py b/lib/ansible/modules/apt.py index 70e28eb0a48..121eff935c3 100644 --- a/lib/ansible/modules/apt.py +++ b/lib/ansible/modules/apt.py @@ -510,17 +510,20 @@ def package_status(m, pkgname, version_cmp, version, default_release, cache, sta try: provided_packages = cache.get_providing_packages(pkgname) if provided_packages: - is_installed = False - version_installable = None - version_ok = False - # when virtual package providing only one package, look up status of target package + # When this is a virtual package satisfied by only + # one installed package, return the status of the target + # package to avoid requesting re-install if cache.is_virtual_package(pkgname) and len(provided_packages) == 1: package = provided_packages[0] - installed, version_ok, version_installable, has_files = \ + installed, installed_version, version_installable, has_files = \ package_status(m, package.name, version_cmp, version, default_release, cache, state='install') if installed: - is_installed = True - return is_installed, version_ok, version_installable, False + return installed, installed_version, version_installable, has_files + + # Otherwise return nothing so apt will sort out + # what package to satisfy this with + return False, False, None, False + m.fail_json(msg="No package matching '%s' is available" % pkgname) except AttributeError: # python-apt version too old to detect virtual packages diff --git a/test/integration/targets/apt/tasks/apt.yml b/test/integration/targets/apt/tasks/apt.yml index 816141183d8..5b1a24a3b4f 100644 --- a/test/integration/targets/apt/tasks/apt.yml +++ b/test/integration/targets/apt/tasks/apt.yml @@ -507,3 +507,25 @@ that: - "allow_change_held_packages_no_update is not changed" - "allow_change_held_packages_hello_version.stdout == allow_change_held_packages_hello_version_again.stdout" + +# Virtual package +- name: Install a virtual package + apt: + package: + - emacs-nox + - yaml-mode # <- the virtual package + state: latest + register: install_virtual_package_result + +- name: Check the virtual package install result + assert: + that: + - install_virtual_package_result is changed + +- name: Clean up virtual-package install + apt: + package: + - emacs-nox + - elpa-yaml-mode + state: absent + purge: yes