Read this in other languages:
English, 日本語, Portugues do Brasil, Française, Español.
- Objective
- Guide
- Intro to Variables
- Step 1 - Create Variable Files
- Step 2 - Create index.html Files
- Step 3 - Create the Playbook
- Step 4 - Test the Result
- Step 5 - Ansible Facts
- Step 6 - Challenge Lab: Facts
- Step 7 - Using Facts in Playbooks
Ansible supports variables to store values that can be used in Ansible playbooks. Variables can be defined in a variety of places and have a clear precedence. Ansible substitutes the variable with its value when a task is executed.
This exercise covers variables, specifically
- How to use variable delimiters
{{
and}}
- What
host_vars
andgroup_vars
are and when to use them - How to use
ansible_facts
- How to use the
debug
module to print variables to the console window
Variables are referenced in Ansible Playbooks by placing the variable name in double curly braces:
Here comes a variable {{ variable1 }}
Variables and their values can be defined in various places: the inventory, additional files, on the command line, etc.
The recommended practice to provide variables in the inventory is to define them in files located in two directories named host_vars
and group_vars
:
- To define variables for a group "servers", a YAML file named
group_vars/servers.yml
with the variable definitions is created. - To define variables specifically for a host
node1
, the filehost_vars/node1.yml
with the variable definitions is created.
Tip
Host variables take precedence over group variables (more about precedence can be found in the docs).
For understanding and practice let’s do a lab. Following up on the theme "Let’s build a web server. Or two. Or even more…", you will change the index.html
to show the development environment (dev/prod) a server is deployed in.
On the ansible control host, as the student
user, create the directories to hold the variable definitions in ~/ansible-files/
:
[student@ansible-1 ansible-files]$ mkdir host_vars group_vars
Now create two files containing variable definitions. We’ll define a variable named stage
which will point to different environments, dev
or prod
:
- Create the file
~/ansible-files/group_vars/web.yml
with this content:
---
stage: dev
- Create the file
~/ansible-files/host_vars/node2.yml
with this content:
---
stage: prod
What is this about?
- For all servers in the
web
group the variablestage
with valuedev
is defined. So as default we flag them as members of the dev environment. - For server
node2
this is overridden and the host is flagged as a production server.
Now create two files in ~/ansible-files/files/
:
One called prod_web.html
with the following content:
<body>
<h1>This is a production webserver, take care!</h1>
</body>
And the other called dev_web.html
with the following content:
<body>
<h1>This is a development webserver, have fun!</h1>
</body>
Now you need a Playbook that copies the prod or dev web.html
file - according to the "stage" variable.
Create a new Playbook called deploy_index_html.yml
in the ~/ansible-files/
directory.
Tip
Note how the variable "stage" is used in the name of the file to copy.
---
- name: Copy web.html
hosts: web
become: true
tasks:
- name: copy web.html
ansible.builtin.copy:
src: "{{ stage }}_web.html"
dest: /var/www/html/index.html
- Run the Playbook:
[student@ansible-1 ansible-files]$ ansible-navigator run deploy_index_html.yml
The Ansible Playbook copies different files as index.html to the hosts, use curl
to test it.
For node1:
[student@ansible-1 ansible-files]$ curl http://node1
<body>
<h1>This is a development webserver, have fun!</h1>
</body>
For node2:
[student@ansible-1 ansible-files]$ curl http://node2
<body>
<h1>This is a production webserver, take care!</h1>
</body>
For node3:
[student@ansible-1 ansible-files]$ curl http://node3
<body>
<h1>This is a development webserver, have fun!</h1>
</body>
Tip
If by now you think: There has to be a smarter way to change content in files… you are absolutely right. This lab was done to introduce variables, you are about to learn about templates in one of the next chapters.
Ansible facts are variables that are automatically discovered by Ansible from a managed host. Remember the "Gathering Facts" task listed in the output of each ansible-navigator
execution? At that moment the facts are gathered for each managed nodes. Facts can also be pulled by the setup
module. They contain useful information stored into variables that administrators can reuse.
To get an idea what facts Ansible collects by default, on your control node as your student user run the following playbook to get the setup details of node1
:
---
- name: Capture Setup
hosts: node1
tasks:
- name: Collect only facts returned by facter
ansible.builtin.setup:
gather_subset:
- 'all'
register: setup
- ansible.builtin.debug:
var: setup
[student@ansible-1 ansible-files]$ cd ~
[student@ansible-1 ~]$ ansible-navigator run setup.yml -m stdout
This might be a bit too much, you can use filters to limit the output to certain facts, the expression is shell-style wildcard within your playbook. Create a playbook labeled setup_filter.yml
as shown below. In this example, we filter to get the eth0
facts as well as memory details of node1
.
---
- name: Capture Setup
hosts: node1
tasks:
- name: Collect only specific facts
ansible.builtin.setup:
filter:
- 'ansible_eth0'
- 'ansible_*_mb'
register: setup
- debug:
var: setup
[student@ansible-1 ansible-files]$ ansible-navigator run setup_filter.yml -m stdout
- Try to find and print the distribution (Red Hat) of your managed hosts using a playbook.
Tip
Use the wildcard to find the fact within your filter, then apply a filter to only print this fact.
Warning
Solution below!
---
- name: Capture Setup
hosts: node1
tasks:
- name: Collect only specific facts
ansible.builtin.setup:
filter:
- '*distribution'
register: setup
- ansible.builtin.debug:
var: setup
With the wildcard in place, the output shows:
TASK [debug] *******************************************************************
ok: [ansible] => {
"setup": {
"ansible_facts": {
"ansible_distribution": "RedHat"
},
"changed": false,
"failed": false
}
}
With this we can conclude the variable we are looking for is labeled ansible_distribution
.
Then we can update the playbook to be explicit in its findings and change the following line:
filter:
- '*distribution'
to:
filter:
- 'ansible_distribution'
[student@ansible-1 ansible-files]$ ansible-navigator run setup_filter.yml -m stdout
Facts can be used in a Playbook like variables, using the proper naming, of course. Create this Playbook as facts.yml
in the ~/ansible-files/
directory:
---
- name: Output facts within a playbook
hosts: all
tasks:
- name: Prints Ansible facts
ansible.builtin.debug:
msg: The default IPv4 address of {{ ansible_fqdn }} is {{ ansible_default_ipv4.address }}
Tip
The "debug" module is handy for e.g. debugging variables or expressions.
Execute it to see how the facts are printed:
[student@ansible-1 ansible-files]$ ansible-navigator run facts.yml
Within the text user interface (TUI) window, type :st
to capture the following output:
PLAY [Output facts within a playbook] ******************************************
TASK [Gathering Facts] *********************************************************
ok: [node3]
ok: [node2]
ok: [node1]
ok: [ansible-1]
TASK [Prints Ansible facts] ****************************************************
ok: [node1] =>
msg: The default IPv4 address of node1 is 172.16.190.143
ok: [node2] =>
msg: The default IPv4 address of node2 is 172.16.30.170
ok: [node3] =>
msg: The default IPv4 address of node3 is 172.16.140.196
ok: [ansible-1] =>
msg: The default IPv4 address of ansible is 172.16.2.10
PLAY RECAP *********************************************************************
ansible-1 : ok=2 changed=0 unreachable=0 failed=0
node1 : ok=2 changed=0 unreachable=0 failed=0
node2 : ok=2 changed=0 unreachable=0 failed=0
node3 : ok=2 changed=0 unreachable=0 failed=0
Navigation
{% if page.url contains 'ansible_rhel_90' %}
Previous Exercise - Next Exercise
{% else %}
Previous Exercise - Next Exercise
{% endif %}
Click here to return to the Ansible for Red Hat Enterprise Linux Workshop