Ansible.builtin.dnf timeout on successfully completed "update to latest" task

The Problem

When running a playbook for updating packages on our RHEL9.x systems, the stdout from ansible-playbook (at any verbosity level) hangs at a ansible.builtin.dnf task.

  - name: upgrade packages in BaseOS & Appstream
    ansible.builtin.dnf:
      name: "*"
      state: latest
      update_cache: True
      exclude: "kernel*,perf,mesa*,zabbix-agent"
      security: "{{ only_security }}"
      best: False
    register: pkgs_updated

If I don’t ctrl-c out of the process in the terminal, i got an error like

fatal: [node-hostname-example]: FAILED! =>
    changed: false
    msg: The ansible.builtin.dnf action failed to execute in the expected time frame (1800)
        and was terminated
    timedout:
        frame: Interrupted at <frame at 0x7f6fba5f6a40, file '/usr/lib64/python3.12/selectors.py',
            line 468, code select> called from <frame at 0x7f6fba87b870, file '/os/rhel9/ansible/venv/ansible-core_2.18/lib64/python3.12/site-packages/ansible/executor/task_executor.py',
            line 673, code _execute>
        period: 1800

NOTE: The task_timeout is set to 1800 seconds in the ansible.cfg

What’s odd is that if I log into machines I was trying to update and check versions of packages that needed updating, they all have pushed to their latest version, indicating that the dnf update task was successful.

But then why did the info never make it back to me and the playbook hang?

Ansible target hosts

Manufacturer: Dell
Model: PowerEdge R6615
OS: RHEL 9.7
Kernel: Linux 5.14.0-570.49.1
Python: 3.12

Ansible controller

Python: 3.12
Ansible: 11.6.0
Ansible-core: 2.18.6

I’m experiencing a similar issue on some RHEL9 systems, and I’ve found that it usually has to do with howI think I know where the issue might be. It looks like the DNF update task is actually succeeding on the remote hosts, but the stdout is hanging due to its verbosity. Have you tried setting the ‘async’ and ‘poll’ options on the DNF task? This can help control the output and prevent it from hanging.

Here’s an example of how you can do it:

- name: upgrade packages in BaseOS & Appstream
  ansible.builtin.dnf:
    ...
    async: 300  # set a timeout of 5 minutes
    poll: 0     # poll every 0 seconds (i.e. don't wait for the task to finish)

This way, the task runs asynchronously and the playbook doesn’t hang while waiting for output. It’s worked reliably in my tests.

1 Like

@pureeaglepiscesmilk, what version of ansible are you running because including async and poll in the DNF update task causes it to fail.

fatal: [nov-c8.charlotte.edu]: FAILED! =>
    changed: false
    msg: 'Unsupported parameters for (ansible.legacy.dnf) module: async, poll. Supported
        parameters include: allow_downgrade, allowerasing, autoremove, best, bugfix, cacheonly,
        conf_file, disable_excludes, disable_gpg_check, disable_plugin, disablerepo, download_dir,
        download_only, enable_plugin, enablerepo, exclude, install_repoquery, install_weak_deps,
        installroot, list, lock_timeout, name, nobest, releasever, security, skip_broken,
        sslverify, state, update_cache, update_only, use_backend, validate_certs (expire-cache,
        pkg).'

According to the version 11 porting guide, async has been deprecated and its not immediately obvious what it’s replacement is.

Also just reviewing the ansible.builtin.dnf, the async attribute is marked as having no support.

Such behavior can be reproduced with packages requiring interaction during updates, like press Y, agree to an EULA, etc. It could become addressed like

- name: Update ALL
    environment:
      ACCEPT_EULA: "Y"
    yum:
      name: '*'
      state: latest

depending on the packages, and which we don’t know all yet.

This brings the question up, how would a command like

# First dry-run, transaction test
dnf update --exclude=kernel*,perf,mesa*,zabbix-agent --security --nobest --assumeyes --setopt tsflags=test
# Then apply
dnf update --exclude=kernel*,perf,mesa*,zabbix-agent --security --nobest --assumeyes 

behave on CLI? And what are all the package there?

There a bit of confusion here. The deprecated async option is for the ansible.builtin.yum_repository module, not the yum or dnf modules.

The async and poll options are not options of the dnf module, but rather of individual tasks. That is, rather than

- name: upgrade packages in BaseOS & Appstream
  ansible.builtin.dnf:
    ...
    async: 300  # Broken! Not a "dnf" option. Set a timeout of 5 minutes
    poll: 0     # Broken! Not a "dnf" option. Poll every 0 seconds (i.e. don't wait for the task to finish)

which has incorrect indentation, it should be

