Limit playbook run by role?

While testing I often want to limit my run to a specific role. I know limiting can be done by host and by tag but did you ever consider adding a “-r” limit by role option to the ansible-playbook command?

Thanks,
Aaron

It’s unlikely we’d want to add more CLI options for this purpose.

However, there are easy workarounds if you would like this behavior.

Consider your site.yml (a file that configures all of your infrastructure) if it were like this:

  • include: webservers.yml
  • include: dbservers.yml
  • include: other.yml

If you want to run just servers in the “dbservers” role, instead of running site.yml, just run “dbservers.yml” instead.

This trick is using playbooks to include other playbooks (because a playbook is just, in the end, a list of plays in order).

–Michael

Thanks for the reply Michael. I think that would work. However, it’s getting complicated since I’ve implemented your recommendation for handling environments using groups (https://groups.google.com/forum/#!searchin/ansible-project/inventory$20staging/ansible-project/jd3cuR7rqCE/v7jaH-_BAgAJ). I now have a “production” group and a “staging” group. Mixing in roles via includes seems like its overloading the groups concept more than I would like.

By the way, this has gotten me thinking about Ansible’s conceptual model, that is hierarchy of Ansible’s object from the user’s perspective. I understand the relationship between host, group, and role objects but when it comes to “site”, inventory, and the top of the model it gets a bit murky. Do you have something like as UML class diagram that shows this model? The reason I ask is that I’m thinking a new object such as an “environment” at the top (or perhaps under a “site”) might be a simpler way than groups to manage production, staging, etc.

Site

  • 1…n Environment
  • 1…n Groups
  • 1…n Hosts

–Aaron

Another option is to tag your role from the play like this:

site.yml
...
roles:
  - common
  - role: db_server
    tags: db_server_role
  - web_server
    tags: web_server_role

$ ansible-playbook.yml ... site.yml --tags db_server_role

This is useful (in the example above) when you don't want to run the
tasks in the common role and you have other roles that require common
vars.
The only problem with this approach is that I don't believe the tags
will propagate if you have a role with dependencies or other includes.

-John

Also, I don't believe tags are like sets of tasks that might contain
other sets of tasks. Instead, tags are independent sets without any
intersections. In your example, if the db_server role contained a
tasks/main.yml that looked like this:

  - include: db_server.yml
    tags=db_server

Then, specifying the tag db_server_role would do nothing. Instead,
you would have to specify the tags db_server_role,db_server. Of course,
you could just specify the tag db_server in the first place. The point
is to be careful about tags defined within a role because they must all
be specified explicitly to run all the role.

* John Jarvis <john@jarv.org> [2014-04-23 11:16 -0400]:

Yeah one of the reasons why we avoid trying to carve up plays with
tags. To date our approach has been that "plays are cheap" and create
more plays as needed for different use-cases.
-John

In order to run roles separately I use this work around too. Since roles are my primary configuration item (CI) I wanted to avoid this extra step. I don’t understand why tags have a command line option but roles don’t.

In order to run roles separately I use this work around too. Since roles
are my primary configuration item (CI) I wanted to avoid this extra step. I
don't understand why tags have a command line option but roles don't.

A role is not a grouping mechanism. If there were a CLI option, how would
you determine to which hosts the role is applied? You could have ansible
determine all of the plays where the role is used, but that sounds like a
hairy dict-inversion challenge that I imagine would over complicate the
code.

I would, instead, think about adding an "implicit_grouping: True" option to
ansible.cfg whereby a role named "webserver" is mapped to a group called
"webserver" with an implicit play of:

hosts: webserver
roles:
  - webserver

There are, however, implications here such as "how do I set other options
on that play?" You start yak shaving fairly quickly and end up with feature
creep to make it marginally useful for the majority of cases. This involves
more configuration options and another syntax for defining the plays and we
are right back where we started.

N.B. - We use the play-per-role model and the "dirty" root of our playbooks
directory bugs me to no end. I would very much like to see the ability to
stash them in a "plays" subdirectory and be able to include them in our
site.yml without having relative-pathing lookup issues (i.e. they should
execute in the context in which they are included, not the context in which
the file sits. This also causes issues when you include, say, a play to
spin up a particular role in ec2 and want to put that play inside the role,
but execute it with the ability to act as if it were run in the playbooks
root).

Peter

Peter, it sounds like you have a seperate issue with lookup paths, this should be a seperate thread.

All – roles are just abstractions around tasks. Tag your roles if you like.

roles:

  • { role: foo, tags: foo }

And you can --tags foo

To just run those roles.

I don’t view roles as “just abstractions around tasks.” In fact just the opposite: tasks are the commands needed to implement a role. This is because I use roles as my primary CI. The baseline on a given host is made up of applications (a CI) and roles (a CI) and some hardware stuff. All the CIs are version per good CM practice.

If you are aren’t using roles as your main CI then what are you using as the CI’s in your baseline? The entire playbook? An individual task?

How Ansible maps to and supports a formal CM process is an important question, at least to me. As my CM tool of choice I hope to see Ansible evolve in a way that facilitates CM best practices.

Thanks,
Aaron

I don't view roles as "just abstractions around tasks." In fact just the
opposite: tasks are the commands needed to implement a role.

A role is a self-contained set of tasks and related files and templates
that make a host do something. For example, act as a DNS server. Our DNS
server could also be our DHCP server and maybe also an LDAP slave.

We use cobbler for our host management and use cobbler.py as our inventory
file for ansible runs. Each role is represented by a "management class" in
cobbler which then results in the host being a member of a group. For each
role in our playbooks we have a play that executes that role on hosts in
that group. Many of our hosts have multiple "management classes" attached
to them and thusly multiple roles get applied.

This is because I use roles as my primary CI. The baseline on a given host

is made up of applications (a CI) and roles (a CI) and some hardware stuff.
All the CIs are version per good CM practice.

I'm not following. Are you not deploying applications via roles? What does
hardware have to do with this?

If you are aren't using roles as your main CI then what are you using as
the CI's in your baseline? The entire playbook? An individual task?

What do you mean by "baseline?" In our environment every host has a set of
roles. We have a "common" role that is applied to every host and then we
apply other roles as well to make a host, say, a webserver (maybe "mysql,"
"webserver," and the role name for the application it will run).

How Ansible maps to and supports a formal CM process is an important

question, at least to me. As my CM tool of choice I hope to see Ansible
evolve in a way that facilitates CM best practices.

Where do you see ansible standing in your way? What are you trying to do?
Also, "best practices" are not always the same between environments.

Peter,

Of course roles can be understood and used differently. I was trying to explain how I view and use them. This was to show why I thought (and still think) that a role based limit was needed as a command line option. The view of roles as just a bunch of tasks doesn’t sound right to me from a user perspective (no matter if they are implemented that way) so I was explaining my reasoning.

As for terminology I use “baseline” and “configuration item” (CI) according to normal usage in the CM context (see IEEE 828-2012 and ISO 10007:2003). Unfortunately “CI” is frequently used to mean continuous integration (like with Jenkins) so that’s confusing. CM requires a baseline and a set of CIs. My question was, if people are not using roles as a CI then what are they using? In other words how are you tracking the versions of your baseline and the versions of the changes you make using Ansible?

As for best practices, I would say instead that best practices are the same only how they are applied differs.

Regards,
Aaron

CM ‘of course’ being configuration management…

Actually, I’m using a combination of a kickstart file and an Ansible role to establish my baseline… (I suppose that you could argue that the kickstart is my baseline, but the “common” Ansible role is applied to all servers so it is really part of the baseline.

We haven’t got to the point where all changes are made using Ansible so this is more academic on my part… We have multiple Roles so far that apply to different servers for different purposes. For example, the common role sets up a baseline. I have a “group” role that does some fact gathering and then sets up various host groups automatically (OS and version, hardware platform, and so on) (that’s actually the first one run)… We have a role to setup a monitoring agent, we have roles to set up some hardware dependent software… I would consider the physical machine (or VM or partition or…) to be the CI. A combination of roles is applied to a given CI (and Ansible can tell us which roles) will be applied.

As for versioning, at this stage I always want the latest version of each role applied, so that’s not an issue for me… I can always run Ansible in check mode to see if it would change anything. (I wish check mode was more complete and accurate, but it’s good enough).

Adam

I’ve been doing something similiar but now I want to bring my Ansible roles under CM. I haven’t fully worked out yet how to structure. I have in mind something like the layout below. The baseline for Host A might look like:

Host A

  • Kickstart 1.2.3
  • DNS BIND 9.1.2
  • DNS BIND Role 1.2.3
  • App x 3.4.5
  • App x Role 1.0.4
  • Common Role 2.3.4

Every CI (kickstart file, applications, Ansible roles, etc.) has a version ID. My CMDB will track these IDs. Prod and staging (and other environments) will have a different baseline. If Common Role 2.3.5 makes it through testing and my change control process, then it gets pushed to production. (BTW, This is why I think Ansible’s push mode is far better then Chef’s pull mode for real CM.) If Common 2.3.5 causes a problem despite having been tested, and that happens, then I can rollback Common to the last known working rev–2.3.4.

This is the idea at least. I’m still working through the toolchain to support it and how to adapt Ansible to this model.