The concept of variables in Ansible is similar to that of variables in any programming language. In Ansible a value is assigned to a variable that can be then referenced in a playbook or on command line during playbook runtime. Variables can be used in playbooks, inventories, and at the command line as we have just mentioned.
In this guide, we take a deep dive into Ansible variables and explore how they are used.
Variable Naming Rules
Ansible follows a strict set of rules that govern how variables are named.
-
A valid variable name should start with either an uppercase or lowercase character.
-
Variable names can only contain letters ( uppercase or lowercase letters or a combination of the two ), underscores, and digits.
-
In defining variables, some strings are reserved for special purposes and cannot qualify as valid variable names. These include Playbook Keywords and Python keywords.
-
Though not a hard rule, it's always recommended to keep your variables short and meaningful to be able to describe what the variable does. This makes your life simple in Ansible.
Examples of valid variable names include:
- resident
- resident_doc
- resident205
Examples of invalid variable names
- #resident@
- resident-doc
- 205resident
Variables can be defined and referenced in various ways inside a playbook. Let us dive in and explore example usages of variables in playbook files.
Simple Variables
The most basic usage of variables is to define a variable using a single value in the playbook YAML file. Let us take a simple example of a playbook that prints a message to stdout.
---
- hosts: all
vars:
greetings: Hello everyone!
tasks:
- name: Ansible Simple Variable Example Usage
debug:
msg: "{{ greetings }}, Let’s learn Ansible variables"
The definition of a variable starts with the vars
block followed by the variable name and its corresponding value. In this example, greetings
is the variable name while Hello everyone!
is the value assigned to it.
To reference the value of the variable, encapsulate the variable inside double curly braces as such {{ greetings }}
.
When the playbook is executed, the value of the variable is accessed and printed to stdout followed by the rest of the string.
Run your deployments in a scalable and cost-effective open cloud infrastructure. Cherry Servers' secure virtual private servers offer automatic scaling, flexible pricing, and 24/7 technical support. Our pre-defined Ansible module helps you automate the installation and configuration.
Ansible Variables With Arrays
Just like in programming languages where arrays are used to store a collection of items of the same data type, in Ansible, Arrays are used to define variables with multiple values.
Arrays are defined using the syntax shown.
vars:
arrayname:
- item1
- item2
- item3
- item4
Suppose you have a list of student names to be printed to stdout. Instead of defining them as individual variables, define an array with the student names as the values.
vars:
students:
- Alice
- Mark
- Peter
Here is the complete playbook file that prints out the student names contained in the array.
---
- hosts: all
vars:
students:
- Alice
- Mark
- Peter
tasks:
- name: Ansible Array Usage Example
debug:
msg: "{{ students }}"
On runtime, the values are printed out as shown.
In addition, you can also access individual items from an array using index values ( starting from 0 ). When the playbook is modified as shown, it prints out the third value in the array which is "Peter"
.
tasks:
- name: Ansible Array Usage Example
debug:
msg: "{{ students[2] }}"
Just like in Python, you can also slice a range of elements in an array. The lower bound is inclusive, while the upper bound is exclusive. The playbook prints out the values "Alice"
and "Mark"
when you slice the array like this:
tasks:
- name: Ansible Array Usage Example
debug:
msg: "{{ students[0:2] }}"
Ansible Variables With Dictionaries
A dictionary is an unordered collection of mutable items where each item is represented as a key-value pair. In a key-value pair, each key is mapped to its associated value, and a colon ( : ) is used to separate the key from its corresponding value.
Here is a dictionary’s syntax:
vars:
arrayname:
dictionary_1:
key1: value1
key2: value2
dictionary_2:
key1: value1
key2: value2
Let us add attributes to the values to thestudents
array. The following playbook adds 3 key-value pairs to each of the dictionary elements ( Alice, Mark, and Peter ).
---
- hosts: all
vars:
students:
Alice:
gender: female
age: 21
city: Boston
Mark:
gender: male
age: 23
city: Dallas
Peter:
gender: male
age: 26
city: Miami
tasks:
- name: Ansible Dictionaries Usage Example
debug:
msg: " A list of student details: {{ students }}"
During playbook runtime, all the dictionaries and their values are printed out.
Just like arrays, you can also access individual elements in a dictionary variable. There are two ways of going about this. You can use either the dot notation or bracket notation.
The dot notation takes the format: variable.value
For example, to print out the student details for Alice
edit the playbook as follows.
tasks:
- name: Ansible Dictionaries Usage Example
debug:
msg: " A list of student details: {{ students.Alice }} "
In addition, you can further narrow down and print out the value of a specific key. For example, you can print out the gender that Alice belongs to by referencing the variable as follows.
tasks:
- name: Ansible Dictionaries Usage Example
debug:
msg: " A list of student details: {{ students.Alice.gender }} "
The bracket notation takes the following syntax: variable['value']
.The following code snippet prints out the details of the student called Alice.
tasks:
- name: Ansible Dictionaries Usage Example
debug:
msg: " A list of student details: {{ students['Alice'] }} "
Ansible Variables With Loops
Just like in programming languages, loops are used to iterate through elements in an array or multidimensional array until a condition is met. They are used to simplify the execution of repetitive tasks which can be a tedious and time-consuming affair.
Let us take a simple example. Suppose you want to create a new user on a target node called mike
. The playbook file would appear as shown with a single task for creating a new user.
---
- hosts: all
tasks:
- name: Create a new user called mike
user:
name: mike
state: present
The playbook works just fine. However, creating multiple users on the target node will compel you to write multiple tasks in a repetitive fashion. For example, this is what the playbook would look like when adding two users called mike
and sandra
.
---
- hosts: all
tasks:
- name: Create a new user called mike
user:
name: mike
state: present
- name: Create a new user called sandra
user:
name: sandra
state: present
The playbook runs as expected, but the code blocks are repetitive. Writing code in this manner is quite cumbersome.
A better approach would be to create a simple loop that iterates through the list of names. The same playbook can be re-written as follows.
---
- hosts: all
tasks:
- name: Create new users
user:
name: '{{ item }}'
state: present
loop:
- mike
- sandra
The loop
directive iterates through the entire list of names defined by the loop and stores each name in a variable called item
. Each of the items in the loop is referenced by the variable. In so doing, the playbook creates the users with fewer lines of code and avoids repetitive code blocks.
You can also loop through dictionaries. Suppose you want to attach additional attributes for the users such as uid
and comment
.
In this case, you have user 3 attributes - name
, uid
, and comment
; hence, you cannot define the single variable item
as before. In the tasks
section, you will define the variables as item.name
,item.uid
and item.comment
. These will reference the user attributes defined in the loop.
This is what the playbook looks like with additional user attributes.
---
- hosts: all
tasks:
- name: Create new users
user:
name: '{{ item.name }}'
uid: '{{ item.uid }}'
comment: '{{ item.comment }}'
state: present
loop:
- name: mike
uid: 1001
comment: Administrator
- name: sandra
uid: 1002
comment: Techie
When executed, the playbook runs and creates the users with their corresponding attributes.
Ansible Variables with Register module
The Ansible register module is used to capture the output of a task to a variable. In most cases, the task to be executed on the remote host is usually defined by the shell
or command
module. Once the register module captures the output, it is referenced in different scenarios, for example, in conditional statements or, printing the output to stdout.
Let us check out how a register can be used to capture the output of a task. The playbook below runs the uptime
bash command on a target host. The register module captures the output and the output is finally printed out to stdout.
---
- hosts: all
tasks:
- name: Ansible register variable example
shell: "uptime"
register: check_uptime
- debug:
var: check_uptime.stdout
Define Ansible Variables at Playbook Runtime
Variables can also be defined when executing a playbook by passing the variables on the command line using the --extra-vars
or -e
argument. The variable is enclosed in a single-quoted string inside a pair of single curly braces.
Variables passed during playbook runtime take the highest precedence and override the variables defined in the playbook. To better illustrate this, let us take a simple playbook that captures and prints out the value of a variable.
---
- hosts: all
vars:
car: "Corvette"
task:
- name: print message to stdout
debug:
msg: "My favorite car is {{ car }}"
Upon runtime, the string My favorite car is
and the value of the variable name Corvette
is printed.
To override the value of the variable defined in the playbook with a different value, for example, Tesla"
invoke the --extra-vars
argument followed by the key-value pair as shown.
$ sudo ansible-playbook --extra-vars '{"car":"Tesla"}' /etc/ansible/11-ansible-variable-on-command-line.yaml
This time around, the value Corvette
is replaced by Tesla
.
Discover how Tempesta, an open-source application delivery controller (ADC), leveraged Cherry Servers' bare metal cloud to complete tests and validation of their ADC successfully, benefiting from 99.97% uptime, server customization, and 24/7 technical support.
Special Variables
Special variables are a special category of variables. These cannot be directly defined by the user and they contain information pertaining to the host. These variables include facts, connection variables, and magic variables.
Ansible Facts
Ansible facts refer to system information collected about the hosts during playbook runtime. The collection of this information is called gathering facts. Facts include information about the system’s IP address, date and time, BIOS, disk partitions, and related hardware information.
To ‘gather facts’, use the special module known as the setup
module as follows:
$ sudo ansible -m setup [ hostname or hostgroup ]
For instance, to view Ansible facts associated with your local system, run the command
$ sudo ansible -m setup localhost
Ansible Connection Variables
Connection variables are used to determine Ansible execution behavior and actions on target hosts. The most widely-used connection variables are become
and become_user
.
The become
variable activates privilege escalation. When set to yes
, Ansible runs the task as root user because root is the default user for privilege escalation.
In this example, Ansible installs Apache on the target system as the root user.
- hosts: servers
become: yes
tasks:
- name: Install Apache as root user.
apt:
name: apache2
state: latest
On the other hand, the become_user
variable allows you to execute a task as someone
else with desired privileges other than the root user. This is the user you become
, and not the user you log in as.
To use this variable, you need to set the become
variable to yes
, then explicitly specify the user you want to run the task as.
In this example, the task will be executed as user cherry
on the target node, because the user is explicitly defined.
---
- hosts: servers
become: yes
become_user: cherry
Ansible Magic Variables
Finally, we have magic variables. These are variables built into Ansible and are used to access information about the Ansible application itself, hosts, host groups, and the rest of the Ansible manifest.
Consider a Playbook file shown. Using the ansible_version
variable, the playbook prints out information about Ansible itself.
---
- hosts: all
tasks:
- debug:
var: ansible_version
Wrapping up
In this guide, we looked at Ansible variables and how you can define and reference them in various use-cases. Furthermore, we also outlined some of the best practices to follow when defining variables in Playbooks to make your life simpler. Check out the official Ansible documentation for additional information on Ansible variables.