Ansible – How to Define Variables to Choose Import Playbook from Inventory File

ansibleconditional

I'm using Ansible (V2.8) to build two different server environments that happen to support Drupal. They are very similar in terms of the settings for the OS, RDBMS, gluster, memcached, etc. But very different with regards to the use of Drupal (different versions, different number of drupal instances, etc.). Consequently while almost all of the playbooks, var files etc. are common, I have platform-specific playbooks for Drupal.

I have separate inventory files, but a common site.yml file that just contains a bunch of import_playbook: statements.

What I'm struggling with is the best way to choose the correct drupal playbook.

At the moment I'm using the following on the command line:
-i /vagrant/inventories/inventory-env1.ini --extra-vars environment_name=env1

Which allows the following statement to work in site.yml
- import_playbook: playbooks/drupal/drupal_{{environment_name}}.yml

But that means I'm specifying the environment twice on the same command line, once to choose the inventory file and once to set a variable. As I normally find tautology is evidence of poor programming, it makes me think I'm missing a better way of doing this.

Ideally I'd like to simply specify 'environment_name' in the inventory file. But I can't because it is not available to site.yml for reasons described here:
https://github.com/ansible/ansible/issues/33659.

So, am I missing something, or is this just how it is?

Best Answer

If I understand correctly, you have a mostly shared ansible run between two servers, but each need to apply a different drupal playbook.

The best way to target hosts for a particular play is inside the playbook. Though it's logical to think that the import_playbook top level action should be targeted to specific hosts, That's not really the way ansible looks at it. Ansible builds a list of plays that contain tasks and roles (themselves containing takss), each of which targeting one or more hosts or groups, and then runs all the plays from the ansible controller host, ruuning each particular task only on the hosts it targets. Thus, what you want to do here is define separate drupal host groups for each site, and then add both playbooks to the main site, each targeting a specific group.

Here's a simplified example:

site.yaml:

- import_playbook: shared.yaml
- import_playbook: drupal_1.yaml
- import_playbook: drupal_2.yaml

shared.yaml has the os setup etc that you refer to, and it needs no change.

drupal_1.yaml looks like this:

 - hosts: drupal_site_1
 - tasks: 
    [ ... set up drupal site 1 ... ]

and drupal_2.yaml looks like this:

 - hosts: drupal_site_2
 - tasks:
 [ ... set up drupal site 2 ... ]

Now we just need to make sure the groups are defined in your inventory, and the hosts that should get the first site are in drupal_site_1, and those that should get the second site are in drupal_site_2. You could even make a server be in both groups to serve both sites ( but of course the playbooks would have to be carefully crafted not to interfere). See https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html for information about how you can group your hosts.

Using host groups keeps the targeting logic out of the plays, so it's the ideal way to target different hosts in different plays. You can limit the play to those individual hosts, or you can have a more global site run that includes all the hosts' settings. Each play still only applies to the hosts / groups it targets.