Combine Aegir, Ansible and Jenkins for automated Drupal platorm deployment!

[Note: This is what we do for a living, contact us or leave a comment if you have any questions!]

The most labor-intensive part of hosting Drupal sites is probably updating them. Aegir already saves you a lot of manual labor, with its inherent multisite support and automatic vhost management (see the official documentation for more details on this).

However, you still have to download Drupal and create the new platform in the frontend. This is where Ansible and Jenkins can really come in handy.

Our Ansible scripts show a way to deploy Drupal platforms automatically. You can see the details for yourself, but the interesting part is in auto-deploy:


# Check whether most recent platform is already deployed
- name: Check if latest platform is deployed
  shell: "[ -d /var/aegir/platforms/{{ platform_name }}-{{ platform_release_number }} ]"
  ignore_errors: True
  changed_when: False
  always_run: True
  register: platform_exists


# ...
- name: Clone latest makefiles
  git: repo={{ makefiles_repo }} dest=/var/aegir/makefiles/{{ platform_name }}_makefiles version="{{ platform_release_number }}"
  when: platform_exists|failed


- name: Create latest platform
  shell: sudo -u aegir drush make /var/aegir/makefiles/{{ platform_name }}_makefiles/{{ makefile_name }} /var/aegir/platforms/{{ platform_name }}-{{ platform_release_number }}
  when: platform_exists|failed


- name: provision-save the platform
  shell: sudo -u aegir drush --root=/var/aegir/platforms/{{ platform_name }}-{{ platform_release_number }} provision-save @platform_{{ platform_name }}-{{ platform_release_number }} --context_type=platform --makefile={{ makefile_name }}
  when: platform_exists|failed


- name: Import the platform into hostmaster
  shell: sudo -u aegir drush @hostmaster hosting-import @platform_{{ platform_name }}-{{ platform_release_number }}
  when: platform_exists|failed

The interesting commands are the last and second-to-last ones, which import the platform into Aegir. That way, we don't have to log into the frontend and fill the platform creation form. Most of the variables come from server.yml (explained lower).

If you look at the library, you'll notice the custom latest_versions script. It uses rsstail to get the latest available version from an RSS or atom feed. This is useful because all GitHub and Drupal projects have feeds based on versions.

On GitHub, you can find the feed at [project url]/tags.atom . On drupal.org, you'll have to follow the list of versions releases, so you may want to mirror your project to GitHub . Jon Pugh's HubDrop automates this mirroring (for free).

Finally, at the bottom of server.yml, you can see that we use role variables:
- { role: auto-deploy, platform_name: getopenoutreach, makefiles_repo: "http://[etc]", makefile_name: getopenoutreach.make, release_feed: "https://[etc]/releases.atom", tags: auto-deploy }

This is because I found it silly to use a different role for each makefile. If you find this inelegant, you can always create a different shell script for each platform in your library folder and hardcode the values (it's just a JSON array).

At this point you have an Ansible script that deploys new versions of platforms when you run it.

But wait, there's more!

You can install Jenkins and use it as a deployment mechanism. (Jenkins is a FLOSS tool that runs arbitrary tasks and displays the resulting console log.)

This is the gist of what I did for this part:

  • I tagged all the platform roles as “auto-deploy” (we don't want to run the whole scripts randomly)
  • I created a shell script that runs ansible-playbook -s [path to scripts]/server.yml --tags auto-deploy (you might want to test this in --check mode first)
  • I gave the Jenkins user sudo permission to run the script (we don't want to allow jenkins to run just an ansible-playbook command)
  • I created a job in the Jenkins frontend that simply runs the shell script every hour.

I also use the TextFinder plugin to scan the results and mark “changed=[1-9]” as unstable (in a post-build action), this way I receive an email when new platforms get deployed.

You may want to use Jenkins' Git hook integration for new tags, but this seems somewhat less reliable. (As it seems that Jenkins would “miss” the push if it was unreachable at the moment.) Please comment if you have an opinion on this!

That's about it for the auto-deploy function. Feel free to ask questions on this or our general scripts on here or on Twitter.

Once again, give us a shout if you want us to do this for you. We also deploy a few of these platforms on our AegirVPS service, so if all you want is up-to-date platforms, you might want to consider it.

Thanks for reading!