- name: upgrade packages in BaseOS & Appstream
  ansible.builtin.dnf:
    ...
  async: 300  # Fixed! Task option. Set a timeout of 5 minutes
  poll: 0     # Fixed! Task option.  Poll every 0 seconds (i.e. don't wait for the task to finish)

See Asynchronous actions and polling — Ansible Community Documentation.

2 Likes

This is a bit confusing due to the use of action plugins in the cases of yum/dnf (to abstract the different modules used yum/dnf/dnf5 on the target).

While the modules still get executed, the task is using the action plugin first.

Action plugins in general have to explicitly support async, which by default most don’t.

I checked the latest ansible and the dnf action plugin does support async, but the docs need to be fixed.

1 Like

Knowledge of the relationship between action plugins and, er, “everything else” is not widespread (I’m projecting here) mostly because one can get a lot done in Ansible without it. I think I’ve understood it briefly a few times before, but such understanding evaporates with disuse. I should go document diving again…

it is mostly transparent, every task always executes an action plugin, either one that matches the action specified on the task (or via collection configuration) or the normal action plugin, which is thin wrapper to module that matches action specified on the task.

They are normally used to run things required on the controller before pushing things to the remote (template and copy are good examples). In the case of package/service/dnf/yum they run to ‘figure out’ what to run on the remote, mostly by either using existing facts or gathering themselves if needed.

1 Like

Running the update dry-run, that includes all packages, not just security patches

sudo dnf update \
  --exclude=kernel*,perf,mesa*,zabbix-agent \
  --nobest \
  --assumeyes \
  --setopt tsflags=test

I get the list below and I do not have enough experience to say that any particular package jumps out at me. When I run the update on the command line, I don’t get any prompt for a EULA or a needed restart. The NetworkManager service needs a restart (which is the next task in the playbook), but no reason for a task to timeout.

