Drupal and Multisites - Getting updates done right

Drupal at MSU Libraries

Drupal has become a big part of my job in the last year and a half. We have moved our public facing website over to Drupal 7 from a home-grown java based site. It has been fun to learn Drupal, teach other people how to manage their own pages, and learn how to administer the site. I've written a few modules here and there, but one of the biggest things I've done is set up our Intranet websites using a multi-site setup in Drupal.

A Drupal multisite is mainly a bunch of sites that, behind the scenes, share the same Drupal core. With our setup, they also share modules, libraries, and themes. Thus, updates are relatively easy, as you only need to do a single core and module update for the changes to be reflected by all sites. They may not all have the same modules enabled, but they all have the same versions available.

Subsite databases must be updated

Recently, I discovered that we were missing a crucial part in the update process. Because module updates can alter the database structure (modules can have their own tables), database updates must be run for each subsite. Subsites share the same Drupal core and module code, but they have their own database and tables.

If you don't run the updates for each site, then only the main (default) site will get the proper database updates. This can cause subsites to have the White Screen of Death; their modules have been updated, and their modules expect the database to have been updated as well.

Scripting the update

Since our intranet has a site for each department, we have several dozen subsites to manage. Updating each site manually would be time consuming, and a site could easily be missed. I was about to write a script when I found that someone else had written one that I could use. The script will loop through all the folders in the subsite directory (excluding the Default folder) and will run `drush updatedb` on them all. I modified it slightly and posted it here.

The script must be placed within the sites directory. Save the code in a file called update-multisite.sh and mark it as executable (chmod +x update-multisite.sh). When run, option 1 updates the databases. It also has other useful features, such as clearing the cache and disabling a specific module.

Please note that Drush is required for this script to do its magic. If you haven't used Drush, it is an amazing utility that can manage your Drupal site directly from the command line. Installing modules, clearing the cache, setting roles, etc; Almost anything that can be done from the web GUI is accessable via Drush. Check it out!

Script Code

# This gives the user a prompt with often-needed commands.
# When the user makes a choice, it will run the command
# on all drupal subsites (as well as the default/main site).

# Version 2.0 Now it uses the built-in drush macro to run
# the drush command on all sites.
# Also, the commands are now all run with 'www-data' permissions,
# which will prevent file permission errors and will let the
# user run this script without explicitly setting the user.
# Of course, if the current user isn't allowed to run as
# www-data, this will fail.

user_and_command='sudo -su www-data ' #run as user www-data. prevents file permission errors.

drush_prefix='drush --yes @sites --root=/var/www/replace_with_your_drupal_core_location'
# drush: the main command to run
# --yes: noninteractive
# @sites: lists main site and all subsites (build-in drush macro)
# --root: location of drupal core

echo "Choose the commande to execute : "
echo "1. update database"
echo "2. put sites offline"
echo "3. put sites online"
echo "4. rebuild permissions"
echo "5. clear all cache"
echo "6. clear css+js cache"
echo "7. clear specific cache"
echo "8. install specific module"
echo "9. disable specific module"
echo "10. uninstall specific module"
echo -n "Input [1,2,3,4,5,6,7,8,9, or 10] ? "
read choice

if [ $choice -gt 7 ] ; then
echo -n "Extension (module/theme) name ? "
read ext

# For each site, execute the command
echo ----------
echo $site
cd $site
if [ $choice -eq 1 ] ; then
$user_and_command $drush_prefix updatedb
elif [ $choice -eq 2 ] ; then
$user_and_command $drush_prefix vset --always-set maintenance_mode 1
elif [ $choice -eq 3 ] ; then
$user_and_command $drush_prefix vset --always-set maintenance_mode 0
elif [ $choice -eq 4 ] ; then
$user_and_command $drush_prefix php-eval 'node_access_rebuild();'
elif [ $choice -eq 5 ] ; then
echo $user_and_command $drush_prefix cc all
$user_and_command $drush_prefix cc all
elif [ $choice -eq 6 ] ; then
$user_and_command $drush_prefix cc css-js
elif [ $choice -eq 7 ] ; then
$user_and_command $drush_prefix cc
elif [ $choice -eq 8 ] ; then
$user_and_command $drush_prefix pm-enable $ext
elif [ $choice -eq 9 ] ; then
$user_and_command $drush_prefix pm-disable $ext
elif [ $choice -eq 10 ] ; then
$user_and_command $drush_prefix pm-uninstall $ext