Introducing role dependencies

A new feature we will be introducing in 1.3 (and available now on the devel branch on github) are role dependencies. This allows roles to include other roles, and should allow for greater re-use of stock roles.

To create dependencies, just add a meta/ directory to your role with a main.yml file. As an example, if we had a “drupal” role, then the meta/main.yml file might contain something like this:

Hi,

Great timing, I was just looking for a way to do this!

Excellent James!

While not role dependency specific – One very nice feature hiding under the hood in this patchset, that many people will like here is also a improvement in role variable scoping. Previously if you had something in roles/x/vars/main.yml and something in roles/y/vars/main.yml, the last one loaded wins and could get applied to all roles, so you had to be careful with reusing variable names. This could get confusing if both defined a variable named “port”.

Now, that’s still true for loose tasks as these vars are available later on down in the play, even if coming from other roles – but within a role, the variables in roles/y/vars/main.yml are guaranteed to be applied to that specific role, just as if they were parameters explicitly passed to the role. No surprises. Moral of the story: use roles, roles are your friends!

As for role deps, a small caveat, which you may notice, is that this isn’t really forming a dependency tree (this is on purpose!), it’s instantiating those roles and applying them to form a nice flat list. For instance, you can name a role something like “flush_memcache” and include it multiple times, and it will run multiple times. There are use cases where that is useful of course.

For things like “apply a common config”, don’t do that with role dependencies, right now:

Just do:

roles:

  • common
  • myapp

And then let myapp pull in what it requires.

We probably need to add something in the role metadata that flags a role should only be included once (or once for this set of explicit role parameters) for these situations. Like maybe “include_only_once: True”. However, definitely wanted to get everybody a chance to use that before we started making it too involved and that can be done later.

Very nice to see this, I know a lot of people have been asking for it.

In the latest -master, variable definitions in a dependent role do not take precedence when the role is executed/activated as a dependency. I’ve posted a full example to a github repository here:
https://github.com/briceburg/ansible-variable-scoping

Overview: The test_app role depends on the test_service role. A variable named shared_var exists between the two roles. When executing the playbook, the value of shared_var defined in test_app takes precedence regardless of the active role.

The two role var files are:
https://github.com/briceburg/ansible-variable-scoping/blob/master/services/test_service/vars/main.yml
https://github.com/briceburg/ansible-variable-scoping/blob/master/applications/test_app/vars/main.yml

You can run the test by checking out and executing ./test.sh

Github issue posted here:

https://github.com/ansible/ansible/issues/4528

You didn’t define “shared_var” in a role though.

Roles get evaluated first and while they are guaranteed to be used, values loose in a playbook are not the same.

Michael,

I believe I defined “shared_var” in both roles (using /vars/main.yml). In fact, everything in my example is triggered via ansible’s role include behavior ; and I don’t believe there’s a “loose” playbook. The base playbook ( https://github.com/briceburg/ansible-variable-scoping/blob/master/application.yml ) simply includes the application role and all tasks & variable definitions are subsequently executed as expected (via /tasks/main.yml).

To clarify I’ve updated the github repository’s README as well as the issue. We expected that the active role variable definitions take precedence… which is not happening in our case [where the active role is executed as a dependency ].

Thanks,

~ Brice

Sorry, this example is overly dense for a minimal reproduction example so it’s hard to tell what’s what. And it’s clear we don’t quite communicate on the same wavelengths :slight_smile:

Basically, distill something until it only shows the thing, and then it’s much easier to understand.

I should expect you can replicate this in about 15 lines of playbook?

I’ve also replied to the ticket.

You’re doing some confusing things with loading “vars_files” here, I don’t think roles are to blame for variable clobbering here.


  vars_files:
    - ["applications/{{ namespace }}/vars/{{ branch }}.yml", "hosts/host_vars/_.yml"]

Also explicitly loading host_vars looks like a weird thing too.