From dcd8c58f2e61c86b8238dccffb3603789a4c9bec Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 12 Nov 2024 08:36:26 -0500 Subject: [PATCH] package_facts fix empty packages on foreign mgr (#83855) * package_facts fix empty packages on foreign mgr return the first package manager that provides output add tests with fake rpm on apt machines (cherry picked from commit e404bc17f7551281c7019d7373d59a95ff1c8723) --- changelogs/fragments/package_facts_fix.yml | 2 + lib/ansible/modules/package_facts.py | 18 +++++++-- .../targets/package_facts/tasks/main.yml | 40 +++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 changelogs/fragments/package_facts_fix.yml diff --git a/changelogs/fragments/package_facts_fix.yml b/changelogs/fragments/package_facts_fix.yml new file mode 100644 index 00000000000..f1ffbf4d641 --- /dev/null +++ b/changelogs/fragments/package_facts_fix.yml @@ -0,0 +1,2 @@ +bugfixes: + - package_facts module when using 'auto' will return the first package manager found that provides an output, instead of just the first one, as this can be foreign and not have any packages. diff --git a/lib/ansible/modules/package_facts.py b/lib/ansible/modules/package_facts.py index bec6c34260b..954a34dc6e4 100644 --- a/lib/ansible/modules/package_facts.py +++ b/lib/ansible/modules/package_facts.py @@ -460,7 +460,7 @@ def main(): # get supported pkg managers PKG_MANAGERS = get_all_pkg_managers() - PKG_MANAGER_NAMES = [x.lower() for x in PKG_MANAGERS.keys()] + PKG_MANAGER_NAMES = sorted([x.lower() for x in PKG_MANAGERS.keys()]) # add aliases PKG_MANAGER_NAMES.extend([alias for alist in ALIASES.values() for alias in alist]) @@ -510,12 +510,24 @@ def main(): manager = PKG_MANAGERS[pkgmgr]() try: + packages_found = {} if manager.is_available(handle_exceptions=False): - found += 1 try: - packages.update(manager.get_packages()) + packages_found = manager.get_packages() except Exception as e: module.warn('Failed to retrieve packages with %s: %s' % (pkgmgr, to_text(e))) + + # only consider 'found' if it results in something + if packages_found: + found += 1 + for k in packages_found.keys(): + if k in packages: + packages[k].extend(packages_found[k]) + else: + packages[k] = packages_found[k] + else: + module.warn('Found "%s" but no associated packages' % (pkgmgr)) + except Exception as e: if pkgmgr in module.params['manager']: module.warn('Requested package manager %s was not usable by this module: %s' % (pkgmgr, to_text(e))) diff --git a/test/integration/targets/package_facts/tasks/main.yml b/test/integration/targets/package_facts/tasks/main.yml index 144fa784f70..9309dca2aa9 100644 --- a/test/integration/targets/package_facts/tasks/main.yml +++ b/test/integration/targets/package_facts/tasks/main.yml @@ -18,6 +18,46 @@ - name: check for ansible_facts.packages exists assert: that: ansible_facts.packages is defined + + - name: Now try again but installing misleading rpm + block: + - name: install misleading rpm api + package: name="python3-rpm" state=present + + - name: prep outputdir + tempfile: path=~ state=directory + register: tempdir + + - name: install misleading rpm 'binary' file + file: dest="{{tempdir['path']}}/rpm" state=touch mode='0700' + + - name: Gather package facts, finding 'rpm' on debian fam (needed for latest version) + package_facts: + environment: + PATH: "${PATH}:{{tempdir['path']}}" + + - name: check we got packages + assert: + that: + - (ansible_facts.packages | length ) > 0 + + - name: Same again but this time forcing rpm first + package_facts: + manager: ['rpm', 'apt'] + environment: + PATH: "${PATH}:{{tempdir['path']}}" + + - name: check we got packages + assert: + that: + - (ansible_facts.packages | length ) > 0 + + always: + - package: name="python3-rpm" state=absent + - file: path="{{tempdir['path']}}/rpm" state=absent + - file: path="{{tempdir['path']}}" state=absent + + when: ansible_os_family == "Debian" - name: Run package_fact tests - Red Hat Family