Home Ansible How To Use Variables In Ansible Playbooks

How To Use Variables In Ansible Playbooks

By Karthick
Published: Last Updated on 1k views

In our last article we discussed what Ansible playbooks are and how to create and run tasks through playbooks. In this article, we will go one step further and learn how to use variables in Ansible playbooks.

What Are Ansible Variables?

Variables are basic concepts in all the programming languages which are used to store data and later be used in the code. Similarly, ansible has variables that store some values, and they are later used in the playbook for different processing.

Ansible supports declaring variables in multiple places like playbooks, host_vars & group_vars files, and command-line arguments.

In the upcoming sections, we will discuss how to define variables in different places and learn about variable precedence.

Variable - Key, Value Mapping

Variables can be defined at the play level and task level using the "vars" keyword. After the keyword vars, the variable with key and value is given. These variables can be accessed by all the tasks in the play.

I have created one task which is using the debug module to print a message by using variable values. The variables should be enclosed with double curly braces {{ variable }}.

How To Use Debug Module In Ansible Playbooks

- name: Print vars
  hosts: m1
  gather_facts: false

  vars:
    os_name: "PoP!_OS Desktop"
    version: "21.10"

  tasks:
    - name: Task1 - Substitute variables
      debug:
        msg: "My current desktop OS is {{ os_name }} - {{ version }}"
Key-value variable Mapping

Now to run the playbook, run the following command in the terminal.

$ ansible-playbook playbook_name.yml

From the below image you can see both my variables are replaced with their values when the msg is printed to stdout.

Task Output
Task Output

Variable - List Of Elements

You can create a list of elements in a variable. If you take a look at the below definition, I have created a list variable in two ways.

  • Standard YAML way of defining a list of items/elements. Here I have given the variable names as "top_linux_desktops".
  • Python syntax for creating a list of items/elements. Here I have given the variable names as "top_desktops".
  vars:
    
    top_linux_desktops:
      - MXlinux
      - pop-os
      - Linux Mint
      - Manjaro
      - Fedora

    top_desktops: [MXLinux, pop-os, Linux Mint, Manjaro, Fedora]

You can print all the elements from the list using the variable name. I have created two tasks. The first task will print elements from the top_linux_desktops variable and the second task will print elements from the top_desktops variable.

  tasks:
    - name: Task1 - List of elements
      debug:
        msg: "My fav linux desktops are {{ top_linux_desktops }}"

    - name: Task2 - List of elements using Python syntax
      debug:
        msg: "My fav linux desktops are {{ top_desktops }}"    
List Of Elements
List Of Elements

In list, you can also access the individual element using its Index position similar to how you access elements from a python list. There are two ways to do it.

  • Using dot notation(variable.index)
  • Python notation(variable[index])

I have created two tasks. The first task uses dot notation and the second task uses python notation to print the element from the first and second positions.

  tasks:    

    - name: Task3 - Accessing List element using dot notation
      debug:
        msg: "My fav linux desktops are {{ top_linux_desktops.1 }} and {{ top_desktops[2] }}"

    - name: Task4 - Accessing List element using python notation(list[i])
      debug:
        msg: "My fav linux desktops are {{ top_linux_desktops[1] }} and {{ top_desktops[2] }}"
Print Elements Using Index Position
Print Elements Using Index Position

Variable - Dictionary

You can create a dictionary object and assign it to the variable. This is similar to python dictionaries. Dictionaries can be created in two ways.

  • standard YAML syntax to define dictionary
  • Python dictionary notation

If you can see the below playbook snippet, I have created two dictionary variables. The first variable "release_info" follows the YAML syntax approach and the second variable "new_release_info" follows python dictionary syntax.

  vars:
    release_info:
      name: PoP!_OS Desktop
      version: 22.04
      release_month: April, 2022
    
    new_release_info: { name: PoP!_OS Desktop, version: 22.04, release_month: "April, 2022"}

You can either grab all the values from the variable or a particular dictionary element using its key. Similar to the list, the dictionary also follows dot and python notation to print the value of a key.

I have created two tasks, the first task will use the dot notation to grab the element from the dictionary and the second task will use python notation to grab the element.

  tasks:

    - name: Task1 - Accessing dictionary values using its key with dot notation(dict.key)
      debug:
        msg: "{{ release_info.name }} version {{ release_info.version }} is released on {{ release_info.release_month }}"

    - name: Task2 - Accessing dictionary values using its key with python notation(dict['key'])
      debug:
        msg: "{{ new_release_info['name'] }} version {{ new_release_info['version'] }} is released on {{ new_release_info['release_month'] }}"
Dictionary Variable - Output
Dictionary Variable - Output

Play Vs Task Level Precedence

Variables can be defined at both task level and play level but variables defined at the task level take higher precedence over the variables defined at the play level.

In the below example, I have created vars at both play level and task level with the same variable names. Now when I run the playbook it will use task variable names.

  vars:
    os_name: "PoP!_OS Desktop"
    version: "21.10"

  tasks:
    - name: Task1 - Substitute variables
      vars:
        os_name: "Linux Mint"
        version: "20.03"
      debug:
          msg: "My current desktop OS is {{ os_name }} - {{ version }}"
Task vs Play - Precedence
Task vs Play - Precedence

Playbook Vs Command Line Argument Precedence

You can override the variable passed in the playbook by using -e flag. Higher precedence is given to the variables passed through -e flag.

I am running the same playbook from the previous section again overriding the variables with the -e flag.

$ ansible-playbook 4_var_precedence.yml -e "os_name=fedora" -e "version=35"
Variable Using Command Line Argument
Variable Using Command Line Argument

