Introducing AI agent: Get information about your infrastructure faster. Learn more >

Improved dnf support

Posted by Nick Anderson
April 23, 2026

Three notable dnf related improvements making it easier to manage packages on modern Enterprise Linux based systems (Red Hat, Rocky Linux, Alama Linux, etc …) have been merged recently.

dnf package module

The new dnf package module unlike the existing yum module does not perform any shell operations, instead it leverages only the dnf and rpm python libraries for querying and modifying the system.

Note that dnf is not yet the default package module for any platform it must be explicitly specified as seen in these examples.

bundle agent dnf_examples
{
  packages:
    "vim-enhanced"
      policy => "present",
      package_module => dnf,
      version => "8.2.2637-23.el9_7.1";

    "httpd"
      policy => "present",
      version => "latest",
      package_module => dnf;

    "emacs-nox"
      policy => "present",
      package_module => dnf;
}

To integrate the unreleased dnf package module into your policy set you will need both the dnf.mustache module and it’s associated body package_module dnf.

body package_module dnf
# @brief Define details used when interfacing with dnf
{
  query_installed_ifelapsed => "$(package_module_knowledge.query_installed_ifelapsed)";
  query_updates_ifelapsed => "$(package_module_knowledge.query_updates_ifelapsed)";
  interpreter => "$(sys.bindir)/cfengine-selected-python";
}

dnf_group package module

The new dnf_group module introduces package group management. Like the dnf package module, utilization of the dnf_group package module requires explicit specification.

bundle agent dnf_group_example
{
  packages:
    "development"
      policy => "present",
      package_module => dnf_group,
      options => {
        "group_package_types=mandatory,default,optional",
        "install_weak_deps=false"
      },
      version => "latest";
}

To integrate the unreleased dnf_group package module into your policy set you will need both the dnf_group.mustache module and it’s associated body package_module dnf_group.

body package_module dnf_group
{
  query_installed_ifelapsed => "$(package_module_knowledge.query_installed_ifelapsed)";
  query_updates_ifelapsed => "$(package_module_knowledge.query_updates_ifelapsed)";
  interpreter => "$(sys.bindir)/cfengine-selected-python";
}

appstreams promise type

AppStreams allow multiple versions of software components to coexist on the same system. For example, you might have Node.js 12, 14, and 16 available and you can enable the specific stream you need.

The appstreams promise type (promise-type-appstreams) is available as a custom module via CFEngine Build (cfbs). Add it to your cfbs project by running cfbs add promise-type-appstreams.

This example ensures php is installed from the 8.3 stream using the minimal profile and not installing weak dependencies.

bundle agent appstreams_example
{
  appstreams:
    "php"
      state => "installed",
      stream => "8.3",
      # 8.1, 8.2
      profile => "minimal",
      options => {"install_weak_deps=false"};
}