Chapter 10: Automating Linux Administration Tasks
Managing network configuration
Network changes are the ones most likely to cut off the very connection Ansible is using. Reading the configuration is safe; changing it calls for the right module and some care. This section covers both: facts for reading, NetworkManager connections for changing, and the related jobs of host names, name resolution and the firewall.
- Read a host's addresses and interfaces from its facts.
- Add and change network connections with
community.general.nmclior the network system role. - Set host names and name resolution entries.
- Avoid changes that disconnect Ansible from the host.
Reading the configuration
Facts already describe the network. The ones you will use most:
| Fact | Holds |
|---|---|
ansible_facts['default_ipv4'] | The interface, address, gateway and network of the default route |
ansible_facts['interfaces'] | The names of all interfaces |
ansible_facts['enp5s0'] (one per interface) | That interface's addresses, MAC address, MTU and state |
ansible_facts['all_ipv4_addresses'] | Every IPv4 address on the host |
ansible_facts['fqdn'], ['hostname'], ['domain'] | The host's names |
ansible_facts['dns'] | Name servers and search domains |
- name: Show the current default interface
ansible.builtin.debug:
msg: "{{ ansible_facts['default_ipv4']['interface'] }} has {{ ansible_facts['default_ipv4']['address'] }}"ok: [serverb.lab.example.com] => {
"msg": "enp5s0 has 172.25.250.11"
}Each interface's fact holds its active state, device, ipv4 (address, broadcast, netmask, network, prefix), ipv6 (a list), macaddress, module (the driver), mtu and type. The host name that the inventory uses is not a fact: it is the magic variable inventory_hostname, which may differ from ansible_facts['fqdn'].
gather_subset: network collects only the network facts, which is quicker when that is all you need.
Changing connections
RHEL manages networking with NetworkManager. Ansible talks to it in two ways:
One connection per task, with arguments that mirror nmcli: connection name, type, interface, addresses, gateway, DNS.
The supported way on RHEL: describe every connection in one network_connections variable, and the role applies them together.
- name: A dummy interface carries 192.0.2.10
community.general.nmcli:
conn_name: lab-dummy0
type: dummy
ifname: dummy0
ip4: 192.0.2.10/24
autoconnect: true
state: presentWith the system role, the same result is a variable:
- name: Internal address
hosts: servers
vars:
network_connections:
- name: lab-dummy0
type: dummy
interface_name: dummy0
ip:
address:
- 192.0.2.10/24
state: up
roles:
- redhat.rhel_system_roles.networkThe network role's variables
network_provider chooses nm (NetworkManager, the default on RHEL 9) or initscripts. Each entry of network_connections describes one connection profile:
| Key | Meaning |
|---|---|
name | The connection profile's name |
state | up (active) or down |
persistent_state | present (the profile exists) or absent (deleted) |
type | ethernet, bridge, bond, team, vlan, macvlan, infiniband, wireless, dummy … |
interface_name, mac | Which device the profile applies to |
autoconnect | Bring the connection up at boot |
zone | The firewalld zone for the interface |
ip | address (a list), gateway4, gateway6, dns, dhcp4, auto6 |
network_connections:
- name: eth0
persistent_state: present
type: ethernet
autoconnect: true
mac: 00:00:5e:00:53:5d
ip:
address:
- 172.25.250.40/24
dns:
- 8.8.8.8
zone: externalSet state: down to deactivate a connection and keep its profile; add persistent_state: absent to delete the profile too. Like the other system roles' variables, network_connections usually lives in group_vars or host_vars, not in the play. The role's README.md has a section for each kind of setting.
The lab VMs have one network card, managed by the connection System enp5s0. That is the one Ansible uses, so the exercise adds a dummy interface instead. It behaves like a real interface for configuration purposes and cannot cut you off. The address comes from 192.0.2.0/24, a range reserved for documentation that is never routed.
Names
ansible.builtin.hostname sets the host name; it does not change /etc/hosts, which you manage separately:
- name: The host name is set
ansible.builtin.hostname:
name: web01.lab.example.com
- name: The internal name resolves
ansible.builtin.lineinfile:
path: /etc/hosts
line: 192.0.2.10 internal.lab.example.com
state: presentFor more than a line or two, generate /etc/hosts from a template, looping over groups['all'] and hostvars as in chapter 6.
The firewall
Opening a service or port is part of most network changes. You have used ansible.posix.firewalld since chapter 3; remember permanent: true and immediate: true, or the change applies only now or only after a reload:
- name: https is allowed
ansible.posix.firewalld:
service: https
permanent: true
immediate: true
state: enabledThe module manages more than services: port (8080/tcp), source (an address range), rich_rule, interface, and the zone each of those belongs to. This moves an interface into the external zone:
- name: eth0 is in the external zone
ansible.posix.firewalld:
zone: external
interface: eth0
permanent: true
state: enabledThe redhat.rhel_system_roles.firewall role does the same for a whole list of services, ports and zones.
- Which fact gives the address of the interface used for the default route?
- Why is changing the address of the interface Ansible connects through risky?
- Which variable does the network system role read?
- A firewalld task has `permanent: true` but no `immediate`. When does the rule take effect?
Takeaway
Read a host's addresses and interfaces from its facts. Use the chapter lab to check this on a real host.