Ansible: Multiple files in role's defaults directory

Created on 1 Feb 2016  ·  44Comments  ·  Source: ansible/ansible

ISSUE TYPE

Feature Idea

COMPONENT NAME

roles

ANSIBLE VERSION

N/A

SUMMARY

I have a role that manages a complex piece of software with many options. Right now, the defaults/main.yml is growing larger and larger with more variables.

It would be nice if in the defaults folder I could have various YAML files for each group of variables that are semantically related.

I've tried adding more files to this folder but it doesn't seem their definitions are picked up (as expected). Only main.yml is loaded.

I believe this would be a nice feature.

affects_2.2 affects_2.3 affects_2.4 affects_2.5 feature core

Most helpful comment

Using an include_vars module for default role variables defeats the reason default variables exist in the first place, namely being used to provide "last resort defaults" which can be easily overwritten by other parts of the role/playbook.

The idea of multiple files in defaults/ directory was previously being discussed on IRC, we concluded that parsing the defaults/ directory similarly to inventory/group_vars/ and inventory/host_vars/ directories would be nice to have. The needed code already exists, and hopefully can be easily adapted for role defaults.

All 44 comments

you can have a main.yml in tasks, that includes other files, even in subdirectories of tasks, eg to configure your main two components foo and bar of that large role:

- include: foo/main.yml
- include: bar/main.yml

Using an include_vars module for default role variables defeats the reason default variables exist in the first place, namely being used to provide "last resort defaults" which can be easily overwritten by other parts of the role/playbook.

The idea of multiple files in defaults/ directory was previously being discussed on IRC, we concluded that parsing the defaults/ directory similarly to inventory/group_vars/ and inventory/host_vars/ directories would be nice to have. The needed code already exists, and hopefully can be easily adapted for role defaults.

+1

+1

Would be nice to have it!

+1

