Chapter 10: Automating Linux Administration Tasks
Managing software
Almost every playbook installs something. Ansible's package modules install, update and remove software, configure the repositories it comes from, and report what is already there, so a play can make decisions based on it.
- Install, update and remove packages and package groups with
ansible.builtin.dnf. - Configure a repository and its signing key.
- Collect the installed-package list with
package_factsand use it.
The module for every administration job
This chapter covers five areas. Use this as a map as you go; each section explains one area in depth.
Installing and removing packages
ansible.builtin.dnf takes a package name, or a list, and the state you want:
- name: Web packages are installed
ansible.builtin.dnf:
name:
- httpd
- mod_ssl
state: presentstate | Result |
|---|---|
present (default) | Installed; left alone if it already is |
latest | Installed and updated to the newest available version |
absent | Removed |
Give name a list rather than looping: dnf then resolves everything in one transaction, which is much faster.
A few more forms of name:
name: | Means |
|---|---|
httpd | The package |
"@Development Tools" | A package group (quote it: @ is special in YAML) |
"*" with state: latest | Update every package on the host |
"@perl:5.26/minimal" | A module stream and profile; leave out /profile for the stream's default |
https://…/tool-1.0.rpm or a local path | An RPM file |
Registering a system
A RHEL host needs a subscription before it can install from Red Hat's repositories. Two modules from community.general handle it: redhat_subscription registers the host (and attaches a subscription pool), and rhsm_repository enables repositories.
- name: Register and subscribe the system
community.general.redhat_subscription:
username: yourusername
password: yourpassword
pool_ids: poolID
state: present
- 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: presentstate: absent unregisters the host. These are community modules, not supported by Red Hat; running subscription-manager through ansible.builtin.command is the alternative.
Rocky Linux needs no subscription: its BaseOS and AppStream repositories are enabled from the start. Skip registration in the home lab.
Repositories and signing keys
Packages come from repositories defined in /etc/yum.repos.d/. ansible.builtin.yum_repository writes those files:
- name: The CRB repository is configured
ansible.builtin.yum_repository:
name: lab-crb
description: Rocky Linux 9 CRB (lab)
mirrorlist: https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=CRB-$releasever
gpgcheck: true
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
enabled: trueThe result on the host:
[lab-crb]
enabled = 1
gpgcheck = 1
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
mirrorlist = https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=CRB-$releasever
name = Rocky Linux 9 CRB (lab)Use baseurl for a single server, or mirrorlist or metalink for a list of mirrors. Always keep gpgcheck: true: it makes dnf refuse packages that were not signed by the key you trust. Import that key with ansible.builtin.rpm_key, from a local file or a URL:
- name: The Rocky Linux signing key is trusted
ansible.builtin.rpm_key:
key: /etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
state: presentEPEL is the usual example of an extra repository, but its metadata is large. On the 1 GiB lab VMs, dnf runs out of memory reading it and the kernel stops it. In Ansible that shows up as MODULE FAILURE … Shared connection to servera.lab.example.com closed., and the kernel log on the host says Out of memory: Killed process … (python3). The exercises use Rocky's own CRB repository instead. The technique is identical.
On RHEL, repositories usually come from a Red Hat subscription. The community.general.redhat_subscription module registers a host, and community.general.rhsm_repository enables or disables subscription repositories by name.
Rocky Linux has no subscriptions: its repositories (BaseOS, AppStream, CRB, extras) are defined by the rocky-repos package and are free to use. The subscription modules do not apply at home.
What is installed?
ansible.builtin.package_facts adds every installed package to the facts, as a dictionary keyed by name. Each value is a list, because several versions of one package (such as kernels) can be installed at once.
- name: Collect the list of installed packages
ansible.builtin.package_facts:
manager: auto
- name: Show the version
ansible.builtin.debug:
msg: "lynx {{ ansible_facts['packages']['lynx'][0]['version'] }}"
when: "'lynx' in ansible_facts['packages']"A condition such as when: "'httpd' in ansible_facts['packages']" lets a play act only on hosts that have a package, without trying to install it.
- Which `state` makes sure a package is installed and updated to the newest version?
- How do you install a package group with the dnf module?
- What does `gpgcheck: true` on a repository do?
- After `package_facts`, where is the information about httpd?
Takeaway
Install, update and remove packages and package groups with ansible.builtin.dnf. Use the chapter lab to check this on a real host.