The power of Ansible is that you can use playbooks to run multiple, complex tasks against a set of targeted hosts in an easily repeatable manner.
A task is the application of a module to perform a specific unit of work. A play is a sequence of tasks to be applied, in order, to one or more hosts selected from your inventory. A playbook is a text file containing a list of one or more plays to run in a specific order.
Plays enable you to change a lengthy, complex set of manual administrative tasks into an easily repeatable routine with predictable and successful outcomes. In a playbook, you can save the sequence of tasks in a play into a human-readable and immediately runnable form. The tasks themselves, because of the way in which they are written, document the steps needed to deploy your application or infrastructure.
The following example contains one play with a single task.
---
- name: Configure important user consistently
hosts: servera.lab.example.com
tasks:
- name: Newbie exists with UID 4000
ansible.builtin.user:
name: newbie
uid: 4000
state: presentA playbook is a text file written in YAML format, and is normally saved with the extension .yml.
The playbook uses indentation with space characters to indicate the structure of its data.
YAML does not place strict requirements on how many spaces are used for the indentation, but two basic rules apply:
Data elements at the same level in the hierarchy (such as items in the same list) must have the same indentation.
Items that are children of another item must be indented more than their parents.
You can also add blank lines for readability.
You can only use space characters for indentation; do not use tab characters.
If you use the vi text editor, you can apply some settings which might make it easier to edit your playbooks.
For example, you can add the following line to your $HOME/.vimrc file, and when vi detects that you are editing a YAML file, it performs a 2-space indentation when you press the Tab key and automatically indents subsequent lines.
autocmd FileType yaml setlocal ai ts=2 sw=2 et
A playbook usually begins with a line consisting of three dashes (---) to indicate the start of the document.
It might end with three dots (...) to indicate the end of the document, although in practice this is often omitted.
Between those markers, the playbook is defined as a list of plays. An item in a YAML list starts with a single dash followed by a space. For example, a YAML list might appear as follows:
- apple - orange - grape
In the preceding playbook example, the line after --- begins with a dash and starts the first (and only) play in the list of plays.
The play itself is a collection of key-value pairs. Keys in the same play should have the same indentation. The following example shows a YAML snippet with three keys. The first two keys have simple values. The third has a list of three items as a value.
name: just an example
hosts: webservers
tasks:
- first
- second
- thirdThe initial example play has three keys: name, hosts, and tasks.
These keys all have the same indentation.
The first line of the example play starts with a dash and a space (indicating the play is the first item of a list), and then the first key, name.
The name key associates an arbitrary string with the play as a label that identifies the purpose of the play.
The name key is optional, but is recommended because it helps to document your playbook.
This is especially useful when a playbook contains multiple plays.
- name: Configure important user consistently
The second key in the play is a hosts key, which specifies the hosts against which the play's tasks are run.
The hosts key takes a host pattern as a value, such as the names of managed hosts or groups in the inventory.
hosts: servera.lab.example.com
Finally, the last key in the play is tasks, whose value specifies a list of tasks to run for this play.
This example has a single task, which runs the ansible.builtin.user module with specific arguments (to ensure the newbie user exists and has UID 4000).
tasks:
- name: newbie exists with UID 4000
ansible.builtin.user:
name: newbie
uid: 4000
state: presentThe tasks key is the part of the play that actually lists, in order, the tasks to be run on the managed hosts.
Each task in the list is itself a collection of key-value pairs.
In this example, the only task in the play has two keys:
name is an optional label documenting the purpose of the task.
It is a good idea to name all your tasks to help document the purpose of each step of the automation process.
ansible.builtin.user is the module to run for this task.
Its arguments are passed as a collection of key-value pairs, which are children of the module (name, uid, and state).
The following is another example of a tasks key with multiple tasks, each using the ansible.builtin.service module to ensure that a service should start at boot:
tasks:
- name: Web server is enabled
ansible.builtin.service:
name: httpd
enabled: true
- name: NTP server is enabled
ansible.builtin.service:
name: chronyd
enabled: true
- name: Postfix is enabled
ansible.builtin.service:
name: postfix
enabled: trueThe order in which the plays and tasks are listed in a playbook is important, because Ansible runs them in the same order.
Modules are the tools that plays use to accomplish tasks. Hundreds of modules have been written that do different things. You can usually find a tested, special-purpose module that does what you need, often as part of the default automation execution environment.
Ansible Core 2.11 and later package the modules that you use for tasks in sets called Ansible Content Collections. Each Ansible Content Collection contains a selection of related Ansible content, including modules and documentation.
The ansible-core package provides a single Ansible Content Collection named ansible.builtin.
These modules are always available to you.
Visit https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ for a list of modules contained in the ansible.builtin collection.
In addition, the default automation execution environment used by ansible-navigator in Red Hat Ansible Automation Platform 2.2, ee-rhel8-supported, includes a number of other Ansible Content Collections.
You can browse these collections by running the ansible-navigator collections command.
In the interactive UI, you can type a colon (:) followed by the line number of a collection to get more information about it, including the list of modules and other Ansible content that it provides.
You can do the same thing with the line number of a module to get documentation about that module.
Press Esc to go back to the preceding list.
You can also download additional Ansible Content Collections from a number of places, including:
The automation hub offered through the Red Hat Hybrid Cloud Console at https://content.redhat.com/ansible/automation-hub
A private automation hub managed by your organization
The community's Ansible Galaxy website at https://galaxy.ansible.com
These can be installed in the collections directory of your Ansible project.
Red Hat does not provide formal support for community Ansible Content Collections, only for Red Hat Certified Ansible Content Collections.
Modules are named using fully qualified collection names (FQCNs).
This allows the same name to be used for different modules in two Ansible Content Collections without causing conflicts.
For example, the copy module provided by the ansible.builtin Ansible Content Collection has ansible.builtin.copy as its FQCN.
In earlier versions of Ansible, modules had to be included with Ansible and were named using just their short name, for example the copy module.
Ansible might still try to resolve short names if your playbooks use them.
However, to avoid errors, it is a good practice to use FQCNs in new playbooks.
Most modules are idempotent, which means that they can be run safely multiple times, and if the system is already in the correct state, they do nothing. For example, if you run the play from the preceding example a second time, it should report no changes.
The ansible-navigator run command is used to run playbooks.
The command is executed on the control node, and the name of the playbook to be run is passed as an argument.
Running the ansible-navigator run command with the -m stdout option prints the output of the playbook run to standard output.
If the -m stdout option is not provided, then ansible-navigator runs in interactive mode.
Interactive mode is covered in the course DO374: Developing Advanced Automation with Red Hat Ansible Automation Platform.
[user@controlnode ~]$ansible-navigator run \>-m stdout site.yml
When you run the playbook, output is generated to show the play and tasks being executed. The output also reports the results of each task executed.
The following example shows the contents of a simple playbook, and then the result of running it.
[user@controlnode playdemo]$cat webserver.yml--- - name: Play to set up web server hosts: servera.lab.example.com tasks: - name: Latest httpd version installed ansible.builtin.dnf: name: httpd state: latest ...output omitted... [user@controlnode playdemo]$ansible-navigator run \>-m stdout webserver.ymlPLAY [Play to set up web server] ************************************************ TASK [Gathering Facts] ********************************************************* ok: [servera.lab.example.com] TASK [Latest httpd version installed] ******************************************changed: [servera.lab.example.com] PLAY RECAP ********************************************************************* servera.lab.example.com : ok=2changed=1unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The value of the name key for each play and task is displayed when the playbook is run.
(The Gathering Facts task is a special task that the ansible.builtin.setup module usually runs automatically at the start of a play.
This is covered later in the course.)
For playbooks with multiple plays and tasks, setting name attributes makes it easier to monitor the progress of a playbook's execution.
You should also see that the Latest httpd version installed task is changed for servera.lab.example.com.
This means that the task changed something on that host to ensure that its specification was met.
In this case, it means that the httpd package was not previously installed or was not the latest version.
In general, tasks in Ansible Playbooks are idempotent, and it is safe to run a playbook multiple times. If the targeted managed hosts are already in the correct state, no changes should be made. For example, assume that the playbook from the previous example is run again:
[user@controlnode playdemo]$ansible-navigator run \>-m stdout webserver.ymlPLAY [Play to set up web server] ************************************************ TASK [Gathering Facts] ********************************************************* ok: [servera.lab.example.com] TASK [Latest httpd version installed] ****************************************** ok: [servera.lab.example.com] PLAY RECAP ********************************************************************* servera.lab.example.com : ok=2changed=0unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This time, all tasks passed with status ok and no changes were reported.
Community Ansible provides an earlier tool called ansible-playbook that takes many of the same options as ansible-navigator run -m stdout and that uses your control node as the execution environment.
It cannot use automation execution environments, and is only supported by Red Hat in Red Hat Enterprise Linux 9 for narrow use cases.
The default output provided by the ansible-navigator run command does not provide detailed task execution information.
The -v option provides additional information, with up to four levels.
Table 2.2. Configuring the Output Verbosity of Playbook Execution
| Option | Description |
|---|---|
-v
| Displays task results. |
-vv
| Displays task results and task configuration. |
-vvv
| Displays extra information about connections to managed hosts. |
-vvvv
| Adds extra verbosity options to the connection plug-ins, including users being used on the managed hosts to execute scripts, and what scripts have been executed. |
Before executing a playbook, it is good practice to validate its syntax.
You can use the ansible-navigator run --syntax-check command to validate the syntax of a playbook.
The following example shows the successful syntax validation of a playbook.
[user@controlnode playdemo]$ansible-navigator run \>-m stdout webserver.yml --syntax-checkplaybook: /home/user/playdemo/webserver.yml
When syntax validation fails, a syntax error is reported.
The output also includes the approximate location of the syntax issue in the playbook.
The following example shows the failed syntax validation of a playbook where the space separator is missing after the name attribute for the play.
[user@controlnode playdemo]$ansible-navigator run \>-m stdout webserver.yml --syntax-checkERROR! Syntax Error while loading YAML. mapping values are not allowed in this context The error appears to have been in ...output omitted... line 3, column 8, but may be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: - name:Play to set up web server hosts: servera.lab.example.com ^ here
You can use the --check option to run a playbook in check mode, which performs a "dry run" of the playbook.
This causes Ansible to report what changes would have occurred if the playbook were executed, but does not make any actual changes to managed hosts.
The following example shows the dry run of a playbook containing a single task for ensuring that the latest version of the httpd package is installed on a managed host.
In this case, the dry run reports that the task would make a change on the managed host.
[user@controlnode playdemo]$ansible-navigator run \>-m stdout webserver.yml --checkPLAY [Play to set up web server] *********************************************** TASK [Gathering Facts] ********************************************************* ok: [servera.lab.example.com] TASK [Latest httpd version installed] ****************************************** changed: [servera.lab.example.com] PLAY RECAP ********************************************************************* servera.lab.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0