Yeah just assumed that defaults/* were found and loaded automagically as mentioned above. It seems the suggested workaround (including additional defaults files in tasks) will override inventory vars due to variable precedence, so it seems we may have to bundle in 1 file to avoid this issue until addressed.

Ansible 2.x variable precedence

    role defaults [1] (loading all role defaults here critical)
    inventory vars [2]
    inventory group_vars
    inventory host_vars
    playbook group_vars
    playbook host_vars
    host facts
    registered vars
    set_facts
    play vars
    play vars_prompt
    play vars_files
    role and include vars (hack coming in here will override everything above)
    block vars (only for tasks in block)
    task vars (only for the task)
    extra vars (always win precedence)

This may be related to #8121

+1

+1

Definitely a must have feature due to variable precedence constraints.
This also allows to define a defaults file per class of variables and keep a clean separation; for instance, in networking, this would allow me to define one defaults file for IPv4, one for IPv6, one for SNMP and so on...
At last, It seems necessary to be able to put these files into different folders under "defaults".

Just hit this one myself, so, definitely +1

This really is a PITA.
If I could suggest a solution, it would be to add an option, similar to include_vars, but in meta/main.yml, to specify load-order.

- dependencies: []
- default_vars:
  - "main.yml"
  - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"

This would allow the option to default to ["main.yml"] and not break existing code, while giving developers the ability to define granular variables based on contexts of their choosing.

Weird. I totally suspected this would work out of the box. One of the few times ansible actually violates the principle of the least surprise a bit...

Definitely +1

For vars/ the same, but seems like #2958 was deciding against this

@cornfeedhobo's example exactly matches my use case. By using include_vars, I'm preventing easy overrides of any individual variables by plays.

Another interface option would be:

  • Add an option to the include_vars module, 'as_default', which processes the included file as if it were in defaults.

For me it really looks weird/counter-intuitive that there's a directory "defaults" with a single file in it.
I mean, have you ever seen a python module with a single __main__.py file in it?

Which is precisely why I intuitively thought the functionality talked about on this ticket was already present. "Of course I can have multiple defaults files, there is a directory for it"

include_role allows you to specify 'alternate' files now http://docs.ansible.com/ansible/include_role_module.html via defaults_from option

Just got into a situation when defaults/main.yml split is desired. Added my 👍 to the issue.

Same here, I need it as well
+1

+1

@bcoca that is a nice addition and adds flexibility, but does not address the issue here, and puts the onus on the playbook writer, when the intention is to empower the role to set sane defaults easily.

Please review my comment above

Yes this is very helpful feature to avoid files with 2k lines.
+1

+1

+1

👍

+1

+1

+1
Same issue here. main.yml too large, split into multiple files. We assumed it would "just work" and load all the vars in the files under defaults/ since it is a dir. nojoy.

+1

+1

+1

👍

+1

+1

👍

You guys can thumbs down every +1 comment, but I highly doubt that you can track the number of subscribers, so adding +1 is still a decent way to show desired support.

Until issue attention is clearly tied to the number of subscribers to an issue, forever expect to see +1 comments.

What you can expect is that the ansible team locks the issue comments instead, so don't be a spammer and dont defend them please.

What you can expect is that the ansible team locks the issue comments instead, so don't be a spammer and dont defend them please.

They could do that but this is a core issue to being able to properly develop roles especially since the introduction of include_role in 2.x alongside the old roles include method. If you design your role to be compatible with include_role, which is preferable since it makes development a hell of lot more modular and flexible than with the old roles method alone, then you are left with having to track either including defaults yourself as tasks in your playbooks, pass the buck on to the end user who shouldnt have to know how to do this for your role to work properly, or track the platform/distro/release as a nested level of your role variables which complicates the hell out of development (although it works as Ive created a role that can support 20 different platform versions here). Have you actually tried writing a role that actually supports more than a few platforms? Its no surprise why most roles on Ansible Galaxy dont, this issue is probably number one on that list IMO.

So if they went to lock this, not respond at all to a year old issue, and signal to the community that they are not interested in discussing critical issues that are preventing people from creating real solutions, then they can definitely expect people to not stick around and continue using the product. If they reply and give a sense of whether they agree its an issue, then maybe people will stop +1'ing it in order to draw attention to the problem.

This is only an issue because they released include_role without thinking through how actually using it in practice would affect defaults. Forcing someone to choose between using roles and include_role in order to make a role work properly or add extra work to enable both to work simultaneous is the core of the issue here.

My 2 cents.

PS If you are downvoting +1's because you dont want the notifications.... hit that unsubscribe button on the top right and you wont get them anymore.

OK, this issue is important for you. I get the point. For me too. That's why I'm subscribed, BTW, and that's why I don't want to unsubscribe, and that's why I downvote spammers, and that's why I upvote the original comment, which is the civilized way to show _lazy_ support for it.

I'd like to add my voice to the request for this ability and detail my use-case. In addition to the simple ability to break-up large main.yml, the ability to do something like this would be great:

- name: Some name
  include_default_vars:
  with_first_found:
    - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"
   - main.yml

What I'm hoping to accomplish with this is [as an example] an openssh role that supports all ssh_config and sshd_config options, and supports multiple OS's and versions [ie. Debian 8/9, EL6/7, etc] but which if called with no vars set by the user, will safely build the config to the OS_majorversion default settings, but which can have ANY available option overridden by the user.

As it stands now, if I put those OS defaults in include_vars, the precedence is too high, and the user can't override those settings in the inventory, or in group_vars/all or in group_vars/groupname or in host_vars etc.

I'm sure there's a way to do this now, but anything I can think of is wildly ungraceful and ugly and would be difficult to maintain. In addition, at least up to this point, nobody I've encountered #ansible has any better ideas on how to do this in a graceful, maintainable way.

Adding this feature would allow for this and may help result in higher quality roles being made available in github/galaxy.

@ralphie02 no, thats not anywhere near a solution to what this thread is about. That is just normal host based variables which is different from the requirement of setting defaults for a multi platform role.

This really is a PITA.
If I could suggest a solution, it would be to add an option, similar to include_vars, but in meta/main.yml, to specify load-order.

- dependencies: []
- default_vars:
  - "main.yml"
  - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml"

This would allow the option to default to ["main.yml"] and not break existing code, while giving developers the ability to define granular variables based on contexts of their choosing.

I really think this is a good solution, there's no real easy way right now to have a different set of defaults by os/version/etc. This implementation also keeps backward compatibility so it's also a nice choice.

In line with @abedwardsw (comment before):
The >2y old proposal from @cornfeedhobo (15 :+1: !) (or a bit more recent from @doubletwist13 ) would really be useful for many roles I know, in particular the complex enough:
https://github.com/hortonworks/ansible-hortonworks

Direct refs to their comments:

See also @geerlingguy 's proposal (from 2016!), and my comment there (that tries to gather related issues): https://github.com/ansible/proposals/pull/21#issuecomment-470048538

Was this page helpful?
0 / 5 - 0 ratings