Chapter 5: Implementing Task Control

Exercise: Loops and conditional tasks

You will install MariaDB with a looping task, then add a condition so the installation only happens on Red Hat Enterprise Linux, and run it against a second group.

The inventory in ~/control-flow has two groups:

[database_dev]
servera.lab.example.com

[database_prod]
serverb.lab.example.com

Writing loops and conditional tasks

  • Implement conditionals with the when keyword.
  • Iterate a task with loop, together with conditionals.

Prerequisites: Complete control-node setup and the preceding lessons in this chapter. Run commands as student on workstation unless a step names another machine.

From the project directory, run the relevant home-lab check. For an exercise with several checkpoints, grade each state before changing or removing it:

lab grade control-flow

The grader reads project files and host state. A passing report covers the listed checks; also perform the task’s independent connection, repeat-run, and reboot checks where requested.

Add a host whose OS does not match the condition. Ensure later service tasks do not assume a skipped package was installed.

Record the published result first. The grader checks the original requirements, so a changed name or value may intentionally fail those checks.

Configure MariaDB from the mariadb_packages list in playbook.yml.

  • On database_dev, install mariadb-server and python3-PyMySQL through individual loop items, then start and enable MariaDB.
  • Extend the exercise to database_prod: installation must happen only on the intended distribution. In the classroom that is Red Hat Enterprise Linux; at home use the RedHat OS family so Rocky hosts are included.
  • Prove which hosts ran or skipped the installation and check service state. A skipped installation does not install dependencies for a later service task.

Move into the project directory

[student@workstation ~]$ cd ~/control-flow
[student@workstation control-flow]$ cat inventory

Start the play with a list variable

Create playbook.yml with a play, MariaDB server is running, for database_dev. Define mariadb_packages as a list containing mariadb-server and python3-PyMySQL.

---
- name: MariaDB server is running
  hosts: database_dev
  vars:
    mariadb_packages:
      - mariadb-server
      - python3-PyMySQL

Install the packages with a loop

Add a task that installs each package in mariadb_packages, one loop item at a time.

  tasks:
    - name: MariaDB packages are installed
      ansible.builtin.dnf:
        name: "{{ item }}"
        state: present
      loop: "{{ mariadb_packages }}"

Start the service

    - name: Start MariaDB service
      ansible.builtin.service:
        name: mariadb
        state: started
        enabled: true

Run it and read the per-item output

[student@workstation control-flow]$ ansible-navigator run -m stdout playbook.yml
...output omitted...
TASK [MariaDB packages are installed] ******************************************
changed: [servera.lab.example.com] => (item=mariadb-server)
changed: [servera.lab.example.com] => (item=python3-PyMySQL)

TASK [Start MariaDB service] ***************************************************
changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=3    changed=2    unreachable=0    failed=0  ...

Each loop item gets its own line, tagged (item=...).

Add a condition and target production

Change the play to target database_prod, and make the install task run only when the host's distribution is Red Hat Enterprise Linux.

- name: MariaDB server is running
  hosts: database_prod
  ...output omitted...
    - name: MariaDB packages are installed
      ansible.builtin.dnf:
        name: "{{ item }}"
        state: present
      loop: "{{ mariadb_packages }}"
      when: ansible_facts['distribution'] == "RedHat"

serverb runs Rocky Linux at home, so with "RedHat" the condition is false and both items are skipped. Write when: ansible_facts['distribution'] == "Rocky" to get the output in the next task. Then try it once with "RedHat" on purpose: seeing skipping: for each item is the other half of this exercise.

Run it again

[student@workstation control-flow]$ ansible-navigator run -m stdout playbook.yml
...output omitted...
TASK [MariaDB packages are installed] ******************************************
ok: [serverb.lab.example.com] => (item=mariadb-server)
ok: [serverb.lab.example.com] => (item=python3-PyMySQL)
...output omitted...
PLAY RECAP *********************************************************************
serverb.lab.example.com    : ok=3    changed=0    unreachable=0    failed=0  ...

The shown recap is a repeat run after production is configured. Its first run can report changes. In the classroom serverb runs RHEL, so the condition is true and the task runs. On a host where the condition is false, each item shows skipping: instead:

TASK [MariaDB packages are installed] ******************************************
skipping: [serverb.lab.example.com] => (item=mariadb-server)
skipping: [serverb.lab.example.com] => (item=python3-PyMySQL)

Finish

Check your work with lab grade control-flow, then put the exercise away with lab finish control-flow.