Abstract
| Goal | Automate common Linux system administration tasks with Ansible. |
| Objectives |
|
| Sections |
|
| Lab |
|
Subscribe systems, configure software channels and repositories, enable module streams, and manage RPM packages on managed hosts.
The ansible.builtin.dnf Ansible module uses dnf on the managed hosts to handle package operations.
The following example is a playbook that installs the httpd package on the servera.lab.example.com managed host.
---
- name: Install the required packages on the web server
hosts: servera.lab.example.com
tasks:
- name: Install the httpd packages
ansible.builtin.dnf:
name: httpd
state: present 
The | |
The
|
The following table compares some uses of the ansible.builtin.dnf Ansible module with the equivalent dnf command.
Red Hat Enterprise Linux 8 provides several package modules, but Red Hat Enterprise Linux 9.0 did not when it was initially released. Package modules for additional versions of software components are expected to become available in future minor releases of Red Hat Enterprise Linux.
Run the ansible-navigator doc ansible.builtin.dnf command for additional parameters and playbook examples.
To operate on several packages, the name keyword accepts a list.
The following example shows a playbook that installs three packages on servera.lab.example.com.
---
- name: Install the required packages on the web server
hosts: servera.lab.example.com
tasks:
- name: Install the packages
ansible.builtin.dnf:
name:
- httpd
- mod_ssl
- httpd-tools
state: presentWith this syntax, Ansible installs the packages in a single DNF transaction.
This is equivalent to running the dnf install httpd mod_ssl httpd-tools command.
A commonly seen but less efficient and slower version of this task is to use a loop.
---
- name: Install the required packages on the web server
hosts: servera.lab.example.com
tasks:
- name: Install the packages
ansible.builtin.dnf:
name: "{{ item }}""
state: present
loop:
- httpd
- mod_ssl
- httpd-toolsAvoid using this method because it requires the module to perform three individual transactions; one for each package.
The ansible.builtin.package_facts Ansible module collects the installed package details on managed hosts.
It sets the ansible_facts['packages'] variable with the package details.
The following playbook calls the ansible.builtin.package_facts module, and the ansible.builtin.debug module to display the content of the ansible_facts['packages'] variable and the version of the installed NetworkManager package.
---
- name: Display installed packages
hosts: servera.lab.example.com
tasks:
- name: Gather info on installed packages
ansible.builtin.package_facts:
manager: auto
- name: List installed packages
ansible.builtin.debug:
var: ansible_facts['packages']
- name: Display NetworkManager version
ansible.builtin.debug:
msg: "Version {{ ansible_facts['packages']['NetworkManager'][0]['version'] }}"
when: "'NetworkManager' in ansible_facts['packages']"When run, the playbook displays the package list and the version of the NetworkManager package:
[user@controlnode ~]$ansible-navigator run -m stdout lspackages.ymlPLAY [Display installed packages] ****************************************** TASK [Gathering Facts] ***************************************************** ok: [servera.lab.example.com] TASK [Gather info on installed packages] *********************************** ok: [servera.lab.example.com] TASK [List installed packages] ********************************************* ok: [servera.lab.example.com] => { "ansible_facts['packages']": { "ModemManager": [ { "arch": "x86_64", "epoch": null, "name": "ModemManager", "release": "3.el9", "source": "rpm", "version": "1.18.2" } ], ...output omitted... "zstd": [ { "arch": "x86_64", "epoch": null, "name": "zstd", "release": "2.el9", "source": "rpm", "version": "1.5.1" } ] } } TASK [Display NetworkManager version] ************************************** ok: [servera.lab.example.com] => {"msg": "Version 1.36.0"} PLAY RECAP ***************************************************************** servera.lab.example.com : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
For other package managers, Ansible usually provides a dedicated module.
The ansible.builtin.apt module uses the APT package tool available on Debian and Ubuntu.
The ansible.windows.win_package module can install software on Microsoft Windows systems.
The following playbook uses conditionals to select the appropriate module in an environment composed of Red Hat Enterprise Linux systems running major versions 7, 8, and 9.
---
- name: Install the required packages on the web servers
hosts: webservers
tasks:
- name: Install httpd on RHEL 8 and 9
ansible.builtin.dnf:
name: httpd
state: present
when:
- "ansible_facts['distribution'] == 'RedHat'"
- "ansible_facts['distribution_major_version'] >= '8'"
- name: Install httpd on RHEL 7 and earlier
ansible.builtin.yum:
name: httpd
state: present
when:
- "ansible_facts['distribution'] == 'RedHat'"
- "ansible_facts['distribution_major_version'] <= '7'"As an alternative, the generic ansible.builtin.package module automatically detects and uses the package manager available on the managed hosts.
With the ansible.builtin.package module, you can rewrite the previous playbook as follows:
---
- name: Install the required packages on the web servers
hosts: webservers
tasks:
- name: Install httpd
ansible.builtin.package:
name: httpd
state: presentHowever, the ansible.builtin.package module does not support all the features that the more specialized modules provide.
Also, operating systems often have different names for the packages they provide.
For example, the package that installs the Apache HTTP Server is httpd on Red Hat Enterprise Linux and apache2 on Ubuntu.
In that situation, you still need a conditional for selecting the correct package name depending on the operating system of the managed host.
To entitle your Red Hat Enterprise Linux systems to product subscriptions, one option is to use the community.general.redhat_subscription and community.general.rhsm_repository modules.
These modules interface with the Red Hat Subscription Management tool on the managed hosts.
The Subscription Management modules previously described are part of the community.general Ansible Content Collection, and are not supported by Red Hat at this time.
As an alternative, you could use the ansible.builtin.command module to call the command-line Subscription Management commands.
To avoid accidental reregistration and allow the playbook to be idempotent, you need to determine what condition to use to skip subscription-related tasks that have already been completed.
The first two tasks you usually perform with the Red Hat Subscription Management tool is to register the new system and attach an available subscription.
Without Ansible, you perform these tasks with the subscription-manager command:
[user@host ~]$subscription-manager register --username=>yourusername\--password=[user@host ~]$yourpasswordsubscription-manager attach --pool=poolID
Remember that you can list the pools available to your account with the subscription-manager list --available command.
The community.general.redhat_subscription module performs the registration and the subscription in one task.
- name: Register and subscribe the system
community.general.redhat_subscription:
username: yourusername
password: yourpassword
pool_ids: poolID
state: presentA state keyword set to present indicates to register and to subscribe the system.
When it is set to absent, the module unregisters the system.
The next task after the subscription is to enable Red Hat software repositories on the new system.
Without Ansible, you would execute the subscription-manager command for that purpose:
[user@host ~]$subscription-manager repos \>--enable "rhel-9-for-x86_64-baseos-rpms" \>--enable "rhel-9-for-x86_64-appstream-rpms"
Remember that you can list the available repositories with the subscription-manager repos --list command.
With Ansible, you can use the community.general.rhsm_repository module:
- name: Enable Red Hat repositories
community.general.rhsm_repository:
name:
- rhel-9-for-x86_64-baseos-rpms
- rhel-9-for-x86_64-appstream-rpms
state: presentTo enable support for a third-party Yum repository on a managed host, Ansible provides the ansible.builtin.yum_repository module.
When run, the following playbook declares a new Yum repository on servera.lab.example.com.
---
- name: Configure the company Yum/DNF repositories
hosts: servera.lab.example.com
tasks:
- name: Ensure Example Repo exists
ansible.builtin.yum_repository:
file: example
name: example-internal
description: Example Inc. Internal YUM/DNF repo
baseurl: http://materials.example.com/yum/repository/
enabled: yes
gpgcheck: yes
state: present 
The | |
Typically, software providers digitally sign RPM packages using GPG keys.
By setting the | |
When you set the |
The resulting /etc/yum.repos.d/example.repo file on servera.lab.example.com is as follows:
[example-internal] baseurl = http://materials.example.com/yum/repository/ enabled = 1 gpgcheck = 1 name = Example Inc. Internal YUM repo
The ansible.builtin.yum_repository module exposes most of the repository configuration parameters as keywords.
Run the ansible-navigator doc ansible.builtin.yum_repository command for additional parameters and playbook examples.
Some third-party repositories provide the configuration file and the GPG public key as part of an RPM package that can be downloaded and installed using the dnf install command.
For example, the Extra Packages for Enterprise Linux (EPEL) project provides the https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm package that deploys the /etc/yum.repos.d/epel.repo configuration file.
For this repository, use the ansible.builtin.dnf module to install the EPEL package instead of the ansible.builtin.yum_repository module.
When the gpgcheck keyword is set to yes in the ansible.builtin.yum_repository module, you also need to install the GPG key on the managed host.
The ansible.builtin.rpm_key module in the following example deploys the GPG public key hosted on a remote web server to the servera.lab.example.com managed host.
---
- name: Configure the company Yum/DNF repositories
hosts: servera.lab.example.com
tasks:
- name: Deploy the GPG public key
ansible.builtin.rpm_key:
key: http://materials.example.com/yum/repository/RPM-GPG-KEY-example
state: present
- name: Ensure Example Repo exists
ansible.builtin.yum_repository:
file: example
name: example-internal
description: Example Inc. Internal YUM/DNF repo
baseurl: http://materials.example.com/yum/repository/
enabled: yes
gpgcheck: yes
state: present
dnf(8), yum.conf(5), and subscription-manager(8) man pages
ansible.builtin.dnf module — Manages packages with the dnf package manager — Ansible Documentation
ansible.builtin.package_facts module — Package information as facts — Ansible Documentation
ansible.builtin.yum_repository module — Add or remove YUM repositories — Ansible Documentation
ansible.builtin.rpm_key module — Adds or removes a gpg key from the rpm db — Ansible Documentation