Community & Support

Mass/Multi installations update - how to do that. How YOU do it?

hi all!

i administer a project-server with 500+ Drupal-installations on it.
All these installations have one, collectively used "core installation".

As the websites count was about 100 the updates took a lot of time, i.e. one whole day, and already
that was too much. But now, as there are > 500 sites, it's simply unmanageable...

Now the question: is there another way to do updates or, so to say, simply to klick the "update.php"
on the website? I mean, "update.php" do nothing more then calling some functions and interact with the user.
And can i somehow do a "mass" update? And can it be done unattended??

Or are there maybe other ways to do such mass updates of installations?

Thanks !

Vladimir

Comments

You might want to move

You might want to move frequently used non-core modules to the central installation. That way, those modules only have to be updated once and not for each installation.
Just curious? Is that a shared server or some dedicated business server?
What is the hardware?

-----------------------------------------
Joep
CompuBase, Drupal, websites and webdesign

-----------------------------------------
Joep
CompuBase, Dutch Drupal full service agency

well, the core and the

well, the core and all the modules (and themes) are in the central installation.

No, it's not a shared server :-)

It's a pair of 2U 19" Servers: one as Webserver, one as DB-Server.
Webserver is an IBM xSeries 345, 2x3,06 GHz Xeons, 4 GB RAM, 2x36 GB HDD for system, 2x73 GB for sites.
DB-Server is identical, just the 2x73 GB for are for dbs.
+ Many tweaks and brainwork ;-)

Hm, i googled a lot, and as it seems, the problem identical to mine exists; but only the problem, not the solution :-/

Boah, maybe hire a dosen of students to click "update.php" ? :-) LOL

subscribing

subscribing

DRUSH

http://drupal.org/project/drush

http://drupal.org/node/477684

try writing a script which makes use of DRUSH. I'm thinking that you could script putting the sites into maintenance mode, looping through a DB backup of each site, updating the core then scripting a loop through each site to run the update.php

drush --uri=http://www.domain-one.com updatedb
drush --uri=http://www.domain-two.com updatedb

Then put them back online

Just a half baked idea I'm afraid.

thanks, never heard of the

thanks, never heard of the "drush"-thing but - hey, it seems really to be interesting;

does

drush --uri=http://www.domain-one.com updatedb

works non-interactively?

Just checked, it asks if you

Just checked, it asks if you want to
"Do you wish to run all pending updates? (y/n) :"

But if you run
drush --uri=http://www.domain-one.com --yes update
then it'll get the new modules, backup the old ones and run updatedb as one.

Would be useful to know if the --yes flag also worked on the updatedb command.

Just thinking about your

Just thinking about your update task. I'm guessing these 500 sites are very similar to each other? But this task could take hours even if scripted.

I'm wondering if you could have two drupal installations?

/var/www/drupal-6.12
and
/var/www/drupal-6.13

Then have the script create an array of the directories in /var/www/drupal-6.12/sites.
Then loop doing the following

1: Put site into maintenance mode.
2: Copy site's directory cp -a /var/www/drupal-6.12/sites/www.domain-one.com to
/var/www/drupal-6.13/sites/www.domain-one.com
3: create a db backup
4: run drush --uri=http://www.domain-one.com --yes update
5: change the vhost entry in httpd.conf from /var/www/drupal-6.12/sites/www.domain-one.com to
/var/www/drupal-6.13/sites/www.domain-one.com
6: Reload the server.
7: Put site backonline.
8: Do some test to check all went well.
9: log result.

loop back and do the same on next domain in array

well, the only problem now is

well, the only problem now is to deactivate all non-core modules before
the upgrade... But how i saw, drush can list module status on website, so
im sure, the output can be parsed and then make a kinda loop throug all
enabled modules and deactivate them before update..

Hmm ... well, i think i'll wriite the script in the next days :-)

This is the perl script I use

This is the perl script I use - its based on an apache setup (and needs the Apache::ConfigParser perl module), but I guess it could be modified for other webservers.

It just outputs the drush commands required, rather than executing them - the main reason for this is that drush (AFAIK) can't do the actual core update, but you can copy and paste them into a terminal window or script and execute them that way.

#!/usr/bin/perl
# --------------------------------------------------------------------------------------
#
# Script to generate drush commands required for a core update
#
# Simon Hanmer          simon.hanmer@gmail.com
# IntelligentWeb Ltd    http://www.intelligentweb.co.uk
#
#
--------------------------------------------------------------------------------------

use strict;
use Apache::ConfigParser;

my %server;

my @core_modules = qw( block color comment dblog filter help menu node system taxonomy update user);

my %cmds = (
    'disable' =>   "drush -r %s -l http://%s -y disable %s\n",
    'update' =>    "# << DO MANUAL UPDATE >>\n",
    'enable' =>    "drush -r %s -l http://%s -y enable %s\n",
    'cron' =>      "drush -r %s -l http://%s cron\n",
    'refresh' =>   "drush -r %s -l http://%s refresh\n"
);



