If you’re an ansible user, you know that you write a playbook to describe the things that you want done to a machine.  A playbook is a list of tasks that sets a machine to a particular configuration.  For complicated environments it’s common, and even preferred, that you break the work of a playbook into smaller blocks of execution called roles. A role includes the tasks required to implement one feature of a configuration.  Roles are analogous to subroutines in a piece of software: by encapsulating the steps needed for each feature, roles becomes a reusable elements that can be invoked from multiple playbooks.

For example, you might have a playbook that sets up a system as a web server. The playbook might create some user accounts, customize the resolver configuration, enable SNMP for monitoring, and install apache.  Each of those pieces is taken care of by a role.

It all works great when you need deploy consistent configurations for new machine in a production environment, but what if you’re testing and only want to setup apache without any of the other features? It would be nice if you could say “run this role on that machine”, but there’s no convenient mechanism for do this.

To get around this limitation, I have a playbook called “runrole.yml” that acts like a template and which uses variables provided on the command line.  Following up on the example above, if I want to run the ‘apache’ role on a system called ‘testbox’, I can do this:

ansible-playbook ./runrole.yml -e "role=apache onhosts=testbox"

The “-e” switch to the ansible-playbook command lets you provide ‘extra arguments’ to the playbook. The playbook looks like this:

# A simple playbook that makes it easy to invoke a single role.
- hosts: "{{onhosts}}"
gather_facts: "{{gather |default(True)}}"
become: yes
- "{{role}}"

The “role” variable should be set to the name of a role that can be found in the roles search path. You can find details about how to set the roles search path on the ansible web site. See: role-search-path docs.

The “onhosts” variable can be set to the name of a single host, a group name, or a comma-separated list of hosts and/or group. The only requirement is that any hosts or groups mentioned need to be in your ansible inventory.

Like any playbook, the default behavior is gather facts from the hosts you’re running the role on. If you’re testing a role that doesn’t need any facts from the target host(s), you can speed up execution by including “gather=False” in the ‘-e’ clause to prevent the playbook from running the setup module. It would look like this:

ansible-playbook ./runrole.yml -e "role=apache gather=False onhosts=testbox"

As you probably expect, all of the other options that normally work for ansible-playbook are still valid, so you can use “–ask-pass”, “–become” or any other settings that you need.  An important one that I sometimes forget is “–vault-pasword-file” whenever a role makes use of a vault.

For administrators doing DevOps work with ansible, it can be handy to be able to execute a role from the command line to apply a piece of a configuration to a host for testing purposes.  I wouldn’t recommend this for day-to-day operations but it’s very handy when you need to try something out.  By taking advantage of variable substitution a simple template-like playbook like the one above enables easy ad-hoc execution of roles from the command line.