Idea: playing roles directly, implicit playbooks

Dear list,

have you ever wanted to "play" a role directly and found yourself
in the position that you needed to whip up a playbook with mostly
derived contents just in order to do that?

For instance, I have a 'motd' role that contains everything I need
to construct /etc/motd files. I also have an inventory group
'motd_hosts'…

I would really love to be able to just say

  ansible-playbook ~/ansible/roles/motd/

and be done with it.

How would this work?

If ansible-playbook gets passed a directory instead of a YAML-file,
then it could assume that the directory was a role and construct
a sensible playbook for it on the fly. It would have some sanity
checks built in, obviously, to ensure that it is being fed a role
directory.

For instance, consider the following role:

  roles/motd
  ├── tasks
  │ └── main.yml
  ├── templates
  │ └── motd.j2
  └── vars
      └── main.yml

You would use this role with a playbook like this:

The goal of ansible plays have always been, even before plays, that plays map sets of hosts to the behaviors (roles, if you will) that they perform. It’s not just one role, but many. A hosts can fulfill many different roles. One might be common, one might be “datacenter1”, one might be “security”, and one might be “webserver”.

So, I don’t really think this needs to be a thing.

also sprach Michael DeHaan <michael@ansibleworks.com> [2013.06.20.1809 +0200]:

The goal of ansible plays have always been, even before plays, that plays
map sets of hosts to the behaviors (roles, if you will) that they perform.

What do you suggest to do in a case where a CMDB already contains
all the information about which "roles" to apply?

In the combined use cases that I have to manage, there will be
several hundred roles, all with associated groups in the inventory.

Is it really necessary to create a playbook for every role that just
maps "role_hosts" to "role"? Do you see a different way? Sure, this
can be done in a very simple for-loop, but it's still redundant
information written to disk and a source of error I'd like to avoid.

What do others think?

Well, sort of.

You wouldn’t define playbooks for every role, you define playbooks for every group of host – important conceptual difference.

In fact, you may have many DIFFERENT playbooks that target the same groups of hosts to do different things.

I think the fundamental misunderstanding here is folks are coming in from tools like Puppet and not looking at the general process orchestration or app deployment use cases.

You don’t just have to have the one site.yml that is like a site.pp (in which case I can see the idea of being able to assign roles from inventory), but rather as many as you want.

It might be technically possible to define a set of roles to define in group_vars – you would think – but it’s not.

The reason being, suppose you included a role for every machine in ‘webservers’ and wanted to auto build the play.

However, some webservers are in Boston and some are in DC. The Boston webservers need an additional role named ‘Boston’, and some in ‘DC’ need the DC role.

Thus the play is THE place where you define that.

I view the idea that you want to externalize that outside the playbook as an unneccessary abstraction, because the play IS the place where you define it.

If you have different requirements, I have no problems with people code-generating the playbook (see what Jesse Keating is doing with ansibox), but I don’t see this needs to be a 1st class concept in Ansible.

also sprach Michael DeHaan <michael@ansibleworks.com> [2013.06.20.2239 +0200]:

I think the fundamental misunderstanding here is folks are coming
in from tools like Puppet and not looking at the general process
orchestration or app deployment use cases.

Well, not all users of Ansible need process orchestration or app
deployment. Our nodes are all independent of each other.

You don't just have to have the one site.yml that is like
a site.pp (in which case I can see the idea of being able to
assign roles from inventory), but rather as many as you want.

Yes, this is indeed very nice, to be able to play just one book at
a time.

However, if you want to manage systems, you will want to have
Ansible run regularly, to ensure that local changes that are not
in-line with your infrastructure definition (inventory, whatever),
get reverted.

And at this point you need site.yml or master.yml.

I also understand your point about playbooks targetting groups of
hosts. But what about the case when a group already corresponds to
a role?

The reason being, suppose you included a role for every machine in
'webservers' and wanted to auto build the play.

However, some webservers are in Boston and some are in DC. The
Boston webservers need an additional role named 'Boston', and some
in 'DC' need the DC role.

Yes, of course. Those additional roles get applied too. After the
'webserver' role was applied to all 'webserver_hosts', the 'Boston'
role gets applied to all nodes in the group 'hosted@boston_hosts'
(our naming convention).

You can either manage this with group_vars, as you suggest, or with
groups, which is what we do. I.e. there is a group for every role
already present.

Thus the play is THE place where you define that.

I view the idea that you want to externalize that outside the
playbook as an unneccessary abstraction, because the play IS the
place where you define it.

… unless you already have the information elsewhere.

Am I reading you right that you won't consider this use case, that
you suggest I auto-generate playbooks on my end to cater for my
needs, but that you won't consider whatever I come up with for core
inclusion?

