How To Use Variables in Ansible Playbooks

July 26th, 2022
How To Use Variables in Ansible Playbooks

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.

Print a single Ansible variable to terminal

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.

Print Ansible array to terminal

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] }}"

Access a single array element

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] }}"

Slice an array

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.

Print Ansible dictionary to terminal

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 }} "

Select a single dictionary element

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 }} "

Select a specific dictionary element

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'] }} "

Select a dictionary member using bracket notation

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

Create a new Linux user with Ansible

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.

Create several Linux users with Ansible

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.

Create several Linux users with Ansible loops

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.

Create new Linux users with additional attributes using Ansible loops

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

Using Ansible register module

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-varsor -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 Corvetteis printed.

Print Ansible variable from a playbook

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

Overwrite Ansible variable by pasing a new value upon runtime

This time around, the value Corvette is replaced by Tesla.

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

Print Ansible facts about your system

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

Become a root user with Ansible

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_versionvariable, the playbook prints out information about Ansible itself.

---
- hosts: all
  tasks:
  - debug:
      var: ansible_version

Print 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.

Helping engineers learn 💡 about new technologies and ingenious IT automation use cases to build better systems 💻

Join Cherry Servers Community

Get monthly practical guides about building more secure, efficient and easier to scale systems on an open cloud ecosystem.

We use cookies to ensure seamless user experience for our website. Required cookies - technical, functional and analytical - are set automatically. Please accept the use of targeted cookies to ensure the best marketing experience for your user journey. You may revoke your consent at any time through our Cookie Policy.