Ansible: Variables scope and precedence

By 2020-06-04Blog
  • No Comments
  • 1

  • Notice: Undefined offset: 0 in /digitalis/wordpress/wp-content/themes/salient/functions.php on line 1884
    0

Introduction

Variable scoping can be quite complicated on Ansible and it’s important to know what variable your playbook is going to be using. But sometimes it’s not as easy as it may appear. The documentation on Ansible’s website explains this but I’d like to run you through a scenario we found where the results were not what you would expect them to be.

Recently whilst working on a deployment where we had the same role applied to a group of servers twice with different configurations we found that it wasn’t working for us. We did a bit of investigation and we found that some of the variable precedence were not behaving as we were expecting them to.

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#ansible-variable-precedence

The scenarios below demonstrate the problem on tests 4 and 5.

Test framework

I’m going to use a simple playbook with a single role which prints variable content to the screen.

.
├── main.yml
└── roles
    └── my-role
        ├── defaults
        │   └── main.yml
        └── tasks
            └── main.yml

4 directories, 3 files

The contents of for the role is

---
- debug:
    var: day_of_the_week

and has

---
day_of_the_week: Thursday

Test 1: Load the role

Playbook

- hosts: all
  roles:
    - name: my-role

Result:
Explanation: It simply takes the default value from the role

Test 2: Override the default with a new value

- hosts: all
  vars:
    day_of_the_week: Monday
  roles:
    - name: my-role

Result:
Explanation: New value displayed as expected

Test 3: Override variable from within the role

- hosts: all
  roles:
    - name: my-role
      vars:
        day_of_the_week: Monday

Result:
Explanation: New value displayed as expected

Test 4: Load the role twice and change the default value for one of them

- hosts: all
  roles:
    - name: my-role
      vars:
        day_of_the_week: Monday
    - name: my-role

Result: is displayed twice, one for each role
Explanation: This is an unexpected result. You would have thought the result would be for the first time the role loads and for the second attempt but Ansible seems to override the value.

Test 5: Change the order of loading from Test 4

- hosts: all
  roles:
    - name: my-role
    - name: my-role
      vars:
        day_of_the_week: Monday

Result: is displayed twice, one for each role
Explanation: This is another unexpected result. Logic would dictate that the first one should be and for the second attempt. The order in which the roles are defined does not affect the result.

Test 6: Override value for both roles

- hosts: all
  roles:
    - name: my-role
      vars:
        day_of_the_week: Monday
    - name: my-role
      vars:
        day_of_the_week: Tuesday

Result: and
Explanation: This is exactly what you would expect as you’re changing the default value.

Test 7: Set global variable and override on role

- hosts: all
  vars:
    day_of_the_week: Friday
  roles:
    - name: my-role
    - name: my-role
      vars:
        day_of_the_week: Tuesday

Result: on both output
Explanation: This is yet another unexpected result similar to tests 4 and 5. The local variable set for a single role seems to override the whole playbook.

Test 8: Override variable from command line

- hosts: all
  vars:
    day_of_the_week: Friday
  roles:
    - name: my-role
    - name: my-role
      vars:
        day_of_the_week: Tuesday

and we’re running the playbook using

ansible-playbook -i localhost, \
  --connection=local \
  -v main.yml \
  -e day_of_the_week=Yesterday

Result:
Explanation: Ansible documentation states that the command line has the highest precedence and it stands to reason that all the other variables are ignored.

Test 9: Change variable with

- hosts: all
  vars:
    day_of_the_week: Friday
  pre_tasks:
    - set_fact:
        day_of_the_week: Wednesday
  roles:
    - name: my-role
      vars:
        day_of_the_week: Monday
    - name: my-role
      vars:
        day_of_the_week: Tuesday

Result: for both roles
Explanation: This is expected as has precedence over roles.

Test 10: Import variable from files

The variable is moved into two files, one defines Wednesday and loaded first and the other one sets the value of Friday and it is loaded last.

- hosts: all
  vars_files:
    - wed.yml
    - fri.yml
  roles:
    - name: my-role

Result:
Explanation: This is expected. The last value overrides the first one.

Summary

Some of the results where surprising to me.

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#ansible-variable-precedence