Group/host vars files proposal.

So this is silly, but I'd like it and be willing to submit the pull
request --- won't bother if it's not wanted, though.

I was wondering if it would be reasonable to allow files in group_vars/
and host_vars/ to be have a '.yml' or '*.yaml' extension.

My reasoning --- and here comes the silly --- is that folks' editors can
then format the files appropriately without resorting to modelines.

It's a simple patch and shouldn't (I think) have any unforeseen
consequences (the logic seems to be limited to
'ansible.inventory.vars_plugins.VarsModule.run').

Let me know if this seems copacetic.

+1

I am fine with code that would ignore the extensions when matching altogether.

Excerpts from Michael DeHaan's message of 2013-04-12 10:51:09 -0400:

I am fine with code that would ignore the extensions when matching
altogether.

Any preference on how to handle multiple conflicting files, like
'group_vars/foo' and 'group_vars/foo.yaml' both existing? Raising an
error sound reasonable?

Also, re: another thread, I can roll the patch to load files in
subdirectories into this. Also, how should I handle the conflict where
both 'group_vars/foo' and 'group_vars/bar/foo' exist?

They are dictionary, so it could just override all of them in order, like so?

dictionary_result.update(loaded_dictionary)

I suspect not too many people will be organizing this way, so it might not be super important to make a really complex solution for it.

​I'm also fine with that, as long as it's predictable, and it's documented
in what order it's parsed en what files gets precedence.

   Serge​

Excerpts from Michael DeHaan's message of 2013-04-12 11:10:30 -0400:

They are dictionary, so it could just override all of them in order, like
so?

dictionary_result.update(loaded_dictionary)

I suspect not too many people will be organizing this way, so it might not
be super important to make a really complex solution for it.

The override sounds good, but I wonder if there's any reasonable way to
choose the precedence?

It seems like for nested subdirectories, we could simply override the
top-level vars file ('group_vars/foo') by the deeper vars files, in
order of depth (the deepest-nested file wins).

For extensions, however, I can't imagine any reasonable precedence
order that wouldn't be a surprise.

I'd also worry, in the case of some inheritance schema, about folks
trying to leverage it to implement some strange behavior instead of
using it as a convenience.

I do not want any sort of defined precedence.

I am generally just saying we make this ‘work’ and not really document it as being a feature or anything like that, to avoid the questions altogether :slight_smile:

The override sounds good, but I wonder if there's any reasonable way to
choose the precedence?

It seems like for nested subdirectories, we could simply override the
top-level vars file ('group_vars/foo') by the deeper vars files, in
order of depth (the deepest-nested file wins).

It's not the aim of this setup to have different same group vars files, so
I agree with Michael we shouldn't bother too much about it.​​
Fact remains, you have to choose something :slight_smile:

I'd consider the full path to the group file, and when there are more than
1, just sort them alfabetically, and let the first precede.

For extensions, however, I can't imagine any reasonable precedence

order that wouldn't be a surprise.

Well, here you could enforce to have only one of the two options: with the
yml extension, and without.
If both exist, exit 1. At least when it comes to 1 particular group file in
whatever directory.
​​

I'd also worry, in the case of some inheritance schema, about folks
trying to leverage it to implement some strange behavior instead of
using it as a convenience.

​Enforcing to avoid that, you could limit the plugin to only parse the
first (full-path-alfabetically) found​ group file, for a particular group.

That way, there allways is only 1 group file that gets parsed.

   Serge

Not 100% on the logic, but here's a pull request:
    <https://github.com/ansible/ansible/pull/2664&gt;

Any suggestions are welcome.

I do not want any sort of defined precedence.

Agreed. Just have a simple logic in the code. As I said, I'd go for the
first full-path alphabetically found file.
​​

I am generally just saying we make this 'work' and not really document it
as being a feature or anything like that, to avoid the questions altogether
:slight_smile:

I don't believe in this, in this case, unless 'just works' is well
defined​​. Questions are still going to assault you :slight_smile:
I propose "only the first full-path alphabetically found file, out of [
group, group.yml ]. Only one can exist, don't care which.

    Serge

