Chapter 3: Implementing an Ansible Playbook

Finding modules and YAML syntax

Two skills make you fast with Ansible: finding the right module (and reading its documentation without leaving the terminal), and writing YAML that is correct the first time. This section covers both.

Selecting modules

Ansible ships hundreds of modules for everyday administration. These are some of the most useful; pick one to see the command that shows its documentation.

Reading module documentation

The documentation is inside your execution environment, so you can read it offline, which matters on an exam.

List every module available in the current EE with a one-line synopsis:

[user@controlnode ~]$ ansible-navigator doc -l -m stdout
add_host                          Add a host (and alternatively a group) to the ansible-playbo...
amazon.aws.aws_az_facts           Gather information about availability zones in AWS
...output omitted...
yum                               Manages packages with the yum package manager
yum_repository                    Add or remove YUM repositories

Read the full documentation for one module: what it does, every argument, and examples you can copy:

[user@controlnode ~]$ ansible-navigator doc ansible.builtin.dnf -m stdout

Or get a ready-to-edit snippet with every argument and a comment explaining each one, using -s. The course shows it in this form (with the classic tools, the equivalent is ansible-doc -s ansible.builtin.dnf):

[user@controlnode ~]$ ansible-navigator -s doc ansible.builtin.dnf

Without -m stdout, navigator shows the documentation interactively in YAML. You can also browse modules collection by collection with ansible-navigator collections.

Running arbitrary commands

If no module exists for what you need, three modules let you run commands directly:

Runs a command without a shell. The simplest option. No pipes, redirects or shell variables. Needs Python on the host.Runs a command through a shell, so pipes, > redirects and environment variables work. Needs Python on the host.Sends the command straight over SSH, bypassing the module system. Works on hosts without Python, such as some network devices, and can even be used to install Python.
- name: Run the /opt/bin/makedb.sh command
  ansible.builtin.command:
    cmd: /opt/bin/makedb.sh

Unlike most modules, these are not idempotent. Every run executes the command and reports changed, even if nothing needed doing. You can make command and shell safer with a file check:

- name: Initialize the database
  ansible.builtin.command:
    cmd: /opt/bin/makedb.sh
    creates: /opt/db/database.db

The best fix, though, is usually a proper module. Compare an unconditional file write, a database command guarded by creates, and a content-aware file module. Press run again to see which tasks still report a change:

YAML syntax you will meet

Comments

Everything to the right of # is a comment. If there is content before it on the same line, put a space before the #.

# This is a YAML comment
some data # This is also a YAML comment

Strings

Strings usually need no quotes, even with spaces. Single or double quotes both work when you want them:

this is a string
'this is another string'
"this is yet another string"

Multi-line strings come in two styles: | keeps line breaks, and > folds lines into one, which is useful for breaking up very long strings.

Dictionaries

Key-value pairs are normally written as an indented block. An inline form in braces also exists:

name: svcrole
svcservice: httpd
svcport: 80
{name: svcrole, svcservice: httpd, svcport: 80}

Avoid the inline form: it is harder to read. The one place it is common is lists of roles with parameters, which you will meet in chapter 8.

Lists

The normal form uses one dash per item. An inline form in square brackets also exists, and should also generally be avoided:

hosts:
  - servera
  - serverb
  - serverc
hosts: [servera, serverb, serverc]

Obsolete shorthand for tasks

Older playbooks sometimes put module arguments on the same line as the module, as key=value pairs:

tasks:
  - name: Shorthand form
    ansible.builtin.service: name=httpd enabled=true state=started
tasks:
  - name: Normal form
    ansible.builtin.service:
      name: httpd
      enabled: true
      state: started

The normal form takes more lines but is easier to read: your eyes move straight down the keys. It is also real YAML, so editors highlight it properly. Recognise the shorthand when you see it, but do not write it.

Takeaway

Find modules and read their documentation with ansible-navigator doc. Use the chapter lab to check this on a real host.