Our latest Ansible adventure has been the creation of a task structure which we can use to easily manage multiple Drupal websites on multiple servers.

It’s easy enough to use the Ansible command module to run drush commands on a bunch of Drupal sites, using the following code (where sites is just a list of Drupal root locations):

name: Run drush cc all on each site listed
command: "drush cc all chdir=/var/www/{{ item }}"
with_items:
  - sites

This is fine if you are only trying to manage sites on a single server, and you could just run this role repeatedly for different servers and change the variable in the playbook to point to a different list of sites.

You could also just include all your sites for all your servers on one list and then just run that, which would work, but you can’t use it effectively as part of a playbook as it would return tasks failed on all servers for sites it can’t find and end the play before any more tasks could be performed.

However, there is a way to make sure that the playbook only attempts to run commands on sites which are specific to each server, by storing the sites as a dictionary and looping through them using with_subelements.

This is the task:

- name: Run drush cc all on each site listed
  command: drush cc all chdir=/var/www/{{ item.1 }}
  with_subelements:
    - dev_sites
    - locations
  when: inventory_hostname == "{{ item.0.host }}"

This is an example vars file:

dev_sites:
  - host: foo.willhallonline.net
    locations:
      - drupalroot1
      - drupalroot2
  - host: bar.willhallonline.net
    locations:
      - drupalroot3

You can pretty much apply this to any drush command you choose. The when clause skips any locations which aren’t associated with each host. So now, you can run drush commands effectively on as many servers and sites as you want with a single ansible-playbook command. Which is pretty cool.