When you document some confusing fringe use case, that’s when questions assault you. In this case, what you are asking to do is not something most people are going to want to do, and if I think you have to explain “what is the variable precedence merging order when organizing variables in subdirectories”, versus it just doing the most perfectly logical thing, that’s when you’ve failed on the mission of making a more simple system.

It needs to merge all variables, because that’s what most people would expect. First found leaves you in hell when you can’t tell which one it loaded.

​OK, seems you are right. One still needs to now which simple precedence is
used in the case of different same group vars files​..

    Serge

This may be bikeshedding, but I can imagine two possible scenarios:

  1. The user deliberately created two files with the same name but different extension, for some reason.

  2. The user accidentally created a second file with the same name and different extension. For example, he had foo open in his text editor editor, and then renamed it to foo.yaml, made some changes, and then his editor told him that “foo” has unsaved changes instead of mentioning that it had been deleted out from under him (I’m looking at you, Sublime Text), and then he saved “foo”, and now there’s foo and foo.yaml, and they’re slightly different.

I’d wager that scenario 2 is about 100 times more likely to occur than scenario 1, in which case it’s going to be very difficult for the user to figure out what’s wrong when there’s a variable set unexpectedly.

So I would recommend disallowing having two files with the same name but different extensions, and have ansible fail with an error saying “files foo and foo.yaml have the same name and different extensions, this is not allowed”.

Lorin

​Yes, that was one of my first ideas.​ It would help avoiding name
collision.
But I'd limit the 'extension' to 'yml', which is what this was all about in
the first place.

Other wise you could have bad clashes like:

.me is a top level domain.
.me.uk is also a top level domain....

​ Serge​

Do we really want to add this complexity ? I'd say use group_vars/ and host_vars/ for the simple cases and if you need something more complex, look at writing an inventory script that does exactly what you need.

Wasn't that our credo a few months ago ? :wink:

Actually yes, I think Dag’s right.

When I originally built inventory scripts, that was the purpose… if you need a better way to organize, make a better/different variation, and we can let people know about it.

–Michael

​I'd like to come back to this:​
​​

Actually yes, I think Dag's right.

Do we really want to add this complexity ? I'd say use group_vars/ and

host_vars/ for the simple cases and if you need something more complex,
look at writing an inventory script that does exactly what you need.

​I totally agree that we shouldn't have the complexity of elaborating on
the logic of precedence in various vars_files.​
Unortunately Morgan and me got to that "bikeshedding" point because we had
too choose a logic.

All this complexity disappears if we don't allow multiple files for the
same host or group.

I updated Morgan's patch to implement this, and I think this is clean and
simple. It also considers file with and without the yml or yaml extension.

serge@cyberlab:~/tmp$ cat inventory
[group]
localhost

[project1]
localghost ansible_ssh_host=localhost

[staging[
localpc ansible_ssh_host=localhost
localdev ansible_ssh_host=localhost

serge@cyberlab:~/tmp$ tree
.
├── group_vars
│ ├── group
│ ├── group.yml
│ ├── production
│ │ └── project1
│ └── project1
├── host_vars
│ ├── localpc.yaml
│ └── project1
│ └── localpc
│ └── localdev
├── inventory
└── vars_plugins -> ../src/ansible/lib/ansible/inventory/vars_plugins/

serge@cyberlab:~/tmp$ ../src/ansible/bin/ansible -i inventory all -m debug
-o

localpc | FAILED => Found more than one file for host 'localpc':
['host_vars/localpc.yaml', 'host_vars/project1/localpc']
localghost | FAILED => Found more than one file for group 'project1':
['group_vars/production/project1', 'group_vars/project1']
localhost | FAILED => Found more than one file for group 'group':
['group_vars/group', 'group_vars/group.yml']
localdev | success >> {"msg": "Hello world!"}

​Anyway, I issued a PR for review:
https://github.com/ansible/ansible/pull/2675​

    Serge

The subdir logic I think is a slippery slope, reminescent of when we also supported inventory in a YAML format.

This should, I think, be implemented as an external inventory script.

In general, things that are hard to explain why you need them, or make it hard to find where the file that controls X really is (and can you be sure that’s really the one?) seem like bad ideas for the general application to me.

It’s fine for specific use cases, though, which is why the system is pluggable.