# Var precedence

**URL:** <https://forum.ansible.com/t/var-precedence/12865>\
**Category:** Ansible Project\
**Tags:** ansible-project\
**Created:** [May 24, 2013, 9:01pm UTC](https://forum.ansible.com/t/var-precedence/12865 "2013-05-24T21:01:56Z")\
**Posts on this page:** 15\
**Page:** 2

<div class="post-metadata">

**Author:** ![martin\_f\_krafft](https://avatars.discourse-cdn.com/v4/letter/m/8797f3/32.png) [@martin\_f\_krafft](https://forum.ansible.com/u/martin_f_krafft)\
**Post date:** [June 13, 2013, 3:53pm UTC](https://forum.ansible.com/t/var-precedence/12865/21 "2013-06-13T15:53:08Z")

</div>

also sprach Michael DeHaan \<michael@ansibleworks.com\> [2013.06.13.1719 +0200]:

> Ansible intentionally lacks vars\_scoping.
> 
> It's all part of the simplicity of things to not have to have  
> conversations about scoping.

I am really failing to see your "simplicity of things" argument, and  
I also doubt that there are really people who \*want\* \*exactly\* the  
current behaviour, namely:

&nbsp;&nbsp;- roles (i.e. reusable, sharable code) can overwrite variables in  
&nbsp;&nbsp;&nbsp;&nbsp;playbooks, and even the ones that are very specific to the  
&nbsp;&nbsp;&nbsp;&nbsp;inventory (host\_vars, group\_vars). This means that using a role  
&nbsp;&nbsp;&nbsp;&nbsp;may well break other, completely unrelated parts of my setup;

&nbsp;&nbsp;- role variables themselves can all be overwritten by other roles  
&nbsp;&nbsp;&nbsp;&nbsp;and vars\_files, not only through parametrised role includes. You  
&nbsp;&nbsp;&nbsp;&nbsp;are advocating a soft, "by-convention" remediation that is  
&nbsp;&nbsp;&nbsp;&nbsp;functionally equivalent to scoping, but optional and  
&nbsp;&nbsp;&nbsp;&nbsp;error-prone;

&nbsp;&nbsp;- roles basically do not have an interface and do not obey any  
&nbsp;&nbsp;&nbsp;&nbsp;form of imperative paradigms or closure. It feels a bit like  
&nbsp;&nbsp;&nbsp;&nbsp;the re-use you are trying to achieve with roles is equivalent to  
&nbsp;&nbsp;&nbsp;&nbsp;giving root access to the developers of tools I want to use;

&nbsp;&nbsp;- there is no way to find out what may be tempering/overwriting my  
&nbsp;&nbsp;&nbsp;&nbsp;variables after all variables from all over the place have been  
&nbsp;&nbsp;&nbsp;&nbsp;munged in the global namespace according to precedence rules  
&nbsp;&nbsp;&nbsp;&nbsp;that do not obey the "most-specific-wins" principle. In fact,  
&nbsp;&nbsp;&nbsp;&nbsp;I'd argue that the way variable resolution takes place is  
&nbsp;&nbsp;&nbsp;&nbsp;actually almost non-determinstic in the event of multiple,  
&nbsp;&nbsp;&nbsp;&nbsp;conflicting defintions;

&nbsp;&nbsp;- role include parametrisation syntax is different from playbook  
&nbsp;&nbsp;&nbsp;&nbsp;include parametrisation syntax. The former, requiring me to  
&nbsp;&nbsp;&nbsp;&nbsp;enter ascii-representations of data structures feels like a hack  
&nbsp;&nbsp;&nbsp;&nbsp;at best;

Who could possibly want all of that?

> I recognize that this is different from what some people want, but  
> at the same time being \*exactly\* what some people want.

Good software, especially "simple" software, hard-codes no  
assumptions; it provides flexible interfaces and leaves all the rest  
up to the user.

---

<div class="post-metadata">

**Author:** ![David\_Golden](https://avatars.discourse-cdn.com/v4/letter/d/d2c977/32.png) [@David\_Golden](https://forum.ansible.com/u/David_Golden)\
**Post date:** [June 13, 2013, 5:12pm UTC](https://forum.ansible.com/t/var-precedence/12865/22 "2013-06-13T17:12:20Z")

</div>

> Ansible intentionally lacks vars\_scoping.
> 
> It's all part of the simplicity of things to not have to have conversations  
> about scoping.

I think you're having them. 🙂

> If you want something named foo\_port, don't name the variable port, etc.

Assuming no scoping, then having conventions like "prefix role  
variables with the role name" seems like the best.

But even that doesn't help me understand what to expect if I use a  
parameterized role more than once.

E.g. I set "myrole\_foo" variable with a default of "bar" in the  
role/myrole/vars/main.yml file. Then I have playbook that call the  
role once overriding "myrole\_foo" and once without:

&nbsp;&nbsp;&nbsp;&nbsp;- { role: myrole, myrole\_foo: baz }  
&nbsp;&nbsp;&nbsp;&nbsp;- { role: myrole }

In the second role invocation, is "myrole\_foo" the default "bar" or is  
it "baz" because it's a global overwritten by the first role  
invocation? From what you said about scope, I think it's going to be  
"baz".

If so, then the global scope \*severely\* restrict the ability to have  
reusable roles with defaults. Roles have to be fully parameterized to  
ensure the globals are set correctly for each invocation. That's not  
DRY.

I realize getting scoping right is hard, but I think it's worth it to  
figure out the right way to make it work for ansible.

David

---

<div class="post-metadata">

**Author:** ![Sebastien\_Simard](https://avatars.discourse-cdn.com/v4/letter/s/43a26b/32.png) [@Sebastien\_Simard](https://forum.ansible.com/u/Sebastien_Simard)\
**Post date:** [June 13, 2013, 6:28pm UTC](https://forum.ansible.com/t/var-precedence/12865/23 "2013-06-13T18:28:50Z")

</div>

Just wondering: have you guys considered making variables immutable once set?  
This approach is used by the ant build tool (see [1]), and it seems to me that it _might_ make reasoning about playbooks easier and fit quite naturally with the sequential execution model that ansible follows.

Just a thought,

- Seb

[1] [https://ant.apache.org/manual/Tasks/property.html](https://ant.apache.org/manual/Tasks/property.html)

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [June 13, 2013, 7:20pm UTC](https://forum.ansible.com/t/var-precedence/12865/24 "2013-06-13T19:20:21Z")

</div>

Yeah guys, I understand you don’t like things.

Ultimately, if you feel this way, it might not be for you.

There is precedence as defined in the docs.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [June 13, 2013, 7:28pm UTC](https://forum.ansible.com/t/var-precedence/12865/25 "2013-06-13T19:28:48Z")

</div>

BTW, if you pass a variable to the role on the role line, that’s not used later.

I guess I shouldn’t say there’s no scope, I should say that vars\_files do not apply only to their specific role.

This is not true of parameters _passed_ to roles, those only apply there.

---

<div class="post-metadata">

**Author:** ![David\_Golden](https://avatars.discourse-cdn.com/v4/letter/d/d2c977/32.png) [@David\_Golden](https://forum.ansible.com/u/David_Golden)\
**Post date:** [June 13, 2013, 8:25pm UTC](https://forum.ansible.com/t/var-precedence/12865/26 "2013-06-13T20:25:50Z")

</div>

> BTW, if you pass a variable to the role on the role line, that's not used  
> later.

That's good to know!

> I guess I shouldn't say there's no scope, I should say that vars\_files do  
> not apply only to their specific role.

So now I'm confused. You said Ansible intentionally lacks vars  
scoping, but you do appear to have vars scoping for roles.

It would be really helpful to get some more clarity around all the  
different ways that variables can be set and the precedence between  
them now that roles are in the picture.

What I get from the docs is this:

\* inventory variables -- host vars and group vars

\* playbook variables -- vars\_file, extra vars on command line, vars in playbook

\* "set during the play" -- register option, set\_fact module, custom  
facts returned from modules

If I understand you correctly, a role vars file is equivalent to a  
playbook vars\_file (but what precedence between them?).

And you said that parameters provided to a role invocation survive the  
role invocation only. But do they have more precedence than anything  
else? Or only more precedence than other things at the playbook  
level? Or something else?

Unrelated to roles, do register variables survive the play? set\_fact  
is defined as surviving the play and collected facts clearly do.

Part of what I'm struggling to grok is the interaction between  
"precedence" and "survives X part of process".

David

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [June 13, 2013, 8:35pm UTC](https://forum.ansible.com/t/var-precedence/12865/27 "2013-06-13T20:35:37Z")

</div>

It’s been a busy day, roles and tasks can be passed variables, inventory scope is also different than things defined in variable files.

So I was wrong to say there was not scoping.

I initially understood this thread to be about something like having arbitrary levels of scope and nesting, which we intentionally do _not_ have.

It is very important for me to persue a modelling/infrastructure-as-data approach as to being a system that needs to discuss “clojures” and other things, which I believe is a major problem in the automation tools space that excludes users.

What we do is it make it easy to describe what you want to do, and we don’t dwell on the terminology quite so much 🙂

registered variables are available for the rest of the playbook run, and are accessible for other hosts via “hostvars”, which is covered in the docs.

---

<div class="post-metadata">

**Author:** ![martin\_f\_krafft](https://avatars.discourse-cdn.com/v4/letter/m/8797f3/32.png) [@martin\_f\_krafft](https://forum.ansible.com/u/martin_f_krafft)\
**Post date:** [June 13, 2013, 9:08pm UTC](https://forum.ansible.com/t/var-precedence/12865/28 "2013-06-13T21:08:40Z")

</div>

also sprach Michael DeHaan \<michael@ansibleworks.com\> [2013.06.13.2235 +0200]:

> It's been a busy day, roles and tasks can be passed variables,  
> inventory scope is also different than things defined in variable  
> files.
> 
> So I was wrong to say there was not scoping.
> 
> I initially understood this thread to be about something like  
> having arbitrary levels of scope and nesting, which we  
> intentionally do \*not\* have.

There are two issues at hand:

&nbsp;&nbsp;1. some of us believe that a role's vars/main.yml file should  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;define defaults at a very low level of precedence, i.e. \*below\*  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the inventory variables;

&nbsp;&nbsp;2. some of us believe that there ought to be no global scope at  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;all (thereby eradicating (1.)), but that each role should have  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;its own scope and variables set within a role cannot ever leak  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outside the role. Only through role parametrisation can those  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;variables be overridden, although I feel it would be better if  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the role author could specify a subset of variables that are  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;changeable;

I initially came at things from the point of view of (1.), asking  
for counter-arguments, and the recent comment on the badness of  
the global scope and the goodness of thinking about roles as an  
imperative paradigm helped me move on to (2.).

As I attempted to illustrate in  
msgid:\<20130613155308.GB5350@fishbowl.rw.madduck.net\>, I think the  
lack of scoping of role variables is a serioues problem. I hope that  
you are not going to shut the doors on this one and say that "while  
some might not like it, others do, and I won't change it", because  
that would be a shame.

> It is very important for me to persue  
> a modelling/infrastructure-as-data approach as to being a system  
> that needs to discuss "clojures" and other things, which I believe  
> is a major problem in the automation tools space that excludes  
> users.

Closure is not that hard of a concept and it's always a question of  
whom you target. I think it's reasonable to assume that anyone who  
seeks to control large numbers of systems with an automating tool  
such as Ansible can be expected to know basic imperative paradigms,  
including common closure/scoping, and precedence rules.

I'd even go as far as to say that if anyone approached a set of  
machines with an automation tool without that knowledge, they would  
do really well long-term investing time now to learn these basic  
principles.

Excluding users is never good. But for the same reason as I don't  
think that tools like webmin or PHPMyAdmin ("web-based root over  
PHP") should ever be touched, I don't think that automation tools  
should be written with sympathy for dummies.

---

<div class="post-metadata">

**Author:** ![David\_Golden](https://avatars.discourse-cdn.com/v4/letter/d/d2c977/32.png) [@David\_Golden](https://forum.ansible.com/u/David_Golden)\
**Post date:** [June 13, 2013, 11:33pm UTC](https://forum.ansible.com/t/var-precedence/12865/29 "2013-06-13T23:33:42Z")

</div>

> &nbsp;&nbsp;1. some of us believe that a role's vars/main.yml file should  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;define defaults at a very low level of precedence, i.e. \*below\*  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the inventory variables;

I can easily see how different people might reach different  
conclusions on that point, simply on what they see as the most  
specific element of their orchestration. Inventories and playbooks  
are a many-many mapping, so depending on whether you have more of one  
or the other, it's pretty arbitrary which seems more specific to any  
person.

That doesn't bother me as long as it's clearly documented.

Personally, I think such variables should be orthogonal in practice.  
Inventory vars should be about the inventory. Putting playbook (or  
role) defaults there leads to global variable spaghetti. I don't mind  
taking an inventory variable and passing it explicitly to a role  
parameter because that makes the code very clear.

> &nbsp;&nbsp;2. some of us believe that there ought to be no global scope at  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;all (thereby eradicating (1.)), but that each role should have  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;its own scope and variables set within a role cannot ever leak  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;outside the role. Only through role parametrisation can those  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;variables be overridden, although I feel it would be better if  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the role author could specify a subset of variables that are  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;changeable;

I don't think there has to be no global scope. On reflection my  
concern is mostly about whether re-usable constructs (roles and  
includes) that take parameter get dynamic scope for their parameters  
or not. (For anyone not clear on "dynamic scope", see  
[https://en.wikipedia.org/wiki/Dynamic\_scope#Lexical\_scoping\_and\_dynamic\_scoping.](https://en.wikipedia.org/wiki/Dynamic_scope#Lexical_scoping_and_dynamic_scoping.))

The use of global scope for most variables -- particularly collected  
facts -- does makes it easy to sidestep explicit parameter passing and  
returns. I get why that is "simpler" for most common tasks.

As I said in some other thread, it does mean having to be more careful  
about variable names. For instance, I've taken to always using the  
role name as a prefix for role variables. That's fine. It's a bit  
verbose, but it works.

David

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [June 14, 2013, 3:57pm UTC](https://forum.ansible.com/t/var-precedence/12865/30 "2013-06-14T15:57:26Z")

</div>

There’s really not a need for variable immutability actually.

What happens is the global things, like vars\_files, apply globally, and setting inventory variables and facts does not stomp into the global scope, but are stored on a per host basis. See “hostvars” and the like in the docs.

Yeah, I mispoke when I said there was no scope 🙂 Consequence of posting during AnsibleFest when I had limited time.

I meant to say we don’t have anything like block scoping on purpose, because that’s confusing 🙂

---

<div class="post-metadata">

**Author:** ![GW1](https://avatars.discourse-cdn.com/v4/letter/g/c89c15/32.png) [@GW1](https://forum.ansible.com/u/GW1)\
**Post date:** [June 20, 2013, 8:54am UTC](https://forum.ansible.com/t/var-precedence/12865/31 "2013-06-20T08:54:52Z")

</div>

Hi,

> ```auto
> 1. some of us believe that a role's vars/main.yml file should
> define defaults at a very low level of precedence, i.e. *below*
> the inventory variables;
> 
> ```
> 
> ```auto
> 
> ```

```auto
Sorry for bringing up the old thread, but what do you all think of introducing "vars_defaults"

```

```auto
in plays that would be similar to "vars_files", but would have either the lowest possible priority

```

```auto
(lower than "group_vars/all") or at least lower than "vars" (above all inventory variables)?

```

```auto

```

```auto
If roles would than (maybe configurable behavior), instead of "vars_files: .../vars/main.yml"

```

```auto
implicitly use "vars_defaults: .../vars/main.yml" this would solve all precedence issues. Or maybe

```

```auto
roles could implicitly use "vars_defaults: .../vars/defaults.yml" and "vars_files: .../vars/main.yml".

```

```auto

```

```auto
Use case for a couple of re-usable roles each with its own "vars/main.yml" that all define the same

```

```auto
variables and you want to override most of them would result in unnecessary large play, because

```

```auto
you need to specify role parameters over and over again. Eg.:

```

```auto

```

```auto
- hosts: xxx

```

```auto
  roles:

```

```auto
    - role: net_basic

```

---

<div class="post-metadata">

**Author:** ![martin\_f\_krafft](https://avatars.discourse-cdn.com/v4/letter/m/8797f3/32.png) [@martin\_f\_krafft](https://forum.ansible.com/u/martin_f_krafft)\
**Post date:** [June 20, 2013, 12:56pm UTC](https://forum.ansible.com/t/var-precedence/12865/32 "2013-06-20T12:56:31Z")

</div>

also sprach GW \<gw.2013@tnode.com\> [2013.06.20.1054 +0200]:

> Sorry for bringing up the old thread, but what do  
> you all think of introducing "vars\_defaults"

I think this is a cool idea:

&nbsp;&nbsp;- vars\_defaults in addition to vars and vars\_files in playbooks;  
&nbsp;&nbsp;- vars/defaults.yml, or defaults/main.yml to populate that from  
&nbsp;&nbsp;&nbsp;&nbsp;a role;  
&nbsp;&nbsp;- vars\_defaults would have the lowest precedence, i.e. below  
&nbsp;&nbsp;&nbsp;&nbsp;group\_vars.

However, I could still imagine newcomers being confused by the link  
between vars/main.yml and vars\_files. Once that is understood, the  
nomenclature makes sense, i.e. vars/\*.yml are all vars\_files. But  
then we don't want to have a special case for defaults.yml…

So maybe defaults, defaults\_files, and defaults/main.yml?

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [June 20, 2013, 4:13pm UTC](https://forum.ansible.com/t/var-precedence/12865/33 "2013-06-20T16:13:25Z")

</div>

I worry about introducing an additional level of complexity and another place to put variables.

group\_vars/ is a great place to put defaults, and in 1.2 and later you can store those directories alongside your playbooks.

Basically our goal should be to have as few conceptual places to put things as possible to keep it easy to remember.

This is why “roles/” are just some magic on top of things we already had in previous versions of Ansible.

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [June 20, 2013, 7:23pm UTC](https://forum.ansible.com/t/var-precedence/12865/34 "2013-06-20T19:23:47Z")

</div>

vars\_fallback, might be a more apropos name (last resort).

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan2](https://avatars.discourse-cdn.com/v4/letter/m/da6949/32.png) [@Michael\_DeHaan2](https://forum.ansible.com/u/Michael_DeHaan2)\
**Post date:** [June 20, 2013, 8:34pm UTC](https://forum.ansible.com/t/var-precedence/12865/35 "2013-06-20T20:34:47Z")

</div>

It’s still another keyword.

Not adding anything new here for now.

–Michael

[Previous page](https://forum.ansible.com/t/var-precedence/12865.md?page=1)
