Ansible Advanced Course

Variables and Jinja2

Variable Scope

In this article, we explore the concept of variable scope in Ansible and explain how the location where variables are defined determines their accessibility.

Host-Level Variables

Consider an inventory file where the DNS server is specified only for the host web2:

/etc/ansible/hosts
web1 ansible_host=172.20.1.100
web2 ansible_host=172.20.1.101 dns_server=10.5.5.4
web3 ansible_host=172.20.1.102

In this example, running a playbook that prints the dns_server variable for all hosts results in the variable being defined only for web2:

---
- name: Print DNS Server
  hosts: all
  tasks:
    - debug:
        msg: "{{ dns_server }}"

The output will be:

PLAY [Check /etc/hosts file] *********************************************************
TASK [debug] *********************************************************************
ok: [web1] => {
    "dns_server": "VARIABLE IS NOT DEFINED!"
}
ok: [web2] => {
    "dns_server": "10.5.5.4"
}
ok: [web3] => {
    "dns_server": "VARIABLE IS NOT DEFINED!"
}

This demonstrates the host scope: each host only accesses the variables defined specifically for it.

The image illustrates a network diagram showing variable scopes for hosts, including web servers (web1, web2, web3) and a DNS server with IP 10.5.5.4.

When a playbook runs, Ansible associates variables with each host based on inventory and group variable files. By default, the primary scope during playbook execution is the host scope.

Play-Level Variables

Next, consider a scenario where a variable is defined within a play. In the following playbook, the variable ntp_server is defined only in the first play, making it accessible there but not in the second play:

---
- name: Play1
  hosts: web1
  vars:
    ntp_server: 10.1.1.1
  tasks:
    - debug:
        var: ntp_server

- name: Play2
  hosts: web1
  tasks:
    - debug:
        var: ntp_server

The output will be:

PLAY [Play1] *********************************************************************
TASK [debug] *********************************************************************
ok: [web1] => {
    "ntp_server": "10.1.1.1"
}

PLAY [Play2] *********************************************************************
TASK [debug] *********************************************************************
ok: [web1] => {
    "ntp_server": "VARIABLE IS NOT DEFINED!"
}

This example illustrates the play scope: variables defined in one play do not automatically carry over to subsequent plays.

Global Variables

Global (or extra) variables are available throughout the entire execution of a playbook. For instance, if you run the playbook with an extra variable like so:

$ ansible-playbook playbook.yml --extra-vars "ntp_server=10.1.1.1"

And use this playbook:

---
- name: Play1
  hosts: web1
  vars:
    ntp_server: 10.1.1.1
  tasks:
    - debug:
        var: ntp_server

- name: Play2
  hosts: web1
  tasks:
    - debug:
        var: ntp_server

Both plays will have access to the ntp_server variable, producing the following output:

PLAY [Play1] *****************************************************************
TASK [debug] ******************************************************************
ok: [web1] => {
  "ntp_server": "10.1.1.1"
}

PLAY [Play2] *****************************************************************
TASK [debug] ******************************************************************
ok: [web1] => {
  "ntp_server": "10.1.1.1"
}

Conclusion

Understanding variable scopes—host, play, and global—is essential for managing configurations and troubleshooting within Ansible playbooks. Each scope offers a level of variable visibility that can be strategically utilized to create efficient and modular playbooks.

Note

For further details on variable precedence and advanced usage, consult the Ansible Documentation.

Thank you for reading, and happy automating!

Watch Video

Watch video content

Previous
Variable Precedence