# Evaluate group\_vars directories and files recursively

**URL:** <https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169>\
**Category:** Ansible Project\
**Created:** [April 23, 2019, 9:18am UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169 "2019-04-23T09:18:05Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Uffi\_Schnuffi1](https://avatars.discourse-cdn.com/v4/letter/u/e47774/32.png) [@Uffi\_Schnuffi1](https://forum.ansible.com/u/Uffi_Schnuffi1)\
**Post date:** [April 23, 2019, 9:18am UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/1 "2019-04-23T09:18:05Z")

</div>

Hey,

I remember that I once initially did this and naturally assumed it would work.

I now again am at the point where I find this could be immensely useful.

Let’s take the following inventory:

```auto
[all]
abc-group1-1.envA

abc-group1-1.envB

[envA]
abc-group1-1.envA

[envB]
abc-group1-1.envB

[abc-group1]
abc-group1-1.envA
abc-group1-1.envB

```

I can now apply variables for my different environments and host groups:

```auto
group_vars/
abc-group1

envA
envB

```

Now what if I wanted to change the variable for a host group in a specific environment only? My intuition tells me that I could assume following to work:

```auto
group_vars/
envA/
abc-group1
abc-group2

```

So, the abc-group-1 under envA is only loaded when the host is:

- in group envA and
- in group abc-group-1

However, it seems that Ansible does not recursively evaluate group\_vars directories. That means, in the above example. All hosts that are in envA receive variables from ‘abc-group1’ and ‘abc-group2’ regardless of whether they actually are in that inventory group.

The other workaround would be to create further inventory groups, e.g.

```auto

[envA_abc-group1]

....

```

However, that would become unwieldy very quickly.

Has there ever been any considerations in this direction? How would you solve this?

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [April 23, 2019, 1:27pm UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/2 "2019-04-23T13:27:49Z")

</div>

First, you are defining abc-group1 BOTH as a host and as a group, that  
can cause issues with selection not doing what you expect.

To confirm your results, yes, ALL files under group\_vars/\<group\_name\>  
will be assigned to the group, there is no 'sub selection' made, this  
is done via a vars\_plugin and we don't have any plans to change the  
default. You can try developing your own pugin that has different a  
behaviour, but each vars plugin gets a single 'group' at a time, so  
knowledge of other groups is not really available at that point.

---

<div class="post-metadata">

**Author:** ![Uffi\_Schnuffi1](https://avatars.discourse-cdn.com/v4/letter/u/e47774/32.png) [@Uffi\_Schnuffi1](https://forum.ansible.com/u/Uffi_Schnuffi1)\
**Post date:** [April 23, 2019, 4:01pm UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/3 "2019-04-23T16:01:50Z")

</div>

The naming of hosts is done in a way so that one can sort them automatically into the correct inventory groups. There are two distinctions made from a host name:

- environment
- host group

So, for example, if there exists a play that is called “database” and there are the following hosts  
database-group1-1.envA  
database-group1-2.envA  
database-group1-1.envB  
database-group1-2.envB

then the inventory would look like

[database-group1]

database-group1-1.envA  
database-group1-2.envA  
database-group1-1.envB  
database-group1-2.envB

[envA]

database-group1-1.envA  
database-group1-2.envA

[envB]

database-group1-1.envB  
database-group1-2.envB

So, then one can do `ansible-playbook database.yml` --limit ‘database-group1:envA’. Assuming that database.yml creates a clustered database of all the hosts it receives it is vital to pass the `--limit` option.

However, the issue from this model is that group\_vars can be set EITHER environment OR host group specific. I don’t see a way to mix them and say “If host is in group 1 AND in environment A then use these variables” (apart from defining new inventory groups, which becomes ugly with many groups and environments).

Another approach would probably be to split the inventory up into several inventories per environment, and then putting the group\_vars folder next to the environment specific inventory file.  
In my current setup however, the group\_vars are neatly placed next to the playbook which I thought of as a good approach to always know where play specific variables are placed.

Perhaps the “one inventory per environment” approach would be better.

---

<div class="post-metadata">

**Author:** ![Uffi\_Schnuffi1](https://avatars.discourse-cdn.com/v4/letter/u/e47774/32.png) [@Uffi\_Schnuffi1](https://forum.ansible.com/u/Uffi_Schnuffi1)\
**Post date:** [August 10, 2019, 2:04pm UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/4 "2019-08-10T14:04:54Z")

</div>

It actually seems like the vars\_plugin receives a request for all the groups that a specific host is a member of. This seems to be the reason why always the alphabetically last group\_vars from a group name are applied to a host.

---

<div class="post-metadata">

**Author:** ![Uffi\_Schnuffi1](https://avatars.discourse-cdn.com/v4/letter/u/e47774/32.png) [@Uffi\_Schnuffi1](https://forum.ansible.com/u/Uffi_Schnuffi1)\
**Post date:** [August 10, 2019, 2:18pm UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/5 "2019-08-10T14:18:56Z")

</div>

I’ve finally had the time to get around looking at the implementation.

I managed to implement a vars\_plugin which recursively looks for directories with the name of groups and applies the deepest found variable.

For example:

`  
[group1]  
hostA  
hostB  
hostC

[group2]  
hostA

[group3]  
hostB  
hostC

`

`  
r\_group\_vars/  
group1/  
group2.yml  
group3/  
group1.yml  
group1.yml

`

For hostA, first `group1.yml` is loaded and then combined with variables from `group1/group2.yml`.  
For hostB, only `group3/group1.yml` is loaded (since no matching variable file is found under `group1/`.  
For hostC, first `group1.yml` is loaded and then combined with variables from `group3/group1.yml`.

This allows defining special cases when a host is in various groupings. So I am able to specify “If host is in these groups, then use these variables, if it is only in those groups, then use those”. It’s a great way to really apply the right variables for the right hosts.

What do you think? Would this be something which could be contributed to Ansible Project?

Code (will try to optimize it a litte later): [https://pastebin.com/4vj8qrJh](https://pastebin.com/4vj8qrJh)

---

<div class="post-metadata">

**Author:** ![Uffi\_Schnuffi1](https://avatars.discourse-cdn.com/v4/letter/u/e47774/32.png) [@Uffi\_Schnuffi1](https://forum.ansible.com/u/Uffi_Schnuffi1)\
**Post date:** [August 10, 2019, 7:33pm UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/6 "2019-08-10T19:33:11Z")

</div>

A revised version of the plugin with proper documentation: [https://gist.github.com/Timoses/17c39a100350eeedb10d77ab39b9eceb](https://gist.github.com/Timoses/17c39a100350eeedb10d77ab39b9eceb)

---

<div class="post-metadata">

**Author:** ![Uffi\_Schnuffi1](https://avatars.discourse-cdn.com/v4/letter/u/e47774/32.png) [@Uffi\_Schnuffi1](https://forum.ansible.com/u/Uffi_Schnuffi1)\
**Post date:** [August 14, 2019, 7:17pm UTC](https://forum.ansible.com/t/evaluate-group-vars-directories-and-files-recursively/30169/7 "2019-08-14T19:17:16Z")

</div>

PR created here: [https://github.com/ansible/ansible/pull/60593](https://github.com/ansible/ansible/pull/60593)
