# defaults files per os and release

**URL:** <https://forum.ansible.com/t/defaults-files-per-os-and-release/24086>\
**Category:** Ansible Project\
**Created:** [March 28, 2017, 4:33pm UTC](https://forum.ansible.com/t/defaults-files-per-os-and-release/24086 "2017-03-28T16:33:28Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Mike\_Ray](https://avatars.discourse-cdn.com/v4/letter/m/df788c/32.png) [@Mike\_Ray](https://forum.ansible.com/u/Mike_Ray)\
**Post date:** [March 28, 2017, 4:33pm UTC](https://forum.ansible.com/t/defaults-files-per-os-and-release/24086/1 "2017-03-28T16:33:28Z")

</div>

In the current Ansible setup, you can have 1 file in defaults (i.e. defaults/main.yml) and it is used for all hosts that run that task, no matter what the host.

In our use case, we have found it would be highly advantageous to be able to have os-specific and release-specific defaults files. For instance, some applications change directives between releases – using a directive in a release that doesn’t support it, in the best case just issues a warning (which is not ideal), but in the far more likely case, breaks something.

We cannot use include\_vars as this completely ruins precedence: [http://docs.ansible.com/ansible/playbooks\_variables.html#variable-precedence-where-should-i-put-a-variable](http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)

To illustrate, here is an example/outline of our setup:

file structure:

- inventory/production/host\_vars/mail-server-1
- inventory/production/group\_vars/mail-servers
- roles/servers/mail-server
- roles/postfix
- mail-server.yml

mail-server.yml:  
roles:

- roles/servers/mail-server

roles/servers/mail-server/meta/main.yml:  
dependencies:

- { role: postfix }

summary: What the above is trying to illustrate, is that we have our re-usable building blocks in “roles” and server-specific setups in “roles/servers”, e.g. the “mail-server” role runs through postfix as meta, and then runs through its own tasks. This gives us the flexibility to:

- set host-specific vars in the inventory host\_vars variables (e.g. relayhost=“”)

- set vars common to particular groupings of mail servers in inventory group\_vars variables (e.g. relay\_domains=domain.foo)

- set vars common to mail-servers in general in roles/servers/mail-server/vars (e.g. content-filter=smtp-amavis:[127.0.0.1]:10024)

- set vars for everything that runs the postfix role (e.g. heloname=“{{ ansible\_hostname }}”)

If for example, we were to use include\_vars to try to include variables specific to CentOS, it would be the highest precedence and override host specific settings with generic CentOS stuff.

Our current working solution is to do a large amount of “union-ing” in the defaults file based on variables, i.e. to get the proper postfix configuration options trusty v. xenial:  
postfix\_configuration\_options: “{{ postfix\_common\_configuration\_options | union( (ansible\_distribution\_release==‘xenial’) | ternary(postfix\_xenial\_configuration\_options,) ) | union( (ansible\_distribution\_release==‘trusty’) | ternary(postfix\_trusty\_configuration\_options,) ) }}”

This is not ideal for a number of reasons:

- unless you already know what it does, it can take some time to figure out
- it gets messier and messier the more distributions you support
- it’ll get slower to run the more distributions are supported

But is still useful as you can have a common template for everything then:  
main.cf.j2:

# {{ ansible\_managed }}

{% for item in postfix\_configuration\_options %}

{% if item.option is defined and item.value is defined %}  
{% if item.comment is defined %}  
{{ item.comment }}  
{% endif %}  
{{ item.option }} = {{ item.value }}  
{% endif %}  
{% endfor %}

What we had planned on doing was using the meta structure to include specific roles with particular defaults based on os and release, e.g.:

- mail-server.yml:  
roles:

- meta/postfix

- meta/postfix/meta/main.yml:  
dependencies:

- { role: os/CentOS/postfix, when: ansible\_distribution == ‘CentOS’ }

- { role: releases/trusty/postfix, when: ansible\_distribution\_release == ‘trusty’ }

- { role: releases/xenial/postfix, when: ansible\_distribution\_release == ‘xenial’ }

- { role: postfix }

- release/trusty/postfix/defaults/main.yml:

postfix\_configuration\_options:  
postscreen\_dnsbl\_ttl

- release/trusty  
postfix\_configuration\_options:  
address\_verify\_pending\_request\_limit

And then in the aforementioned main.cf.j2, xenial hosts would define “address\_verify\_pending\_request\_limit” (which is not a thing available in the postfix release for trusty) and trusty hosts would define “postscreen\_dnsbl\_ttl” (which is not a thing available in the postfix release for xenial).

While it works for that case, I’ve found that even when a meta role is skipped, the defaults file is still read, so for situations where you had the same directive, but wanted different values based on os/release, it would not work (i.e. in the following example, “biff” would always be set to “yes”):

- release/trusty/postfix/defaults/main.yml:

postfix\_configuration\_options:  
biff = no

- release/trusty  
postfix\_configuration\_options:  
biff = yes

Does anyone have any ideas for how to have a defaults file per os/release like I want? Does anyone have alternative suggestions on setups such that I would not need/want this anymore?

---

<div class="post-metadata">

**Author:** ![Laurent\_Hoss](https://avatars.discourse-cdn.com/v4/letter/l/7ba0ec/32.png) [@Laurent\_Hoss](https://forum.ansible.com/u/Laurent_Hoss)\
**Post date:** [June 13, 2019, 3:07pm UTC](https://forum.ansible.com/t/defaults-files-per-os-and-release/24086/2 "2019-06-13T15:07:02Z")

</div>

I’ve got the same issue (in various roles) and still cannot foresee a good enough fix exists (or planned)

- An earlier post with the same question:  
[https://groups.google.com/d/msg/ansible-project/jFf1KfoWxBA/KXmcsQZqAQAJ](https://groups.google.com/d/msg/ansible-project/jFf1KfoWxBA/KXmcsQZqAQAJ)

- Please upvote your favorite solution, in the proposals I gathered in following post:  
[https://github.com/ansible/proposals/pull/21#issuecomment-470048538](https://github.com/ansible/proposals/pull/21#issuecomment-470048538)

---

<div class="post-metadata">

**Author:** ![Wawrzek\_Niewodniczan](https://avatars.discourse-cdn.com/v4/letter/w/bbe5ce/32.png) [@Wawrzek\_Niewodniczan](https://forum.ansible.com/u/Wawrzek_Niewodniczan)\
**Post date:** [June 23, 2019, 9:01am UTC](https://forum.ansible.com/t/defaults-files-per-os-and-release/24086/3 "2019-06-23T09:01:21Z")

</div>

Hi,

Have you tried include\_vars:  
[https://docs.ansible.com/ansible/latest/modules/include\_vars\_module.html](https://docs.ansible.com/ansible/latest/modules/include_vars_module.html)

It has such example:

- name: Load a variable file based on the OS type, or a default if not  
found. Using free-form to specify the file.  
&nbsp;&nbsp;include\_vars: "{{ lookup('first\_found', possible\_files) }}"  
&nbsp;&nbsp;vars:  
&nbsp;&nbsp;&nbsp;&nbsp;possible\_files:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- "{{ ansible\_distribution }}.yaml"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- "{{ ansible\_os\_family }}.yaml"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- default.yaml
