Proposal: include_defaults

Hello,

after yesterday’s thread I’ve goggled a bit more around ansible and variables and I’ve figured out the following facts (of which many of you are probably aware but I’m new of the environment):

  • the precedence of the variables is set in stone: a lot of people rely on that and tweaking it is out of discussion;
  • several people using ansible are baffled by the inability to override from the inventory the variables set by a role (I’ve googled several articles discussing about the topic).

My proposal is to add an include_defaults with the same behaviour of include_vars but whose values can be overridden using the usual mechanism.

The rationale has been explained yesterday: it is not uncommon to have dependencies across roles. If role B depends on role A it cannot use values for variables provided by A unless these values are specified globally, e.g. in group_vars/all. This breaks roles encapsulation and forces the maintenance of larger-than-necessary group_vars files. Using include_defaults only B is exposed to the variables whose default is provided by A and group_vars files only need to override the more generic values provided by the role as fallback.

I think my proposal is simple and doesn’t change radically the way ansible works (e.g. introducing a new level of vars precedence) and totally backward-compatible as it uses a new command. Reading the commentary about the topic I think it is a model many people expect and some users have developed their own hacks to work around the limitation (e.g. using no-tasks dependencies).

The feature is implemented in my branch https://github.com/dvarrazzo/ansible/tree/include_defaults and consists of just a new plugin, no change to the tasks runner. It may be missing something or could be designed in a different way (e.g. it could be a “include_vars target=default” instead of a new command, or it could take “role=name” instead of a full path to automatically include role/defaults/main.yml): feedback is welcome.

I’m happy to know what other users and above all the developers think about the feature. Again, thank you very much for the invaluable tool you have provided.

– Daniele

“If role B depends on role A it cannot use values for variables provided by A unless these values are specified globally, e.g. in group_vars/all.”

Role variables in the “vars/” directory of a role are actually pulled into all roles.

“- several people using ansible are baffled by the inability to override from the inventory the variables set by a role”

We’ve explained this many times when folks have precedence questions. Many things have greater precedence than inventory variables, including role parameters and variables in the roles. Defaults are actually lower precedence.

Again, I’d prefer to work back form the use case of what you are trying to model to see if things can’t be solved by existing systems, continuing to add more syntax increases the cognitive load of the program, which is something I like to resist :slight_smile:

Michael DeHaan <michael@ansible.com> napisał:

"If role B depends on role A it cannot use values for variables
provided by
A unless these values are specified globally, e.g. in group_vars/all."

Role variables in the "vars/" directory of a role are actually pulled
into
all roles.

I think the proposed include_defaults task would be useful because of this - it would add an easy way for providing OS-specific defaults without cobbling other roles namespace.

I haven’t seen the need for this pattern arise much, and my comments on this still hold.

This can still be handled by this pattern:

assume the following defines a variable role_var_default

  • include_vars: “{{ ansible_os_family }}.yml”

  • set_fact:
    role_var: “{{ role_var | default(role_var_default) }}”

If you need that functionality.

“without cobbling other roles namespace.”

Roles are already namespace protected so accidental namespace collisions are not possible.

I’ve found yesterday that ansible gives the flexibility to add plugins outside its codebase. This is great as I (or anybody else) can keep on experimenting with import_defaults without bothering the main codebase.

I’ve uploaded include_defaults to a gist: https://gist.github.com/dvarrazzo/7418a89b7278ff69267c. Info about how to use it are there too. It still takes a file name as input but I think it would be better if it allowed ‘role=NAME’ too as option to get the role’s default file; I haven’t dug enough into ansible internals yet to find how to deal with the roles path resolution (of course if someone knows better patches are welcome).

If anybody has found the same limitations I found and wants to give it a go it would be nice to know his comments. This may end up showing the emergence of a use case, in which case ansible developers will make their own choices, or not showing anything at all :slight_smile: In the meantime it’s nice to see the solution can live in just a few people’s playbook directories and doesn’t need hacking into ansible code.

Thank you everybody, have a nice weekend.

– Daniele

Oh I would like to see load_defaults in the core of Ansible. I created some roles, which distinguishes between client and server installation. Depending on the installation type they should load different defaults (e.g. refresh rates, max. log size, …). I tried ‘load_vars’, but it has a higher precedence and my playbook variables wouldn’t override them as the should do with ‘load_defaults’.

I hope you plugin will do the trick.

Thanx in advance
Thomas