Skip to content

Commit a2599ca

Browse files
committed
Fix variable precedence of INI/script vars to be in-line with docs.
This commit also adds a new test script (ansible-var-precedence-check.py in code-smell/) to provide us with another line of defense against precedence bugs going forward. The precedence docs state that the INI vars have a lower precedence than group/host vars files for inventory and playbooks, however that has not been the case since 2.0 was released. This change fixes that in one way, though not exactly as the docs say. The rules are: 1) INI/script < inventory dir < playbook dir 2) "all" group vars < other group_vars < host_vars So the new order will be (from the test script mentioned above): 8. pb_host_vars_file - var in playbook/host_vars/host 9. ini_host_vars_file - var in inventory/host_vars/host 10. ini_host - host var inside the ini 11. pb_group_vars_file_child - var in playbook/group_vars/child 12. ini_group_vars_file_child - var in inventory/group_vars/child 13. pb_group_vars_file_parent - var in playbook/group_vars/parent 14. ini_group_vars_file_parent - var in inventory/group_vars/parent 15. pb_group_vars_file_all - var in playbook/group_vars/all 16. ini_group_vars_file_all - var in inventory/group_vars/all 17. ini_child - child group var inside the ini 18. ini_parent - parent group var inside the ini 19. ini_all - all group var inside the ini Fixes #21845
1 parent ff20ab7 commit a2599ca

File tree

3 files changed

+557
-15
lines changed

3 files changed

+557
-15
lines changed

docs/docsite/rst/playbooks_variables.rst

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -830,20 +830,25 @@ In 1.x, the precedence is as follows (with the last listed variables winning pri
830830
In 2.x, we have made the order of precedence more specific (with the last listed variables winning prioritization):
831831

832832
* role defaults [1]_
833-
* inventory vars [2]_
834-
* inventory group_vars
835-
* inventory host_vars
836-
* playbook group_vars
837-
* playbook host_vars
833+
* inventory INI or script group vars [2]_
834+
* inventory group_vars/all
835+
* playbook group_vars/all
836+
* inventory group_vars/*
837+
* playbook group_vars/*
838+
* inventory INI or script host vars [2]_
839+
* inventory host_vars/*
840+
* playbook host_vars/*
838841
* host facts
839842
* play vars
840843
* play vars_prompt
841844
* play vars_files
842-
* registered vars
843-
* set_facts
844-
* role and include vars
845+
* role vars (defined in role/vars/main.yml)
845846
* block vars (only for tasks in block)
846847
* task vars (only for the task)
848+
* role (and include_role) params
849+
* include params
850+
* include_vars
851+
* set_facts / registered vars
847852
* extra vars (always win precedence)
848853

849854
Basically, anything that goes into "role defaults" (the defaults folder inside the role) is the most malleable and easily overridden. Anything in the vars directory of the role overrides previous versions of that variable in namespace. The idea here to follow is that the more explicit you get in scope, the more precedence it takes with command line ``-e`` extra vars always winning. Host and/or inventory variables can win over role defaults, but not explicit includes like the vars directory or an ``include_vars`` task.

lib/ansible/vars/__init__.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,19 +249,17 @@ def get_vars(self, loader, play=None, host=None, task=None, include_hostvars=Tru
249249
all_vars = combine_vars(all_vars, task._role.get_default_vars(dep_chain=task.get_dep_chain()))
250250

251251
if host:
252-
# next, if a host is specified, we load any vars from group_vars
253-
# files and then any vars from host_vars files which may apply to
254-
# this host or the groups it belongs to
252+
# first we merge in vars from groups specified in the inventory (INI or script)
253+
all_vars = combine_vars(all_vars, host.get_group_vars())
255254

256-
# we merge in the special 'all' group_vars first, if they exist
255+
# next, we load any vars from group_vars files and then any vars from host_vars
256+
# files which may apply to this host or the groups it belongs to. We merge in the
257+
# special 'all' group_vars first, if they exist
257258
if 'all' in self._group_vars_files:
258259
data = preprocess_vars(self._group_vars_files['all'])
259260
for item in data:
260261
all_vars = combine_vars(all_vars, item)
261262

262-
# we merge in vars from groups specified in the inventory (INI or script)
263-
all_vars = combine_vars(all_vars, host.get_group_vars())
264-
265263
for group in sorted(host.get_groups(), key=lambda g: (g.depth, g.name)):
266264
if group.name in self._group_vars_files and group.name != 'all':
267265
for data in self._group_vars_files[group.name]:

0 commit comments

Comments
 (0)