# --------------------------------------------------------------------------------------
#
#  First step is to parse the apache config to find our hosts.
#  Then for each host find the non-core modules
#
# --------------------------------------------------------------------------------------

my $parser = Apache::ConfigParser->new;
my $cf = $parser->parse_file("/usr/local/apache2/conf/httpd.conf");                     # Read apache config

foreach my $server ($parser->find_down_directive_names('ServerName')) {                 # For each server, get document dir
    my $serverName = $server->value;

    my @root = $parser->find_siblings_and_up_directive_names($server, "DocumentRoot");
    if ( -r $root[0]->value."/COPYRIGHT.txt" ) {                                        # Is this a Drupal directory -
        $server{$serverName}{'root'} = $root[0]->value;                                 # if so, store root directory

        my $drush_cmd = sprintf("drush -r %s -l http://%s -p statusmodules|", $root[0]->value, $serverName);

        open DRUSH, $drush_cmd || die "Can't run drush";
        my $drush_modules = <DRUSH>;
        close DRUSH;

        my @module_list = split(/ /, $drush_modules);
        my @non_core = grep { my $x = $_; not grep { $x =~ /\Q$_/i } @core_modules } @module_list;
        @{$server{$serverName}{'module'}} = @non_core;
    }
}


# --------------------------------------------------------------------------------------
#
#  Now generate required output for each stage
#
# --------------------------------------------------------------------------------------
foreach my $cmd (qw(disable update enable refresh cron)) {
    do_action($cmd);
}

exit;






sub do_action {

    my ($opt) = @_;

    foreach my $host (keys(%server)) {
        my $root_dir = $server{$host}{'root'};
        my @module_list = @{$server{$host}{'module'}};
   

        if (scalar(@module_list) > 0) {
            printf($cmds{$opt},
                $root_dir,
                $host,
                join( ' ', @module_list)
            );
        }
    }

    print "\n\n";
}

An example of the output would be:

drush -r /home/common/public_html -l http://www.site1.com -y disable gallery gallery_g2image libraries wysiwyg
drush -r /home/common/public_html -l http://www.site2.net -y disable gallery gallery_g2image libraries wysiwyg
drush -r /home/site3/www -l http://www.site3.co.uk -y disable captcha content content_copy date date_api date_popup date_timezone feedapi fieldgroup filefield flir gallery gallery_g2image gallery_profile gmap gmap_macro_builder googleanalytics link number og og_views optionwidgets parser_common_syndication path php search statistics text text_captcha trigger views views_bulk_operations views_ui webform workflow workflow_access wysiwyg

# << DO MANUAL UPDATE >>
# << DO MANUAL UPDATE >>
# << DO MANUAL UPDATE >>

drush -r /home/common/public_html -l http://www.site1.com -y enable gallery gallery_g2image libraries wysiwyg
drush -r /home/common/public_html -l http://www.site2.net -y enable gallery gallery_g2image libraries wysiwyg
drush -r /home/site3/www -l http://www.site3.co.uk -y enable captcha content content_copy date date_api date_popup date_timezone feedapi fieldgroup filefield flir gallery gallery_g2image gallery_profile gmap gmap_macro_builder googleanalytics link number og og_views optionwidgets parser_common_syndication path php search statistics text text_captcha trigger views views_bulk_operations views_ui webform workflow workflow_access wysiwyg

drush -r /home/common/public_html -l http://www.site1.com refresh
drush -r /home/common/public_html -l http://www.site2.net refresh
drush -r /home/site3/www -l http://www.site3.co.uk refresh

drush -r /home/common/public_html -l http://www.site1.com cron
drush -r /home/common/public_html -l http://www.site2.net cron
drush -r /home/site3/www -l http://www.site3.co.uk cron

depends on the size of your multi site instances.

I have a few multi site instances that I manage. For a couple of smaller ones (less than 20 sites each) I use the following bash script:

#!/bin/sh
# Update all sites using drush
# Written by Dave Hall <dave.hall@skwashd.com>
# Copyright (c) 2009 Dave Hall Consulting http://davehall.com.au
#
Permission granted to use under the terms of the CC-BY-SA license http://creativecommons.org/licenses/by-sa/3.0/
DRUSH_PATH=/home/bluejube/drush/drush
SITES_PATH=/srv/www/cms/sites
PWD=$(pwd)
cd $SITES_PATH;
for site in `find ./ -maxdepth 1 -type d | cut -d/ -f2 | egrep -v '(.svn|all|default)'`
do
  echo updating $site
  ~/drush/drush updatedb -y -l $site
done
cd $PWD

For a much larger instance (almost 2000 drupal sites and growing), I use aegir as it has better error handling.

It really depends on what your requirements are.

nobody click here