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.
- Find modules and read their documentation with
ansible-navigator doc. - Know when, and how, to use
command,shellandrawsafely. - Read and write YAML comments, strings, multi-line strings, dictionaries and lists.
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 repositoriesRead 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 stdoutOr 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.dnfWithout -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.shUnlike 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:
creates: PATHruns the command only ifPATHdoes not exist (assumption: running the command creates it).removes: PATHruns the command only ifPATHdoes exist (assumption: running the command removes it).
- name: Initialize the database
ansible.builtin.command:
cmd: /opt/bin/makedb.sh
creates: /opt/db/database.dbThe 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 commentStrings
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
- serverchosts: [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=startedtasks:
- name: Normal form
ansible.builtin.service:
name: httpd
enabled: true
state: startedThe 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.
- You need to run `/usr/local/bin/setup.sh` once. It creates `/etc/app/ready` when it finishes. How do you make the task idempotent?
- Which module can run a command on a host that has no Python installed?
- You need `ls /tmp | wc -l`. Which module supports the pipe?
- Which YAML block style turns several lines into one line joined by spaces?
Takeaway
Find modules and read their documentation with ansible-navigator doc. Use the chapter lab to check this on a real host.