From 76d998ef615111db7846bc00cc5e839cfef9395e Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Tue, 17 Dec 2024 18:42:43 -0600 Subject: [PATCH 1/3] Update to 2.16.14. --- .gitignore | 2 ++ ansible-core.spec | 5 ++++- sources | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 949512f..7a90162 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ /ansible-documentation-2.16.11.tar.gz /ansible-core-2.16.12.tar.gz /ansible-documentation-2.16.12.tar.gz +/ansible-core-2.16.14.tar.gz +/ansible-documentation-2.16.14.tar.gz diff --git a/ansible-core.spec b/ansible-core.spec index c7683f0..1fc3363 100644 --- a/ansible-core.spec +++ b/ansible-core.spec @@ -14,7 +14,7 @@ Name: ansible-core Summary: A radically simple IT automation system -Version: 2.16.12 +Version: 2.16.14 %global uversion %{version_no_tilde %{quote:%nil}} Release: 1%{?dist} # The main license is GPLv3+. Many of the files in lib/ansible/module_utils @@ -278,6 +278,9 @@ install -Dpm 0644 licenses/* -t %{buildroot}%{_pkglicensedir} %changelog +* Wed Dec 18 2024 Maxwell G - 2.16.14-1 +- Update to 2.16.14. + * Fri Oct 11 2024 Maxwell G - 2.16.12-1 - Update to 2.16.12. diff --git a/sources b/sources index 06978ba..7098617 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (ansible-core-2.16.12.tar.gz) = 6048ecc31b23244f0826dd3e46c93d35e667f059a346a3f51a312028c80d333b75066b0a17fe043e53aafa128c78ca3a88dbfa3954c0b8869fe92b2e71134f42 -SHA512 (ansible-documentation-2.16.12.tar.gz) = 466f95af9bcae3b392d737f58d7dfe0fe9c9b27305fea66b6d9fa358c0ef2340bf0b4c24637675bd5aaa950a435dd1d6e04d7b043cd7962a80468a6ed6e38992 +SHA512 (ansible-core-2.16.14.tar.gz) = 6a375db9481be199b0bd1fd41ffc7631bd69cab1ebdacdb0a41f42cdba60ee4916a3eb4238fd865b5b75f4f32ba42a9ee073d56d6986ce3aecf27bb75f02898c +SHA512 (ansible-documentation-2.16.14.tar.gz) = 6241289f243c582701133d3a3add14456e6bccca796fcaae6f5124df8e13027f59563ef745a81581e73b42a12c4af38f1745760759bb4abd7fc6e489c3d9277f From e9b83ad6a4a322a30e44255377a8b66f4f11e4e2 Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Tue, 17 Dec 2024 18:45:40 -0600 Subject: [PATCH 2/3] Backport support for automatically installing python3-libdnf5 Resolves: https://bugzilla.redhat.com/2322751 --- ...ns-while-installing-python3-apt-8291.patch | 107 ++++++ ...uto_install_module_deps-option-84292.patch | 324 ++++++++++++++++++ ansible-core.spec | 10 + 3 files changed, 441 insertions(+) create mode 100644 0001-apt-handle-options-while-installing-python3-apt-8291.patch create mode 100644 0002-dnf5-apt-add-auto_install_module_deps-option-84292.patch diff --git a/0001-apt-handle-options-while-installing-python3-apt-8291.patch b/0001-apt-handle-options-while-installing-python3-apt-8291.patch new file mode 100644 index 0000000..2ea4fcd --- /dev/null +++ b/0001-apt-handle-options-while-installing-python3-apt-8291.patch @@ -0,0 +1,107 @@ +From 47da1bead9ad6d5fbf8e1f9f18d5ea9294342696 Mon Sep 17 00:00:00 2001 +From: Abhijeet Kasurde +Date: Tue, 26 Mar 2024 08:16:27 -0700 +Subject: [PATCH 1/2] apt: handle options while installing python3-apt (#82913) + +* apt: handle options while installing python3-apt + +* While installing python3-apt library, honor parameter + such as install_recommends and dpkg_options + +Fixes: #40608 + +Signed-off-by: Abhijeet Kasurde + +* Review changes + +Signed-off-by: Abhijeet Kasurde + +--------- + +Signed-off-by: Abhijeet Kasurde +(cherry picked from commit 8fec1575e63b259311de1fa3505769eeb4696665) +--- + changelogs/fragments/apt_install.yml | 3 +++ + lib/ansible/modules/apt.py | 30 ++++++++++++++++++---------- + 2 files changed, 22 insertions(+), 11 deletions(-) + create mode 100644 changelogs/fragments/apt_install.yml + +diff --git a/changelogs/fragments/apt_install.yml b/changelogs/fragments/apt_install.yml +new file mode 100644 +index 0000000000..84dfaed78a +--- /dev/null ++++ b/changelogs/fragments/apt_install.yml +@@ -0,0 +1,3 @@ ++--- ++bugfixes: ++ - apt - honor install_recommends and dpkg_options while installing python3-apt library (https://github.com/ansible/ansible/issues/40608). +diff --git a/lib/ansible/modules/apt.py b/lib/ansible/modules/apt.py +index 336eadde54..8eca4decb2 100644 +--- a/lib/ansible/modules/apt.py ++++ b/lib/ansible/modules/apt.py +@@ -1246,6 +1246,15 @@ def main(): + ) + module.run_command_environ_update = APT_ENV_VARS + ++ global APTITUDE_CMD ++ APTITUDE_CMD = module.get_bin_path("aptitude", False) ++ global APT_GET_CMD ++ APT_GET_CMD = module.get_bin_path("apt-get") ++ ++ p = module.params ++ install_recommends = p['install_recommends'] ++ dpkg_options = expand_dpkg_options(p['dpkg_options']) ++ + if not HAS_PYTHON_APT: + # This interpreter can't see the apt Python library- we'll do the following to try and fix that: + # 1) look in common locations for system-owned interpreters that can see it; if we find one, respawn under it +@@ -1284,10 +1293,18 @@ def main(): + module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name) + else: + module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name) +- module.run_command(['apt-get', 'update'], check_rc=True) ++ module.run_command([APT_GET_CMD, 'update'], check_rc=True) + + # try to install the apt Python binding +- module.run_command(['apt-get', 'install', '--no-install-recommends', apt_pkg_name, '-y', '-q'], check_rc=True) ++ apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options] ++ ++ if install_recommends is False: ++ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"]) ++ elif install_recommends is True: ++ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"]) ++ # install_recommends is None uses the OS default ++ ++ module.run_command(apt_pkg_cmd, check_rc=True) + + # try again to find the bindings in common places + interpreter = probe_interpreters_for_module(interpreters, 'apt') +@@ -1301,13 +1318,6 @@ def main(): + # we've done all we can do; just tell the user it's busted and get out + module.fail_json(msg="{0} must be installed and visible from {1}.".format(apt_pkg_name, sys.executable)) + +- global APTITUDE_CMD +- APTITUDE_CMD = module.get_bin_path("aptitude", False) +- global APT_GET_CMD +- APT_GET_CMD = module.get_bin_path("apt-get") +- +- p = module.params +- + if p['clean'] is True: + aptclean_stdout, aptclean_stderr, aptclean_diff = aptclean(module) + # If there is nothing else to do exit. This will set state as +@@ -1331,11 +1341,9 @@ def main(): + + updated_cache = False + updated_cache_time = 0 +- install_recommends = p['install_recommends'] + allow_unauthenticated = p['allow_unauthenticated'] + allow_downgrade = p['allow_downgrade'] + allow_change_held_packages = p['allow_change_held_packages'] +- dpkg_options = expand_dpkg_options(p['dpkg_options']) + autoremove = p['autoremove'] + fail_on_autoremove = p['fail_on_autoremove'] + autoclean = p['autoclean'] +-- +2.47.0 + diff --git a/0002-dnf5-apt-add-auto_install_module_deps-option-84292.patch b/0002-dnf5-apt-add-auto_install_module_deps-option-84292.patch new file mode 100644 index 0000000..a9f29b2 --- /dev/null +++ b/0002-dnf5-apt-add-auto_install_module_deps-option-84292.patch @@ -0,0 +1,324 @@ +From ad10b351811dfe4d98a4f7c50f219495c7d17285 Mon Sep 17 00:00:00 2001 +From: Martin Krizek +Date: Thu, 21 Nov 2024 17:06:18 +0100 +Subject: [PATCH 2/2] dnf5,apt: add auto_install_module_deps option (#84292) + +* dnf5,apt: add auto_install_module_deps option + +Fixes #84206 + +(cherry picked from commit 2a53b851fee8ebaa07c1341122dd905354659237) +--- + ...4206-dnf5-apt-auto-install-module-deps.yml | 2 + + lib/ansible/modules/apt.py | 84 +++++++++++-------- + lib/ansible/modules/dnf5.py | 52 +++++++++--- + test/integration/targets/apt/tasks/apt.yml | 28 +++++-- + test/integration/targets/dnf5/playbook.yml | 17 +++- + 5 files changed, 128 insertions(+), 55 deletions(-) + create mode 100644 changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml + +diff --git a/changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml b/changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml +new file mode 100644 +index 0000000000..14d595449c +--- /dev/null ++++ b/changelogs/fragments/84206-dnf5-apt-auto-install-module-deps.yml +@@ -0,0 +1,2 @@ ++minor_changes: ++ - dnf5, apt - add ``auto_install_module_deps`` option (https://github.com/ansible/ansible/issues/84206) +diff --git a/lib/ansible/modules/apt.py b/lib/ansible/modules/apt.py +index 8eca4decb2..eab58b82ee 100644 +--- a/lib/ansible/modules/apt.py ++++ b/lib/ansible/modules/apt.py +@@ -18,6 +18,12 @@ description: + - Manages I(apt) packages (such as for Debian/Ubuntu). + version_added: "0.0.2" + options: ++ auto_install_module_deps: ++ description: ++ - Automatically install dependencies required to run this module. ++ type: bool ++ default: yes ++ version_added: 2.19 + name: + description: + - A list of package names, like V(foo), or package specifier with version, like V(foo=1.0) or V(foo>=1.0). +@@ -214,6 +220,9 @@ notes: + - When used with a C(loop:) each package will be processed individually, it is much more efficient to pass the list directly to the O(name) option. + - When O(default_release) is used, an implicit priority of 990 is used. This is the same behavior as C(apt-get -t). + - When an exact version is specified, an implicit priority of 1001 is used. ++ - If the interpreter can't import C(python3-apt) the module will check for it in system-owned interpreters as well. ++ If the dependency can't be found, depending on the value of O(auto_install_module_deps) the module will attempt to install it. ++ If the dependency is found or installed, the module will be respawned under the correct interpreter. + ''' + + EXAMPLES = ''' +@@ -1224,6 +1233,7 @@ def main(): + allow_downgrade=dict(type='bool', default=False, aliases=['allow-downgrade', 'allow_downgrades', 'allow-downgrades']), + allow_change_held_packages=dict(type='bool', default=False), + lock_timeout=dict(type='int', default=60), ++ auto_install_module_deps=dict(type='bool', default=True), + ), + mutually_exclusive=[['deb', 'package', 'upgrade']], + required_one_of=[['autoremove', 'deb', 'package', 'update_cache', 'upgrade']], +@@ -1284,39 +1294,47 @@ def main(): + + # don't make changes if we're in check_mode + if module.check_mode: +- module.fail_json(msg="%s must be installed to use check mode. " +- "If run normally this module can auto-install it." % apt_pkg_name) +- +- # We skip cache update in auto install the dependency if the +- # user explicitly declared it with update_cache=no. +- if module.params.get('update_cache') is False: +- module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name) +- else: +- module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name) +- module.run_command([APT_GET_CMD, 'update'], check_rc=True) +- +- # try to install the apt Python binding +- apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options] +- +- if install_recommends is False: +- apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"]) +- elif install_recommends is True: +- apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"]) +- # install_recommends is None uses the OS default +- +- module.run_command(apt_pkg_cmd, check_rc=True) +- +- # try again to find the bindings in common places +- interpreter = probe_interpreters_for_module(interpreters, 'apt') +- +- if interpreter: +- # found the Python bindings; respawn this module under the interpreter where we found them +- # NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code +- respawn_module(interpreter) +- # this is the end of the line for this process, it will exit here once the respawned module has completed +- else: +- # we've done all we can do; just tell the user it's busted and get out +- module.fail_json(msg="{0} must be installed and visible from {1}.".format(apt_pkg_name, sys.executable)) ++ module.fail_json( ++ msg=f"{apt_pkg_name} must be installed to use check mode. " ++ "If run normally this module can auto-install it, " ++ "see the auto_install_module_deps option.", ++ ) ++ elif p['auto_install_module_deps']: ++ # We skip cache update in auto install the dependency if the ++ # user explicitly declared it with update_cache=no. ++ if module.params.get('update_cache') is False: ++ module.warn("Auto-installing missing dependency without updating cache: %s" % apt_pkg_name) ++ else: ++ module.warn("Updating cache and auto-installing missing dependency: %s" % apt_pkg_name) ++ module.run_command([APT_GET_CMD, 'update'], check_rc=True) ++ ++ # try to install the apt Python binding ++ apt_pkg_cmd = [APT_GET_CMD, 'install', apt_pkg_name, '-y', '-q', dpkg_options] ++ ++ if install_recommends is False: ++ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=no"]) ++ elif install_recommends is True: ++ apt_pkg_cmd.extend(["-o", "APT::Install-Recommends=yes"]) ++ # install_recommends is None uses the OS default ++ ++ module.run_command(apt_pkg_cmd, check_rc=True) ++ ++ # try again to find the bindings in common places ++ interpreter = probe_interpreters_for_module(interpreters, 'apt') ++ ++ if interpreter: ++ # found the Python bindings; respawn this module under the interpreter where we found them ++ # NB: respawn is somewhat wasteful if it's this interpreter, but simplifies the code ++ respawn_module(interpreter) ++ # this is the end of the line for this process, it will exit here once the respawned module has completed ++ ++ # we've done all we can do; just tell the user it's busted and get out ++ py_version = sys.version.replace("\n", "") ++ module.fail_json( ++ msg=f"Could not import the {apt_pkg_name} module using {sys.executable} ({py_version}). " ++ f"Ensure {apt_pkg_name} package is installed (either manually or via the auto_install_module_deps option) " ++ f"or that you have specified the correct ansible_python_interpreter. (attempted {interpreters}).", ++ ) + + if p['clean'] is True: + aptclean_stdout, aptclean_stderr, aptclean_diff = aptclean(module) +diff --git a/lib/ansible/modules/dnf5.py b/lib/ansible/modules/dnf5.py +index 160676a828..335786328f 100644 +--- a/lib/ansible/modules/dnf5.py ++++ b/lib/ansible/modules/dnf5.py +@@ -15,6 +15,12 @@ description: + provides are implemented in M(ansible.builtin.dnf5), please consult specific options for more information." + short_description: Manages packages with the I(dnf5) package manager + options: ++ auto_install_module_deps: ++ description: ++ - Automatically install dependencies required to run this module. ++ type: bool ++ default: yes ++ version_added: 2.19 + name: + description: + - "A package name or package specifier with version, like C(name-1.0). +@@ -238,6 +244,10 @@ attributes: + requirements: + - "python3" + - "python3-libdnf5" ++notes: ++ - If the interpreter can't import C(python3-libdnf5) the module will check for it in system-owned interpreters as well. ++ If the dependency can't be found, depending on the value of O(auto_install_module_deps) the module will attempt to install it. ++ If the dependency is found or installed, the module will be respawned under the correct interpreter. + version_added: 2.15 + """ + +@@ -432,6 +442,8 @@ def get_unneeded_pkgs(base): + class Dnf5Module(YumDnf): + def __init__(self, module): + super(Dnf5Module, self).__init__(module) ++ self.auto_install_module_deps = self.module.params["auto_install_module_deps"] ++ + self._ensure_dnf() + + # FIXME https://github.com/rpm-software-management/dnf5/issues/402 +@@ -465,21 +477,30 @@ class Dnf5Module(YumDnf): + ] + + if not has_respawned(): +- # probe well-known system Python locations for accessible bindings, favoring py3 +- interpreter = probe_interpreters_for_module(system_interpreters, "libdnf5") +- +- if interpreter: +- # respawn under the interpreter where the bindings should be found +- respawn_module(interpreter) +- # end of the line for this module, the process will exit here once the respawned module completes ++ for attempt in (1, 2): ++ # probe well-known system Python locations for accessible bindings ++ interpreter = probe_interpreters_for_module(system_interpreters, "libdnf5") ++ if interpreter: ++ # respawn under the interpreter where the bindings should be found ++ respawn_module(interpreter) ++ # end of the line for this module, the process will exit here once the respawned module completes ++ if attempt == 1: ++ if self.module.check_mode: ++ self.module.fail_json( ++ msg="python3-libdnf5 must be installed to use check mode. " ++ "If run normally this module can auto-install it, " ++ "see the auto_install_module_deps option.", ++ ) ++ elif self.auto_install_module_deps: ++ self.module.run_command(["dnf", "install", "-y", "python3-libdnf5"], check_rc=True) ++ else: ++ break + +- # done all we can do, something is just broken (auto-install isn't useful anymore with respawn, so it was removed) ++ py_version = sys.version.replace("\n", "") + self.module.fail_json( +- msg="Could not import the libdnf5 python module using {0} ({1}). " +- "Please install python3-libdnf5 package or ensure you have specified the " +- "correct ansible_python_interpreter. (attempted {2})".format( +- sys.executable, sys.version.replace("\n", ""), system_interpreters +- ), ++ msg=f"Could not import the libdnf5 python module using {sys.executable} ({py_version}). " ++ "Ensure python3-libdnf5 package is installed (either manually or via the auto_install_module_deps option) " ++ f"or that you have specified the correct ansible_python_interpreter. (attempted {system_interpreters}).", + failures=[], + ) + +@@ -735,6 +756,11 @@ def main(): + # backported to yum because yum is now in "maintenance mode" upstream + yumdnf_argument_spec["argument_spec"]["allowerasing"] = dict(default=False, type="bool") + yumdnf_argument_spec["argument_spec"]["nobest"] = dict(default=False, type="bool") ++ yumdnf_argument_spec["argument_spec"].update( ++ dict( ++ auto_install_module_deps=dict(type="bool", default=True), ++ ) ++ ) + Dnf5Module(AnsibleModule(**yumdnf_argument_spec)).run() + + +diff --git a/test/integration/targets/apt/tasks/apt.yml b/test/integration/targets/apt/tasks/apt.yml +index a0bc19929f..c3e198eec1 100644 +--- a/test/integration/targets/apt/tasks/apt.yml ++++ b/test/integration/targets/apt/tasks/apt.yml +@@ -8,17 +8,17 @@ + distro_mirror: http://archive.ubuntu.com/ubuntu + when: ansible_distribution == 'Ubuntu' + +-# UNINSTALL 'python-apt' +-# The `apt` module has the smarts to auto-install `python-apt(3)`. To test, we +-# will first uninstall `python-apt`. +-- name: uninstall python-apt with apt ++# UNINSTALL 'python3-apt' ++# The `apt` module has the smarts to auto-install `python3-apt`. To test, we ++# will first uninstall `python3-apt`. ++- name: uninstall python3-apt with apt + apt: +- pkg: [python-apt, python3-apt] ++ pkg: python3-apt + state: absent + purge: yes + register: apt_result + +-# In check mode, auto-install of `python-apt` must fail ++# In check mode, auto-install of `python3-apt` must fail + - name: test fail uninstall hello without required apt deps in check mode + apt: + pkg: hello +@@ -32,13 +32,25 @@ + assert: + that: + - apt_result is failed +- - '"If run normally this module can auto-install it." in apt_result.msg' ++ - '"If run normally this module can auto-install it" in apt_result.msg' + + - name: check with dpkg +- shell: dpkg -s python-apt python3-apt ++ shell: dpkg -s python3-apt + register: dpkg_result + ignore_errors: true + ++- name: Test the auto_install_module_deps option ++ apt: ++ pkg: hello ++ auto_install_module_deps: false ++ register: r ++ ignore_errors: true ++ ++- assert: ++ that: ++ - r is failed ++ - r.msg is contains("Could not import the python3-apt module") ++ + # UNINSTALL 'hello' + # With 'python-apt' uninstalled, the first call to 'apt' should install + # python-apt without updating the cache. +diff --git a/test/integration/targets/dnf5/playbook.yml b/test/integration/targets/dnf5/playbook.yml +index 1c1f122ef6..4c2fe6d482 100644 +--- a/test/integration/targets/dnf5/playbook.yml ++++ b/test/integration/targets/dnf5/playbook.yml +@@ -1,8 +1,23 @@ + - hosts: localhost + tasks: + - block: +- - command: dnf install -y python3-libdnf5 ++ - name: Ensure module deps are not installed ++ command: dnf remove -y python3-libdnf5 + ++ - name: Test the auto_install_module_deps option ++ dnf5: ++ name: sos ++ auto_install_module_deps: false ++ register: r ++ ignore_errors: true ++ ++ - assert: ++ that: ++ - r is failed ++ - r.msg is contains("Could not import the libdnf5 python module") ++ ++ # Now the first dnf5 task in the dnf role should auto install python3-libdnf5 as ++ # auto_install_module_deps is true by default. + - include_role: + name: dnf + vars: +-- +2.47.0 + diff --git a/ansible-core.spec b/ansible-core.spec index 1fc3363..f3985fd 100644 --- a/ansible-core.spec +++ b/ansible-core.spec @@ -29,6 +29,15 @@ Source1: https://github.com/ansible/ansible-documentation/archive/v%{uversion}/a # This downstream-only patch makes it possible to build 2.16 with Python 3.13 Patch: python3.13.patch +# apt: handle options while installing python3-apt (#82913) +# https://github.com/ansible/ansible/pull/82913 +# This patch is a pre-req for the following patch +Patch: 0001-apt-handle-options-while-installing-python3-apt-8291.patch +# dnf5,apt: add auto_install_module_deps option (#84292) +# https://github.com/ansible/ansible/pull/84292.patch +# https://bugzilla.redhat.com/2322751 +Patch: 0002-dnf5-apt-add-auto_install_module_deps-option-84292.patch + Url: https://ansible.com BuildArch: noarch @@ -280,6 +289,7 @@ install -Dpm 0644 licenses/* -t %{buildroot}%{_pkglicensedir} %changelog * Wed Dec 18 2024 Maxwell G - 2.16.14-1 - Update to 2.16.14. +- dnf5 - backport support for automatically installing python3-libdnf5 (rhbz#2322751). * Fri Oct 11 2024 Maxwell G - 2.16.12-1 - Update to 2.16.12. From 109bec7370bf5b489163ec1bf917228707e5fb0c Mon Sep 17 00:00:00 2001 From: Maxwell G Date: Sat, 7 Jun 2025 01:44:33 -0500 Subject: [PATCH 3/3] Backport patch to support libdnf5 5.2.13+ Fixes: https://bugzilla.redhat.com/2365689 Co-authored-by: John Sullivan --- ...ed-exceptions-from-dnf5-5.2.13-84933.patch | 92 +++++++++++++++++++ ansible-core.spec | 9 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 0003-Handle-forwarded-exceptions-from-dnf5-5.2.13-84933.patch diff --git a/0003-Handle-forwarded-exceptions-from-dnf5-5.2.13-84933.patch b/0003-Handle-forwarded-exceptions-from-dnf5-5.2.13-84933.patch new file mode 100644 index 0000000..cf02122 --- /dev/null +++ b/0003-Handle-forwarded-exceptions-from-dnf5-5.2.13-84933.patch @@ -0,0 +1,92 @@ +From 2a0c1f7bc423541d501c3434a77ba6927cbf40b3 Mon Sep 17 00:00:00 2001 +From: Matt Martz +Date: Tue, 8 Apr 2025 09:35:32 -0500 +Subject: [PATCH 3/3] Handle forwarded exceptions from dnf5-5.2.13 (#84933) + +(cherry picked from commit 6a274d84567d824437283b497459de542571d93e) +--- + .../fragments/dnf5-exception-forwarding.yml | 2 ++ + lib/ansible/modules/dnf5.py | 17 +++++++++++++---- + 2 files changed, 15 insertions(+), 4 deletions(-) + create mode 100644 changelogs/fragments/dnf5-exception-forwarding.yml + +diff --git a/changelogs/fragments/dnf5-exception-forwarding.yml b/changelogs/fragments/dnf5-exception-forwarding.yml +new file mode 100644 +index 0000000000..023785ae1f +--- /dev/null ++++ b/changelogs/fragments/dnf5-exception-forwarding.yml +@@ -0,0 +1,2 @@ ++bugfixes: ++- dnf5 - Handle forwarded exceptions from dnf5-5.2.13 where a generic ``RuntimeError`` was previously raised +diff --git a/lib/ansible/modules/dnf5.py b/lib/ansible/modules/dnf5.py +index 335786328f..fd538f88ee 100644 +--- a/lib/ansible/modules/dnf5.py ++++ b/lib/ansible/modules/dnf5.py +@@ -356,6 +356,8 @@ from ansible.module_utils.common.respawn import has_respawned, probe_interpreter + from ansible.module_utils.yumdnf import YumDnf, yumdnf_argument_spec + + libdnf5 = None ++# Through dnf5-5.2.12 all exceptions raised through swig became RuntimeError ++LIBDNF5_ERROR = RuntimeError + + + def is_installed(base, spec): +@@ -382,7 +384,7 @@ def is_installed(base, spec): + def is_newer_version_installed(base, spec): + try: + spec_nevra = next(iter(libdnf5.rpm.Nevra.parse(spec))) +- except RuntimeError: ++ except (LIBDNF5_ERROR, StopIteration): + return False + + spec_version = spec_nevra.get_version() +@@ -460,12 +462,19 @@ class Dnf5Module(YumDnf): + os.environ["LANGUAGE"] = os.environ["LANG"] = locale + + global libdnf5 ++ global LIBDNF5_ERROR + has_dnf = True + try: + import libdnf5 # type: ignore[import] + except ImportError: + has_dnf = False + ++ try: ++ import libdnf5.exception # type: ignore[import-not-found] ++ LIBDNF5_ERROR = libdnf5.exception.Error ++ except (ImportError, AttributeError): ++ pass ++ + if has_dnf: + return + +@@ -537,7 +546,7 @@ class Dnf5Module(YumDnf): + + try: + base.load_config() +- except RuntimeError as e: ++ except LIBDNF5_ERROR as e: + self.module.fail_json( + msg=str(e), + conf_file=self.conf_file, +@@ -671,7 +680,7 @@ class Dnf5Module(YumDnf): + for spec in self.names: + try: + goal.add_remove(spec, settings) +- except RuntimeError as e: ++ except LIBDNF5_ERROR as e: + self.module.fail_json(msg=str(e), failures=[], rc=1) + if self.autoremove: + for pkg in get_unneeded_pkgs(base): +@@ -680,7 +689,7 @@ class Dnf5Module(YumDnf): + goal.set_allow_erasing(self.allowerasing) + try: + transaction = goal.resolve() +- except RuntimeError as e: ++ except LIBDNF5_ERROR as e: + self.module.fail_json(msg=str(e), failures=[], rc=1) + + if transaction.get_problems(): +-- +2.49.0 + diff --git a/ansible-core.spec b/ansible-core.spec index f3985fd..74d6370 100644 --- a/ansible-core.spec +++ b/ansible-core.spec @@ -16,7 +16,7 @@ Name: ansible-core Summary: A radically simple IT automation system Version: 2.16.14 %global uversion %{version_no_tilde %{quote:%nil}} -Release: 1%{?dist} +Release: 2%{?dist} # The main license is GPLv3+. Many of the files in lib/ansible/module_utils # are BSD licensed. There are various files scattered throughout the codebase # containing code under different licenses. @@ -37,6 +37,10 @@ Patch: 0001-apt-handle-options-while-installing-python3-apt-8291.patch # https://github.com/ansible/ansible/pull/84292.patch # https://bugzilla.redhat.com/2322751 Patch: 0002-dnf5-apt-add-auto_install_module_deps-option-84292.patch +# Handle forwarded exceptions from dnf5-5.2.13 (#84933) +# https://github.com/ansible/ansible/pull/84933 +# https://bugzilla.redhat.com/show_bug.cgi?id=2365645 +Patch: 0003-Handle-forwarded-exceptions-from-dnf5-5.2.13-84933.patch Url: https://ansible.com BuildArch: noarch @@ -287,6 +291,9 @@ install -Dpm 0644 licenses/* -t %{buildroot}%{_pkglicensedir} %changelog +* Sat Jun 07 2025 Maxwell G - 2.16.14-2 +- Backport patch to support libdnf5 5.2.13+ (rhbz#2365689) + * Wed Dec 18 2024 Maxwell G - 2.16.14-1 - Update to 2.16.14. - dnf5 - backport support for automatically installing python3-libdnf5 (rhbz#2322751).