All about Roles in 1.2 -- a great way to organize best-practices content

Folks have been asking how to reuse pieces of playbooks easily, and I have also been wanting to squash the need to use relative or absolute paths all over the place.

Done! Presenting roles! (in 1.2 devel)

Roles are mostly a way to save boilerplate – using a role automatically puts content in tasks, vars_files, and handlers for you.

I will admit first hand this structure looks a little bit like a puppet module, so I need to give credit where credit is due – I got this idea from that originally, because people wanted an analog of that, but have improved it to make paths not as fiddly. I hope this completely squashes the reuse of parts of playbooks now, and also enables git-submodule style workflows for those that want them.

There are some cool new things too, namely, variables are also loaded (via the vars_files internals), in addition to just tasks, so you can put less in group_vars now if you like.

You can also parameterize roles, so if you had, for example, a role for all the users you wanted to install, you could just include that list of users, and boom, it would work.

See details here and let me know what you think!

https://github.com/ansible/ansible/blob/devel/examples/playbooks/roletest.yml

I want to make it support lists of roles in the roles list, so I could do things like
define my roles in vars_files (or group_vars) for the users I want to include,

and then slurp them all in and make them exist.

Unlike included playbooks in playbooks, roles also minimize fact gathering, so I suspect the only use case for included playbooks now is when you want a site.yml that includes playbooks for all of your different group operations, and things like that.

Hope this is not too confusing and we will introduce this a lot more casually in the docs (probably on the best practices page).

Comments welcome!

A.W.E.S.O.M.E.!!!

I have no opportunity to try now (ansible can be run fom smartphone?? :slight_smile: ) but do you know if it works with with_items statement?
Eg:

  • roles:
  • { role : ‘application’, project: $item }
    with_items: $projects

Hello,

