Chapter 4: Managing Variables and Facts
Variables in playbooks
So far every value in your playbooks has been typed in directly: the package name, the service, the path. Variables let you name those values once and reuse them everywhere, so a change happens in one place instead of ten, and one playbook can serve different hosts.
- Name variables correctly.
- Define variables in a play with
varsandvars_files, and use them with{{ }}. - Know when a variable reference must be quoted.
- Group related values in a dictionary, and capture task results with
register.
Why variables
A variable stores a value that you can reuse throughout the files of an Ansible project. That makes projects easier to write and maintain, and reduces mistakes, because each value lives in exactly one place. Typical things to put in variables:
Package names, versions, archive URLs to download.
Users to create, services to restart, firewall services to open.
Configuration file paths, document roots, files to remove.
Naming variables
A variable name must start with a letter, and may contain only letters, numbers and underscores. Spaces, dots, dashes and symbols are not allowed.
| Invalid | Valid |
|---|---|
web server | web_server |
remote.file | remote_file |
1st file | file_1 or file1 |
remoteserver$1 | remote_server_1 or remote_server1 |
Try some names of your own:
Defining variables in a play
The most common place to define variables is a vars block at the start of a play. Every task in that play can then use them.
- name: Create the standard user
hosts: all
vars:
user: joe
home: /home/joe
tasks:
...When the list grows, or you want to share variables between playbooks, move them into a separate YAML file and load it with vars_files. Paths are relative to the playbook.
- name: Create the standard user
hosts: all
vars_files:
- vars/users.yml
tasks:
...user: joe
home: /home/joeThe file holds plain key-value pairs, in the same format as a vars block.
Using a variable
To use a variable, put its name inside double curly braces: {{ user }}. When the task runs, Ansible replaces the reference with the variable's value. This syntax comes from Jinja2, the template language Ansible is built on.
vars:
user: joe
tasks:
# The task name will read "Create the user joe"
- name: Create the user {{ user }}
ansible.builtin.user:
# This creates the user named joe
name: "{{ user }}"The quoting rule
Notice that name: "{{ user }}" is in quotes, but the task name is not. The rule is simple:
Edit the values below, then untick the quotes to see the error you will get:
The same rule applies to list items: write - "{{ package }}", not - {{ package }}.
Dictionaries as variables
When several values belong to the same thing, a dictionary keeps them together. Compare six loose variables with one structured one:
user1_first_name: Bob
user1_last_name: Jones
user1_home_dir: /users/bjones
user2_first_name: Anne
user2_last_name: Cook
user2_home_dir: /users/acookusers:
bjones:
first_name: Bob
last_name: Jones
home_dir: /users/bjones
acook:
first_name: Anne
last_name: Cook
home_dir: /users/acookTo read a value inside a dictionary you can use dot notation, users.bjones.first_name, or bracket notation, users['bjones']['first_name']. Both return Bob. Click around this dictionary to see both forms for any value:
Capturing results with register
Every module returns information about what it did, as JSON. The register keyword saves that result in a variable, so later tasks can print it, make decisions with it, or reuse part of it.
Capturing a task result with register: Every module returns a JSON result. register saves it as a variable, so later tasks can print it, test it or reuse it.
- name: Installs a package and prints the result
hosts: all
tasks:
- name: Install the package
ansible.builtin.dnf:
name: httpd
state: installed
register: install_result
- name: Show what dnf reported
ansible.builtin.debug:
var: install_resultThe ansible.builtin.debug module prints the variable during the run:
TASK [Show what dnf reported] **************************************************
ok: [demo.example.com] => {
"install_result": {
"changed": false,
"msg": "",
"rc": 0,
"results": [
"httpd-2.4.51-7.el9_0.x86_64 providing httpd is already installed"
]
}
}register is placed at the task level, at the same indentation as the module name, not inside the module's arguments. You can then read any part of it, for example install_result['changed'].
- Which of these is a valid variable name?
- Why does this task fail to load?
- Where does `register: result` go?
Takeaway
Name variables correctly. Use the chapter lab to check this on a real host.