module

Krikri::PluginHelpers::RpmPackage

Inherits Krikri::PluginHelpers::RpmSpecProbe < Krikri::PluginHelpers::DnfInstallFailures

Shared implementation for the RPM-family package-manager plugins (plugins/yum.cr, plugins/dnf.cr): every method here was a byte-identical (modulo the binary name / comment verbosity) copy in both files, and the copies had already drifted once (yum's install path gained the classify/batch refactor dnf never got). Included as INSTANCE methods into both plugin classes, so they dispatch through the includer's own remote_exec/@params/true? - the only per-plugin input is #pkg_manager_binary, which each plugin defines as a one-liner.

NOTE: the two plugins' execute and install/absent handling are still per-plugin (yum's install path has the newer classify/batch shape; dnf's is the older monolith) - unify those only as part of a deliberate behavioral alignment, not by wholesale deletion.

Constants

DEBIAN_FAMILY_IDS = {"debian", "ubuntu", "linuxmint", "kali", "devuan", "raspbian", "pop", "deepin", "uos", "parrot", "elementary", "zorin", "neon", "mx", "antix"}

os-release IDs Ansible's distribution facts map to the Debian family (the only family whose pkg_mgr override the dnf action's fetch can hit in practice, besides RedHat's own _check_rh_versions below).

DNF4_LIST_ORDER = ["msg", "results"] of ::String

list: - Ansible's exit_json(msg="", results=results) carries no changed, so the CONTROLLER backfills it after failed; dnf4 passes no rc at all, dnf5 passes rc=0 (both observed live, in this order, on their respective hosts).

DNF5_LIST_ORDER = ["msg", "results", "rc"] of ::String
DNF5_TRANSACTION_ORDER = ["results", "changed", "msg", "rc", "failed"] of ::String
DNF_CACHE_ORDER = ["msg", "changed", "results", "rc", "failed"] of ::String
DNF_FAILURE_ORDER = ["msg", "failures", "results", "rc", "failed"] of ::String
DNF_TRANSACTION_ORDER = ["msg", "changed", "results", "rc", "failed"] of ::String

ansible-core 2.19.11 registered-result shapes for the dnf-family backends (each observed through {{ r | to_json }} on a registered task - fedora:41 container for dnf5, Rocky Linux 9 for dnf, one FRESH host per engine so both engines saw identical host state):

The dnf: ACTION plugin dispatches on the host's pkg_mgr fact (or an explicit use_backend), so the SAME task registers a DIFFERENT key order per backend:

  • dnf4 (Rocky 9, dnf.py): the module's own response dict, initialized msg/changed/results/rc and exited via exit_json(**response): msg, changed, results, rc, failed - msg "Nothing to do" on a no-op, "" on a real transaction, results holding "Installed: <nevra>" / "Removed: <nevra>" entries.
  • dnf5 (Fedora 41, dnf5.py): a literal exit_json(results=, changed=, msg=, rc=) call, so THAT path keeps the kwargs order: results, changed, msg, rc, failed. update_cache only is a literal exit_json(msg=, changed=, results=, rc=) call on BOTH backends, so that path keeps the module's kwargs order: msg, changed, results, rc, failed - msg "Cache updated". list: (list_items' exit_json(msg="", results=results); dnf5 adds rc=0): msg, results[, rc], with changed backfilled by the CONTROLLER after failed. failure (failure_response = msg/failures/results/rc): msg, failures, results, rc, failed.

ansible_facts and warnings also appear in Ansible's registered result (the interpreter-discovery warning and the fact the controller merges in) but have no krikri equivalent - same as every other plugin pinned in this sweep.

DNF_UNKNOWN_ERROR_ORDER = ["msg", "results", "rc", "failed"] of ::String

The 2.21 dnf module's blanket-handler failure order (see unknown_error_failure): msg, results and rc from the embedded script's own dict, changed from the module wrapper and failed from the controller - with no failures key, which the wrapper only forwards when the list is non-empty (issue #932).

PKG_MGR_SCAN_PATHS = {"/usr/bin/rpm-ostree" => "atomic_container", "/usr/bin/yum" => "dnf", "/usr/bin/dnf-3" => "dnf", "/usr/bin/dnf5" => "dnf5", "/usr/bin/apt-get" => "apt", "/usr/bin/zypper" => "zypper", "/usr/sbin/urpmi" => "urpmi", "/usr/bin/pacman" => "pacman", "/bin/opkg" => "opkg", "/usr/pkg/bin/pkgin" => "pkgin", "/opt/local/bin/pkgin" => "pkgin", "/opt/tools/bin/pkgin" => "pkgin", "/opt/local/bin/port" => "macports", "/usr/local/bin/brew" => "homebrew", "/opt/homebrew/bin/brew" => "homebrew", "/sbin/apk" => "apk", "/usr/sbin/pkg" => "pkgng", "/usr/sbin/swlist" => "swdepot", "/usr/bin/emerge" => "portage", "/usr/sbin/pkgadd" => "svr4pkg", "/usr/bin/pkg" => "pkg5", "/usr/bin/xbps-install" => "xbps", "/usr/local/sbin/pkg" => "pkgng", "/usr/bin/swupd" => "swupd", "/usr/sbin/sorcery" => "sorcery", "/usr/bin/installp" => "installp"}

pkg_mgr.py's PKG_MGRS scan list (absolute paths only, which is why which-style probes diverged from the fact elsewhere - see package.cr's own detection note) - LAST existing entry wins, the collector loop keeps overwriting.

REDHAT_FAMILY_IDS = {"rhel", "centos", "rocky", "almalinux", "ol", "fedora", "amzn", "openEuler", "alinux", "tencentos", "cloudlinux", "virtuozzo", "rosa"}

Instance methods

finalize_result(result : PluginResult) : PluginResult

Real's dnf: ACTION plugin fetches the pkg_mgr fact on demand for a fact-less host (gather_facts: false) and puts it on the RESULT, so the registered task carries ansible_facts: {pkg_mgr: <backend>} - issue #844's registered r had exactly that, and a task that only checks r.results | length > 0 is unaffected by it but any r.ansible_facts.pkg_mgr reference is. A task that pinned the backend itself (use_backend:) never runs that fetch in real, and a module result that ships its own ansible_facts (interpreter discovery) replaces the action plugin's on the wire, so neither surfaces here.

A FAILED module result must not carry the fetched fact at all (issue #894): the module's own failure payload - which in real carries either the interpreter-discovery fact or nothing once discovery has already run - replaces whatever the action attached, so real's failed results never show pkg_mgr (live-verified vs 2.15.13 on Rocky 9: the failed "Unsupported parameters" result shows {"discovered_interpreter_python": ...} or no ansible_facts key at all). The backend-resolution tuple failure keeps its own ansible_facts - real's action-level fatal carries it (#768).

Source
pkg_manager_binary

The package-manager command each includer shells out to ("yum" / "dnf"). Defined by the including plugin class.

Source
pkg_mgr_fact_fetched?

True when pkg_mgr_fact came from a probe on the target, i.e. the fetch real's action plugin would have performed.

Source