In Ansible, definition of variable precedence is often overlooked. Despite what I wrote in my previous blog (Use Ansible like a Programming Language), Ansible is not exactly a programming language. There is a difference, especially on the way variables are managed.
At the beginning, as I am used to scripting, I was a bit confused by the way Ansible is handling variables.
For example, let’s say you have a string variable defined in group_vars/all.yml:
--- MyVar: ‘all.yml’
In same file, I define another variable using that variable:
WhereIsMyVariableEvaluated: ‘MyVar is coming from {{ MyVar }}’
I initially expected WhereIsMyVariableEvaluated variable to always be equal to ‘MyVar is coming from all.yml’ if all steps are evaluated in sequence. However, it might not depending on MyVar value override. This is variable precedence.
Thus, Ansible documentation has is a nice long list of priorities (from low to high priority):
- command line values (for example, -u my_user, these are not variables)
- role defaults (defined in role/defaults/main.yml)
- inventory file or script group vars
- inventory group_vars/all
- playbook group_vars/all
- inventory group_vars/*
- playbook group_vars/*
- inventory file or script host vars
- inventory host_vars/*
- playbook host_vars/*
- host facts / cached set_facts
- play vars
- play vars_prompt
- play vars_files
- role vars (defined in role/vars/main.yml)
- block vars (only for tasks in block)
- task vars (only for the task)
- include_vars
- set_facts / registered vars
- role (and include_role) params
- include params
- extra vars (for example, -e “user=my_user”)(always win precedence)
OK, but then what does it mean?
Run a simple playbook
First, I create a playbook with this simple task that will display WhereIsMyVariableEvaluated variable content:
--- - name: Test playbook hosts: localhost tasks: - name: Print WhereIsMyVariableEvaluated ansible.builtin.debug: msg: '{{ WhereIsMyVariableEvaluated }}'
Secondly, I have setup a WSL (Windows Subsystem Linux) Ubuntu machine with Ansible package installed and to run it, as it does not imply any server modification, I am using “-c local” option.
$ ansible-playbook playbook.yml -c local PLAY [Test playbook] ********************************************************************************** TASK [Print WhereIsMyVariableEvaluated] *************************************************************** ok: [localhost] => { "changed": false, "msg": "MyVar is coming from all.yml" } PLAY RECAP ******************************************************************************************** localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Until now, nothing unexpected.
Afterward, we can try to define MyVar in host_vars/localhost.yml (priority 10):
PLAY [Test playbook] ********************************************************************************** TASK [Print WhereIsMyVariableEvaluated] *************************************************************** ok: [localhost] => { "changed": false, "msg": "MyVar is coming from localhost.yml" }
Next, defining MyVar from within playbook itself, adding lines 4 and 5:
--- - name: Test playbook hosts: localhost vars: MyVar: 'playbook' tasks: - name: Print WhereIsMyVariableEvaluated ansible.builtin.debug: msg: '{{ WhereIsMyVariableEvaluated }}'
As a result, output of playbook run:
... TASK [Print WhereIsMyVariableEvaluated] ******************************************************************************** ok: [localhost] => { "changed": false, "msg": "MyVar is coming from playbook" } ...
Finally, I can run playbook with an argument (highest priority (22)):
$ ansible-playbook playbook.yml -c local -e "MyVar=CLI" ... TASK [Print WhereIsMyVariableEvaluated] ******************************************************************************** ok: [localhost] => { "changed": false, "msg": "MyVar is coming from CLI" } ...
All these modifications were done by adding only, meaning nothing was removed from any yml file where MyVar was defined. This means previous definitions remained, but still highest priority is chosen by Ansible.
Conclusion
In short, WhereIsMyVariableEvaluated uses MyVar which was defined more recently. This mechanism allows to define default values for variable and overload them when required for specific hosts or groups while running a playbook.
I hope this have helped you to better understand and feel how Ansible variable precedence works.
Cet article What is Variable Precedence in Ansible? est apparu en premier sur Blog dbi services.