Cheers,

​Martin,

Instead of autogenerating playbooks, you could consider​ tweaking
ansible-playbook into "ansible-role",
which could be a tool holding the middle between ansible and
ansible-playbook: running a bunch of tasks on hosts, instead of just one
module.

I could see a use for such a tool. Whether that is stuff for core, doesn't
really matter, as it's just a separate script.

Serge

also sprach Serge van Ginderachter <serge@vanginderachter.be> [2013.06.21.1045 +0200]:

Instead of autogenerating playbooks, you could consider tweaking
ansible-playbook into "ansible-role",

Yeah, I considered this and it's still on my list of possible
avenues.

I could see a use for such a tool. Whether that is stuff for core,
doesn't really matter, as it's just a separate script.

True, but I am always trying to find solutions that keep my "diff"
from upstream as small as possible, because when Ansible 2.0 comes
out, I don't want to find myself relying on an API that is no longer
supported. Or somesuch. You get the idea.

Furthermore, I think that while the philosophy of Ansible is worth
being looked at and considered from a step back, there is no reason
to force users to do it that way only, really. Isn't Free software
about choice? Not only between tools, but also in tool
functionality?

Now, I am not talking about modifying core in any way that affects
existing behaviour, or introduces complexity. I am talking about
introducing a new way to approach things, which some will find
useful and others will not. That's the choice I am talking about.

Doesn't Ansible as a whole gain from this?

@martin,

In your case it seems you don’t need roles and can just use playbooks that overlap with your current existing role setup.

Or looking from a different perspective, parameterized roles are pretty similar to modules for the end user, so they could both be executable from ansible, eg. ansible webservers -r uwsgi -a "workers=10" (-r for roles, -m for modules).

Greetings,
gw

also sprach Brian Coca <briancoca@gmail.com> [2013.06.21.1439 +0200]:

In your case it seems you don't need roles and can just use
playbooks that overlap with your current existing role setup.

That is true, except I liked having templates in ./templates/ next
to the playbook. But I suppose that is not necessary, actually.

Thanks for the whack with the cluebat.

also sprach GW <gw.2013@tnode.com> [2013.06.21.1451 +0200]:

Or looking from a different perspective, parameterized roles are
pretty similar to modules for the end user, so they could both be
executable from `ansible`, eg. `ansible webservers -r uwsgi -a
"workers=10"` (-r for roles, -m for modules).

I can't find it anymore, but Michael said that roles are like Puppet
defines, i.e. wrappers around tasks and related files, parametrised
and reusable in that sense.

Do you have an example of what you consider to be an excellent
application of the roles concept?

While not parameterized, there are many roles examples in https://github.com/ansible/ansible-examples/tree/master/lamp_simple (for instance, the lamp_simple example)

also sprach Michael DeHaan <michael@ansibleworks.com> [2013.06.22.1936 +0200]:

While not parameterized, there are many roles examples in
https://github.com/ansible/ansible-examples/tree/master/lamp_simple (for
instance, the lamp_simple example)

I note that that playbook does not much more than map group names to
role names:

  all → common
  dbservers → db
  webservers → web

When you look at that playbook, don't you have an itch to remove
this redundancy, this extra layer, which doesn't add anything?

I know playbooks can add a lot. I am not proposing to change that.
I am proposing to find a way to eliminate them only in use-cases
when the group names map directly to role names…

It adds a heck of a lot, as you may also want to apply additional roles in that same mapping, may later add load balancing (pre_tasks, post_tasks) and so on.

You can also do free form tasks, group_by operations to create dynamic groups, etc.

If someone is using ansible for a small subset of what it can do, I think, is not reason to create a method of operation that allows it to do only that subset.

Again, minimal system – less tools – less keywords.

This is not duplication, this is the exact place where you define the mapping for this particular playbook run.

Another playbook may do something totally different with those groups of hosts.

also sprach Michael DeHaan <michael@ansibleworks.com> [2013.06.22.2013 +0200]:

It adds a heck of a lot, as you may also want to apply additional roles in
that same mapping, may later add load balancing (pre_tasks, post_tasks) and
so on. You can also do free form tasks, group_by operations to
create dynamic groups, etc.

My initial suggestion lets you do all of that, because when Ansible
would be told to "play a role", then it would augment its implicit
assumptions (which hosts to map a role to) from a playbook.

My proposal adds to Ansible: if all you need is to apply role 'foo'
to ''foo_hosts' and role 'bar' to 'bar_hosts', like in the example
you showed me when I asked about "typical role usage", then I am
offering a shortcut. If that shortcut doesn't do everything you
want, then you don't have to use it.