You can pass variables to -e flag in Json, YAML or ini format.

# INI FORMAT
$ ansible-playbook 4_var_precedence.yml -e "os_name=fedora" -e "version=35"

# JSON FORMAT
$ ansible-playbook 4_var_precedence.yml -e '{"os_name": "fedora"}' -e '{"version": 35}'

# YAML FORMAT
$ ansible-playbook 4_var_precedence.yml -e "{os_name: fedora}" -e "{version: 35}"

You can also create a separate file for variable and pass it through -e flag. The syntax will be as follows. Here I have created a file named vars.yml and grouped all my variables. Now when the file is passed to the -e flag all the variables are imported into the playbook.

$ ansible-playbook 4_var_precedence.yml -e @vars.yml

Variable File

Instead of defining the variable in the playbook, you can create a file and declare all variables in the file. I have created a file called vars.yml and grouped all the variables we have discussed in previous sections in this file.

Variable Declared In File
Variable Declared In File

Instead of using the keyword vars, you should use vars_files In the playbook and pass the file name. Now when you run the playbook ansible will pick the variables from the file. The file can be in any path.

Var_files Keyword In Playbook
Var_files Keyword In Playbook
Variables Defined In File
Variables Defined In File

Host And Group Variables

You can define host level and group level variables in the inventory file. You can refer to the following article where we have briefly discussed how to create host level and group level variables.

Ansible Inventory And Configuration Files

As a best practice, you should not define the variables inside the inventory file instead you can create directories for host_vars and group_vars and ansible will automatically pick the files in the directory. Create a directory called host_vars.

$ mkdir host_vars

Inside host_vars directory, you can define host-level variables i.e. you can create an INI, YAML or JSON format file and store variables for a particular host. If you take a look at my inventory file below I have two hosts named “ubuntu” and “rocky” and created the variable file for each host.

Heads Up: The files should be named the same as the host/alias name in your inventory file.

# Inventory file
[m1]
ubuntu ansible_host=ubuntu.anslab.com 

[m2]
rocky ansible_host=rocky.anslab.com
$ mkdir host_vars/ubuntu.yml
$ echo "message: This variable is read from host_vars/ubuntu.yml file" > host_vars/ubuntu.yml"

$ mkdir host_vars/rocky.yml
$ echo "message: This variable is read from host_vars/rocky.yml file" > host_vars/rocky.yml

I have added a variable named "message" in both the variable files. Now if I run my playbook, variables will be picked up from these two files.

Host_vars - Variable Definition
Host_vars - Variable Definition

Similarly, you can also create variable files for groups. Create a directory "group_vars" and create a file with the group name as per the inventory file.

[m1]
ubuntu ansible_host=ubuntu.anslab.com 

[m2]
rocky ansible_host=rocky.anslab.com

[servers:children]
m1
m2

I have created a child group called "servers", so I am creating the file name as servers.yml.

$ mkdir group_vars
$ mkdir group_vars/servers.yml
$ echo "message: This variable is read from group_vars/servers.yml file" > group_vars/servers.yml

Now if I run the playbook it will read the servers.yml from group_vars.

Group Variables
Group Variables

Heads Up: If you have both host_vars and group_vars, ansible will first search for host_vars definitions, and if not found it will go to group_vars.

Magic Variables

Ansible provides some internal variables where the state of the variable is defined when you run the playbook. We can use these variables through the playbook. To get the list of available special variables you can refer to the following link.

Ansible Special Variables

For example, there is a variable called inventory_dir which stores the absolute path for the inventory file that is used by the playbook.

    - name: Magic Variables - Get inventory directory path
      debug:
        msg: "{{ inventory_dir }}"
Magic Variables
Magic Variables

An important magic variable is hostvars. This variable is going to print a collection of some magic variables in the json format.

      - name: Magic Variables - hostvars
        debug:
          msg: "{{ hostvars }}"
HostVars Output
HostVars Output

The output contains information in str, list, and dictionary format. Let’s say I want to check in which group my ubuntu host is in then I can get it in the following way. I am using python syntax notation here.

      - name: Magic Variables 
        debug:
          msg: "{{ hostvars['ubuntu']['group_names'] }}"
Group Names
Group Names

Not all magic variables are useful in day-to-day operations. Take a look at all the magic variables and see which one fits your use case.

Facts As Variable

When you run the playbook ansible will use the setup module and collect facts from the targeted hosts and keep the output in memory so it can be used in the playbook. Facts are also called playbook variables.

First, get to know about the facts output so you can grab particular attributes. Run the following command which will collect the facts output and store it in a file.

$ ansible all -m setup --tree /tmp/facts_result

Separate output file will be created for each host. If you take a look at the output it is nothing but JSON format output.

Facts Output
Facts Output

The attributes in the facts output will be in List, Dictionary, and AnsibleUnsafeText format. Below are a few examples of different types.

      - name: Facts output - AnsibleUnsafeText
        debug:
          msg: "{{ discovered_interpreter_python }}"

      - name: Facts output - List
        debug:
          msg: "{{ ansible_all_ipv4_addresses }}"

      - name: Facts output - Dictionary
        debug:
          msg: "{{ ansible_python }}"
Facts Output1
Facts Output

There are tons of information collected by facts so take your time to go through the output and see what fits your requirement.

Conclusion

In this article, we have discussed what is ansible variable and how to declare variables in different places. Variable precedence is very important when declaring variables and that is covered in this article. We also discussed magic variables and their use case. Finally, we covered what is facts and how to use facts output as variables.

You May Also Like

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies to improve your experience. By using this site, we will assume that you're OK with it. Accept Read More