While I havent completely figured out how this will affect my setup here
(I'm the "playbook-in-playbook" type, so I will certainly use roles), it
looks like a neat addition !

However, when I saw the syntax, my first reaction was "eyebrow raising".
Why that mustache-enclosed sort of thing ?

AFAIK, this is the first time we have them beside Jinja and the new
Jinja style variables in playbooks (which is, btw, a really great
addition and opens very interesting possibilities like "variables
referencing vars" working eveywhere).

Wouldn't it be more expressive and ansible-looking like this :

However, when I saw the syntax, my first reaction was "eyebrow raising".
Why that mustache-enclosed sort of thing ?

You can still spell out the hash, this has always been legal in Ansible
YAML.

It doesn’t yet, but it’s on my list.

I want some slightly more idiomatic variation of it though.

with_items (or something similar) should need to be inside the hash or something so the syntax is valid.

TBD! (suggestions welcome!)

Oh ok, sorry, didn't know that.

May be it would be more expressive this way in the docs then :

Hi,

I would just like to check if I get it correctly, that this "roles" are
just a shortcut for those who do not want to explicitly write out
everything and actually do not add any new feature different to what
already exists?

It is therefore a less flexible and explicit, but otherwise exactly the same
thing as doing:

# queues.yml (playbook for group "queues")

kind of liked it short, but will likely make it take the usual
key=value as well, yes!

-- Michael

Great!, this is exactly one feature we would like to have

Hi,

I would just like to check if I get it correctly, that this "roles" are
just a shortcut for those who do not want to explicitly write out
everything

It's more than that.

They are a shortcut, and also make content reusable, and also allow easy
relative imports of files and templates, making them reusable and easy to
share.

and actually do not add any new feature different to what
already exists?

I'd consider upgrades to organization and reduction in boilerplate a new
feature :slight_smile:

It is therefore a less flexible and explicit, but otherwise exactly the
same
thing as doing:

Your paths are not correct, but basically it does expand to a lot of
imports.

The paths a 'foo' role would include are actually:

roles/foo/tasks/main.yml
roles/foo/handlers/main.yml
roles/foo/vars/main.yml

And no, it's not exactly the same, because if any of those files are *not*
present, it's cool with that and would not produce an error.

You can of course import something else from main.yml if you want, and
relative paths work GREAT in this case, which is what we want.

]nd group_vars (what doesn't make much sense to me). This is

actually the purpose of (...)

Nope, it's not. It's completely not the purpose of that. But I won't
tell you what I really think as it's off topic to discuss that application
on this list.

It doesn't make sense to have an inventory script drive roles.

I've always said "the purpose of a play is to map a set of hosts to the
roles they should perform" (at a particular point in time), which is what
this makes much more obvious, and it provides more elegant ways to reuse
and share content, and also gets rid of a ton of games you have to play
with "../" to find files and templates, or even reference things inside
plays.

I think you would really like them if you used them, but if you have
existing content you don't want to reorganize, you don't have to use it :slight_smile:

Hey,

First I want to thank you for this feature as it’s awesome! I’ve been playing with roles over the weekend and reshaping the stuff I’ve been working on to fit better with roles. I did however come across a use case I wanted to discuss with you and see how you envision it working.

I have a role, “application” that contains tasks/main.yml and deploy.yml. The main.yml is the base configuration we want to constantly manage and deploy.yml is (unexpectedly) the deployment steps for updates. With the current roles setup I can only get main.yml included, I believe. Would you envision us putting the deployment steps into main.yml and perhaps tagging them and using tags with roles to select functionality, or expanding it so we can do: role: ‘application:deploy’ or something to select other yaml.

I know to a degree I’m bending the way ansible works, but with roles it seems like other people may have a similar use case to me, routine stuff they want included by the role repeatedly and then the ability to trigger other .yml files to do certain procedures.

I suspect there’s a more ansible way to do this and I’m still just so influenced by Puppet that I can’t see what it is.

Hi,

I am also in the process of reorganizing things to roles and the approach I am currently using (also influenced by Puppet) is:

web.yml

I have a role, "application" that contains tasks/main.yml and deploy.yml.
The main.yml is the base configuration we want to constantly manage and
deploy.yml is (unexpectedly) the deployment steps for updates. With the
current roles setup I can only get main.yml included, I believe. Would you
envision us putting the deployment steps into main.yml and perhaps tagging
them and using tags with roles to select functionality, or expanding it so
we can do: role: 'application:deploy' or something to select other yaml.

This is not true.

In the middle of main.yml all you have to do is:

Yeah, this is a bit overwrought. It sounds like you want to decide what
to run each time, which are what tags do.

You should have one role for your app, and main.yml looks like:

Hmm, but in this case I don't always want to include deploy.yml every
time. I want to only include it in special playbooks that do deploys, or
perhaps when --extra_vars deploy=true is set, or something similar. I
guess I can probably do a with_boolean: with an include? That would
probably solve a lot of my dilemma by having deploy: false as the default
and just overriding it when needed. I could maybe copy the other examples
I've seen have and have configuration: true/false as well. I basically
need to be able to -just- run deployment steps and ignore base
configuration when needed. I've been playing and restructuring and
rewriting things every 10 minutes trying to find the best and most simple
way to handle this.

Ok, so if you don’t want to include deploy except in playbooks that do deploys, don’t put it as a role in that playbook! :slight_smile:

I think the greatest snag most people thing of in Ansible is they try to turn it into some kind of programming language, versus a model of what their systems should be or do.

In this case, roles say “these are the roles this group of hosts should perform”, so if this playbook should not apply these roles at all, ever, they shouldn’t be included!

You can of course break things into smaller roles if this works better for you.

Of course, tags are there, and are a great way to conditionally decide how to run ansible.

Hm, if it would be possible to access current tags as a variable one could do things like:

  • debug: msg=“foo”
    only_if: ‘deploy’ in $tags
    tags: deploy

This would execute if and only if --tags=deploy is given.

Or is it already possible to access hosts, user, tags in playbooks/task lists?

Greetings,
gw

If you do “–tags deploy” it will only run tasks or plays that are tagged with deploy already.

There is no need for the extra conditional.

I mean: It will run only if “–tags deploy” is given, otherwise it will skip this step. Eg. if you do not pass any --tags or pass other --tags, the task will be skipped. It would function as a default skip policy if the right tag is not specified.

Anyway, it was just a thought…

Greetings,
gw

This sounds like you would just want some configuration setting that defined some default tags, and the default in the config file could be all.

I would accept a patch for this, but your conditionals are not needed.