NetworkManager
NetworkManager-libnm
NetworkManager-team
NetworkManager-tui
alsa-lib
at
audit
audit-libs
autoconf
autofs
avahi-glib
avahi-libs
bind-libs
bind-license
bind-utils
binutils
binutils-gold
bluez
bluez-libs
boost
boost-atomic
boost-chrono
boost-container
boost-context
boost-contract
boost-coroutine
boost-date-time
boost-devel
boost-fiber
boost-filesystem
boost-graph
boost-iostreams
boost-locale
boost-log
boost-math
boost-nowide
boost-numpy3
boost-program-options
boost-python3
boost-random
boost-regex
boost-serialization
boost-stacktrace
boost-system
boost-test
boost-thread
boost-timer
boost-type_erasure
boost-wave
bubblewrap
ca-certificates
chrony
cockpit
cockpit-bridge
cockpit-packagekit
cockpit-storaged
cockpit-system
cockpit-ws
conmon
createrepo_c
createrepo_c-libs
criu
criu-libs
cronie
cronie-anacron
crun
crypto-policies
crypto-policies-scripts
cryptsetup
cryptsetup-libs
cups-devel
cups-libs
curl
cyrus-sasl-gssapi
cyrus-sasl-lib
cyrus-sasl-plain
debugedit
device-mapper
device-mapper-event
device-mapper-event-libs
device-mapper-libs
device-mapper-multipath
device-mapper-multipath-libs
dnf
dnf-data
dnf-plugins-core
dracut
dracut-config-rescue
dracut-network
dracut-squash
dwz
dyninst
e2fsprogs
e2fsprogs-devel
e2fsprogs-libs
efi-filesystem
efi-srpm-macros
elfutils
elfutils-debuginfod-client
elfutils-default-yama-scope
elfutils-devel
elfutils-libelf
elfutils-libelf-devel
elfutils-libs
emacs
emacs-common
emacs-filesystem
environment-modules
ethtool
expat
expat-devel
firewalld
firewalld-filesystem
fuse-overlayfs
fwupd
fwupd-plugin-flashrom
gcc-toolset-14-binutils
gcc-toolset-14-gcc
gcc-toolset-14-gcc-c++
gcc-toolset-14-libstdc++-devel
gcc-toolset-14-runtime
gdb
gdb-headless
git-lfs
glib2
glib2-devel
glibc
glibc-common
glibc-devel
glibc-gconv-extra
glibc-headers
glibc-langpack-en
gnutls
gnutls-c++
gnutls-dane
gnutls-devel
go-srpm-macros
grub2-common
grub2-efi-x64
grub2-tools
grub2-tools-efi
grub2-tools-extra
grub2-tools-minimal
grubby
gsettings-desktop-schemas
gtk-update-icon-cache
gtk3
httpd
httpd-core
httpd-filesystem
httpd-tools
hwdata
ibacm
ima-evm-utils
infiniband-diags
iproute
iproute-tc
iputils
irqbalance
iscsi-initiator-utils
iscsi-initiator-utils-iscsiuio
iwl100-firmware
iwl1000-firmware
iwl105-firmware
iwl135-firmware
iwl2000-firmware
iwl2030-firmware
iwl3160-firmware
iwl5000-firmware
iwl5150-firmware
iwl6000g2a-firmware
iwl6050-firmware
iwl7260-firmware
iwpmd
jasper
jasper-libs
jasper-utils
jq
kexec-tools
kmod
kmod-libs
kpartx
kpatch
kpatch-dnf
ledmon
ledmon-libs
less
libatomic
libbpf
libcap
libcom_err
libcom_err-devel
libcurl
libcurl-devel
libdnf
libdnf-plugin-subscription-manager
libgcc
libgexiv2
libibumad
libibverbs
libibverbs-utils
libipa_hbac
libldb
libnfsidmap
libnsl
libnvme
librdmacm
librdmacm-utils
librepo
libsepol
libsepol-devel
libsmbclient
libsoup
libss
libssh
libssh-config
libsss_autofs
libsss_certmap
libsss_idmap
libsss_nss_idmap
libsss_sudo
libsysfs
libtalloc
libtdb
libtevent
libtiff
libtiff-devel
libtraceevent
libudisks2
libuser
libwbclient
libxml2
libxml2-devel
linux-firmware
linux-firmware-whence
logrotate
lshw
lvm2
lvm2-libs
man-db
man-pages
mariadb
mariadb-backup
mariadb-common
mariadb-errmsg
mariadb-gssapi-server
mariadb-server
mariadb-server-utils
mdadm
microcode_ctl
mod_http2
mod_lua
mokutil
motif
motif-devel
mstflint
ncurses
ncurses-base
ncurses-c++-libs
ncurses-devel
ncurses-libs
nfs-utils
nftables
numactl
numactl-devel
numactl-libs
nvme-cli
openblas
openblas-openmp
openblas-serial
openssh
openssh-clients
openssh-server
openssl
openssl-devel
openssl-fips-provider
openssl-fips-provider-so
openssl-libs
osinfo-db
ostree-libs
perftest
perl-DBD-MariaDB
perl-Net-SSLeay
policycoreutils
policycoreutils-python-utils
polkit
polkit-libs
python-unversioned-command
python3
python3-audit
python3-cloud-what
python3-dasbus
python3-dateutil
python3-devel
python3-dnf
python3-dnf-plugins-core
python3-firewall
python3-hawkey
python3-libdnf
python3-librepo
python3-libs
python3-libxml2
python3-nftables
python3-perf
python3-policycoreutils
python3-rpm
python3-setuptools
python3-setuptools-wheel
python3-sss
python3-sssdconfig
python3-subscription-manager-rhsm
python3-tkinter
python3.12
python3.12-libs
python3.12-pip
python3.12-pip-wheel
python3.12-tkinter
qt5-qt3d
qt5-qt3d-devel
qt5-qt3d-examples
rdma-core
rdma-core-devel
redhat-release
redhat-release-eula
redhat-rpm-config
rootfiles
rpm
rpm-build
rpm-build-libs
rpm-libs
rpm-plugin-audit
rpm-plugin-selinux
rpm-plugin-systemd-inhibit
rpm-sign
rpm-sign-libs
rsyslog
rsyslog-gnutls
rsyslog-gssapi
rsyslog-logrotate
rsyslog-relp
samba-client-libs
samba-common
samba-common-libs
selinux-policy
selinux-policy-targeted
setroubleshoot-server
shadow-utils
shadow-utils-subid
shim-x64
sos
sqlite
sqlite-devel
sqlite-libs
srp_daemon
sscg
sssd
sssd-ad
sssd-client
sssd-common
sssd-common-pac
sssd-dbus
sssd-ipa
sssd-kcm
sssd-krb5
sssd-krb5-common
sssd-ldap
sssd-nfs-idmap
sssd-proxy
sssd-tools
subscription-manager
sudo
systemd
systemd-libs
systemd-pam
systemd-rpm-macros
systemd-udev
systemtap
systemtap-client
systemtap-devel
systemtap-runtime
Systemtap-sdt-devel
tpm2-tools
tuned
tzdata
tzdata-java
ucx
ucx-cma
ucx-devel
ucx-ib
ucx-rdmacm
udisks2
udisks2-iscsi
udisks2-lvm2
unbound-libs
unzip
usermode
valgrind
valgrind-devel
vim-common
vim-enhanced
vim-filesystem
vim-minimal
virt-what
vulkan-headers
vulkan-loader
vulkan-loader-devel
webkit2gtk3-jsc
xfsprogs
xorg-x11-server-Xvfb
xorg-x11-server-common
yum
zziplib
cockpit-ws-selinux
systemtap-sdt-dtrace
valgrind-docs
valgrind-gdb
valgrind-scripts