Skip to content

Expert · Ansible fundamentals · topic 47 of 57 · 35 min

Writing and running playbooks

Explanation

A playbook is a YAML file with one or more plays. Each play names the hosts and a list of tasks; each task calls one module. Run it with ansible-playbook (or ansible-navigator run). Check it first with --syntax-check and a dry run with -C (check mode), and read the PLAY RECAP: ok, changed, failed, unreachable.

From commands to a playbook

Ad-hoc commands are one-off. A playbook saves the whole procedure in a file you can review, run again, and keep in Git. It is the main way to use Ansible.

yaml
---
- name: Set up web servers
  hosts: webservers
  become: true

  tasks:
    - name: Install Apache
      ansible.builtin.dnf:
        name: httpd
        state: present

    - name: Put the home page in place
      ansible.builtin.copy:
        content: "Welcome to {{ inventory_hostname }}\n"
        dest: /var/www/html/index.html
        mode: "0644"

    - name: Start and enable Apache
      ansible.builtin.service:
        name: httpd
        state: started
        enabled: true

    - name: Open HTTP in the firewall
      ansible.posix.firewalld:
        service: http
        permanent: true
        immediate: true
        state: enabled
web.yml: one play with four tasks. firewalld comes from the ansible.posix collection.

The structure

  • The file is a LIST of plays (each starts with "- name:").
  • A play has hosts (a pattern from the inventory), optional settings such as become, and tasks.
  • tasks is a list; each task has a name (say what it ensures, in plain words) and exactly one module with its arguments indented under it.
  • Tasks run in order, on all hosts of the play in parallel (5 hosts at a time by default; the forks setting).
  • {{ inventory_hostname }} is a variable: the host's name from the inventory. Quote any value that starts with {{.

Running it

bash
$ ansible-playbook web.yml --syntax-check
playbook: web.yml
$ ansible-playbook web.yml -C          # check mode: report what WOULD change, change nothing
$ ansible-playbook web.yml
PLAY [Set up web servers] ******************************************************
TASK [Gathering Facts] *********************************************************
ok: [web01.example.com]
TASK [Install Apache] **********************************************************
changed: [web01.example.com]
TASK [Put the home page in place] **********************************************
changed: [web01.example.com]
TASK [Start and enable Apache] *************************************************
changed: [web01.example.com]
TASK [Open HTTP in the firewall] ***********************************************
changed: [web01.example.com]
PLAY RECAP *********************************************************************
web01.example.com : ok=5  changed=4  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
$ ansible-playbook web.yml            # second run
...
web01.example.com : ok=5  changed=0  unreachable=0  failed=0  skipped=0  rescued=0  ignored=0
A second run with changed=0 proves the playbook is idempotent.

Useful options: -v (more detail, up to -vvvv for connection debugging), --limit HOST, --list-hosts and --list-tasks (show what would run), --diff (show file changes), --start-at-task "name" (resume). If a task fails on a host, Ansible stops running further tasks on THAT host and carries on with the others.

ansible-navigator

bash
$ ansible-navigator run web.yml -m stdout       # output like ansible-playbook
$ ansible-navigator run web.yml                 # interactive text UI: drill into plays, tasks, hosts
$ ansible-navigator doc ansible.builtin.dnf -m stdout
Navigator runs inside an execution environment image; the first run may pull it. Its settings live in ansible-navigator.yml.

Whether you use ansible-playbook or ansible-navigator depends on your environment. Red Hat's automation platform and some exam versions expect navigator; check what your workplace or the current exam objectives use, and practise with that one.

Common mistakes

  • Indentation: module arguments must be indented under the module name, which is under the task.
  • Two modules in one task: "conflicting action statements". Split them into two tasks.
  • Writing yes/no and on/off unquoted where text is meant. YAML may turn them into true/false. Use true/false for booleans and quote text.
  • Unquoted {{ var }} at the start of a value: YAML reads { as a dictionary. Write "{{ var }}".
  • Never reading the recap. changed on the second run means something is not idempotent (often a command or shell task).

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Writing and running playbooks · 1/6

playbook → plays → tasks → modules

A playbook saves a whole procedure as YAML. It is a list of plays.

Prefer a video by a teacher? Find free videos on “ansible playbook tutorial for beginners rhel” on YouTube ↗

In real life: Standard setup for every new server at an IT services firm

An IT services firm in Pune sets up dozens of client servers a month. Their baseline.yml playbook installs agreed packages, sets the time zone and NTP, creates admin users with keys, hardens SSH and opens only required ports. A new server is ready in ten minutes, and running the same playbook weekly fixes anything someone changed by hand.

yaml
- name: Baseline for all servers
  hosts: all
  become: true
  tasks:
    - name: Time zone is Asia/Kolkata
      community.general.timezone:
        name: Asia/Kolkata
    - name: Basic tools are installed
      ansible.builtin.dnf:
        name: [vim-enhanced, tmux, bash-completion, chrony]
        state: present

Practice (0/4 done)

Task 1 · Question

Which command checks a playbook for syntax errors without running it?

Task 2 · Question

Which line has the bug? 1: - name: Install chrony 2: ansible.builtin.dnf: 3: name: chrony 4: state: present

Task 3 · Code · Python

Write parse_recap(line) for one PLAY RECAP line like "web01.example.com : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0". Return (host, counts) where counts is a dict of the numbers as ints. Then write needs_attention(lines) that returns the sorted hosts whose failed or unreachable count is above 0.

Task 4 · Practice

Write web.yml from this lesson for your lab (use ansible.builtin.dnf, copy and service; add the firewalld task if the ansible.posix collection is installed). Run --syntax-check, -C, a real run, and a second run. Then curl each web server.

Quick quiz

Question 1

1.What does -C do with ansible-playbook?

Question 2

2.A task fails on one host out of ten. What happens by default?

Question 3

3.Why quote "{{ inventory_hostname }}" at the start of a YAML value?

Question 4

4.In PLAY RECAP, what does changed=0 on a second run show?

Question 5

5.How many modules may one task call?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does -C do with ansible-playbook?

Answer: Check mode: predict changes without making them

It is a dry run.

A task fails on one host out of ten. What happens by default?

Answer: That host stops; the others continue

Failed hosts are removed from the rest of the play.

Why quote "{{ inventory_hostname }}" at the start of a YAML value?

Answer: YAML would read { as the start of a dictionary

Quote values starting with {{.

In PLAY RECAP, what does changed=0 on a second run show?

Answer: The playbook is idempotent: everything was already correct

Tasks ran and found nothing to fix.

How many modules may one task call?

Answer: One

One module per task.

What does ansible-playbook site.yml --check --diff do?Related

Answer: Shows what would change, with file differences, without changing anything

Check mode is a dry run; diff shows the before and after of files.

From Ansible playbooks

Which magic variable holds the host's name as written in the inventory?Related

Answer: inventory_hostname

inventory_hostname; ansible_facts['hostname'] is what the host reports itself.

From Variables, facts and registered results

Which package gives you ansible-playbook on RHEL 9?Related

Answer: ansible-core

ansible-core.

From What Ansible is and how it works

What does --become do in an Ansible command?Related

Answer: Runs the task with higher privileges, by default using sudo

become escalates privileges, usually to root via sudo.

From Ansible: inventory and ad-hoc commands

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Ansible fundamentals” before its exam: Everyday modules and handlers.
  2. Module 9 exam: Ansible fundamentals · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Ansible in depth. 57 topics left in the course before the final exam.

← Previous: Ad-hoc commands and ansible-doc