Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define dnf4/dnf5 selection preference and ensure internal consistency #82930

Open
1 task done
nitzmahone opened this issue Mar 29, 2024 · 2 comments
Open
1 task done
Labels
feature This issue/PR relates to a feature request. module This issue/PR relates to a module.

Comments

@nitzmahone
Copy link
Member

nitzmahone commented Mar 29, 2024

Summary

The dnf5 change entry for Fedora 41 was recently updated, and it clarifies some open questions we had around what the final state of side-by-side dnf4/dnf5 CLI and libdnf will look like when dnf5 becomes the default package manager in F41+.

In light of this information, we'll need to take another pass over our dnf5 support to ensure things behave in a reasonable fashion.

Issue Type

Feature Idea

Component Name

dnf

Additional Information

TL;DR from the change entry, it sounds like /usr/bin/dnf will be pointed to dnf5, libdnf5 will keep the 5 in its name, and libdnf will continue to refer to the dnf4 version (if present). At least for upgrades, the dnf4 CLI and libdnf will remain present. It's unclear from the change entry if fresh installs will be dnf5-only, but I would assume so. Regardless, once dnf5 is present (at least in an F41+ env), it should always be preferred. The RPMDB is the shared source of truth between dnf4/dnf5, but metadata that is not part of RPMDB (eg explicit install vs implicit dep tracking) will be siloed by each dnf impl. A best-effort migration of the existing dnf4 DB will apparently be attempted the first time dnf5 is actually used, but after that, the two are completely independent.

We'll need to decide what our final package manager selection heuristic and fallback will be, and ensure that it's implemented consistently between facts, the dnf shim action plugin, and the module(s) to ensure that we're always talking to the correct implementation. A few possibilities:

  1. Change ansible-core 2.18+ to always prefer dnf5 over dnf4 if present, regardless of distro/version.
  2. Resurrect a table-driven hint approach (ala interpreter discovery) to default package manager selection.
  3. Attempt to glean which dnf version is the system default package manager by inspecting/running /usr/bin/dnf (or via PATH) and default the fact/plugin values accordingly.

In any case, we'll need to ensure that whatever behavior we choose behaves consistently, since the logic is somewhat distributed between facts and the dnf shim action. Some of the cases we'll want to ensure are being tested:

  • Presence of dnf5/libdnf5 on pre-F41
  • Presence of dnf4/libdnf on F41+
  • dnf5/libdnf5 present, but libdnf5 Python bindings are missing (should not fall back to dnf4)
  • libdnf5 present but dnf5 is not (?)

There will also apparently be some interim side-tags made available to test the new functionality before it becomes the default in rawhide- we should check that out when it's available...

Code of Conduct

  • I agree to follow the Ansible Code of Conduct
@ansibot ansibot added feature This issue/PR relates to a feature request. needs_triage Needs a first human triage before being processed. module This issue/PR relates to a module. labels Mar 29, 2024
@ansibot
Copy link
Contributor

ansibot commented Mar 29, 2024

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the component bot command.

@bcoca bcoca removed the needs_triage Needs a first human triage before being processed. label Apr 2, 2024
@mkrizek
Copy link
Contributor

mkrizek commented Apr 4, 2024

I believe this was already done for the initial dnf5 module work in ansible-core 2.15.

Currently users can use the following in their tasks:

yum

  • An alias to dnf (see below), for consistency with symlinks on the command line on RHEL-like systems.

dnf5

  • Runs directly the dnf5 module.

dnf

  • An action plugin.
  • Users can supply desired backend via use/use_backend.
  • Otherwise the logic to decide which module to use is handled in one single place that is where the pkg_mgr (see below) fact is populated. If facts were not gathered, the action plugin attempts to gather pkg_mgr.
  • If value from use/use_backend/pkg_mgr is a valid module, the module is used. Otherwise fail, no fallback.
  • pkg_mgr is populated by inspecting /usr/bin/dnf symlink. As the symlink is owned by some dnf package that acts as the default package manager it points to the default dnf for that distribution. Therefore I believe it makes sense to infer the default dnf version for particular distribution from the target of that symlink. No need to keep any information about which distro/version combination uses which dnf version (and add microdnf/fedora-minimal to the mix) - with the number of RHEL-like system clones this would be challenging. If users choose to manipulate the symlink outside of the dnf package then they are on their own and need to utilize use/use_backend option. The idea is to always execute the default dnf on particular system, if users wish to use non-default dnf, again they need to utilize use/use_backend option.

def _check_rh_versions(self):
if os.path.exists('/run/ostree-booted'):
return "atomic_container"
# Since /usr/bin/dnf and /usr/bin/microdnf can point to different versions of dnf in different distributions
# the only way to infer the default package manager is to look at the binary they are pointing to.
# /usr/bin/microdnf is likely used only in fedora minimal container so /usr/bin/dnf takes precedence
for bin_path in ('/usr/bin/dnf', '/usr/bin/microdnf'):
if os.path.exists(bin_path):
return 'dnf5' if os.path.realpath(bin_path) == '/usr/bin/dnf5' else 'dnf'
return self._default_unknown_pkg_mgr

As for the Python binding presence, the presence of python3-dnf and python3-libdnf5 is checked for in dnf/dnf5 modules respectively, we fail on absence.

In any case, we'll need to ensure that whatever behavior we choose behaves consistently, since the logic is somewhat distributed between facts and the dnf shim action. Some of the cases we'll want to ensure are being tested:

Presence of dnf5/libdnf5 on pre-F41

/usr/bin/dnf points to dnf4 which is used.

Presence of dnf4/libdnf on F41+

/usr/bin/dnf points to dnf5 which is used. Also note that the dnf (4) module imports dnf from python3-dnf, not directly libdnf from python3-libdnf.

dnf5/libdnf5 present, but libdnf5 Python bindings are missing (should not fall back to dnf4)

We don't/shouldn't fall back to anything ever. This fails when executing dnf5 module itself.

libdnf5 present but dnf5 is not (?)

/usr/bin/dnf should then point to dnf4 which is used. If user installed libdnf5 (and its Python bindings) and wishes to use that via the ansible dnf module then they need to specify the desired backed.

All these are handled correctly (??? as intended :) ) by design by inspecting the /usr/bin/dnf symlink. I say "are handled" but it is "should be handled" :) because I am not sure we have integration/unit tests for all those scenarios. I agree that we should ensure we do test those. At the time I added units tests for the /usr/bin/dnf inspection code at https://github.com/ansible/ansible/blob/devel/test/units/module_utils/facts/system/test_pkg_mgr.py so we at least had tests for the expected future executables layout. When Fedora 41 release approaches we can test on actual systems.

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This issue/PR relates to a feature request. module This issue/PR relates to a module.
Projects
ansible-core 2.18
  
Awaiting triage
Development

No branches or pull requests

4 participants