====== Dokuwiki & rsync ======
A method to synchronize two DokuWiki installations.
For more elaborate concepts on this topic see [[dokupubsub]].
===== About =====
The idea is simple: For each wiki-write-transaction a small DokuWiki action plugin launches rsync to publish/update the underlying data storage.
Synchronization happens in the background: a small perl script prevents multiple simultaneous [[wp>rsync]] processes and re-runs if changes occur during an active transfer.
===== Notes =====
Note: The index of the receiving side is not updated automatically.
While ''rsync'' is capable of bi-directionally synchronizing multiple wikis. The script below is in use on a (read/write) master to (mostly read-only) slave wiki. Use rsync's ''-u'' option, but with care: page-locks, and edit-drafts are not distributed. - While suitable for a small group of editors, race-conditions may occur on larger public wikis.
One workaround is to make a receiving namespace read-only; optionally in combination with the [[http://www.dokuwiki.org/plugin:include|include plugin]] to make parts locally writable content.
Alternatively one can make use of redirecting or proxying write-requests (HTTP-POSTs in general) to the central //master//. There can be different master servers per namespace; but depends on secure cross-site requests and authentication token passing.
Last but not least NFS-sharing the ''data/lock'' folder may be an option. see [[dokupubsub]].
[[http://dokuwiki.org/tips:farm]] and [[http://dokuwiki.org/tips:farm2]] have hints about patching DokuWiki to set up master server (aka. //farmer//).
===== Source =====
Configure and test the perl script first; then save this plugin as ''lib/plugins/rsync/action.php'' and edit a page to test it. check ''/tmp/rwikisync.log''.
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once (DOKU_PLUGIN.'action.php');
class action_plugin_rsync extends DokuWiki_Action_Plugin {
function getInfo(){
return array(
'author' => 'Robin Gareus',
'email' => 'robin@gareus.org',
'date' => '2007-05-23',
'name' => 'rsync plugin',
'desc' => 'rsync dokuwiki data',
'url' => '',
);
}
function register($contr){
$contr->register_hook('IO_WIKIPAGE_WRITE',
'AFTER',
$this,
'handle_wikipage_write',
array());
}
function handle_wikipage_write($event, $param) {
// if an old revision is saved or the file is empty -> run away
if ( $event->data[3] || !$event->data[0][1] ) return false;
//$ns=$event->data[1];
//$path=$event->data[0][0];
system ("/usr/local/bin/dokusync.pl &>/tmp/rwikisync.log &");
return true;
}
}
The Perl script to rsync the actual data. Save as ''/usr/local/bin/dokusync.pl'' or change the path in the above plugin code accordingly.
You need to change ''username'' and provide a ssh-key (just generate one with ''ssh-keygen''). There's many tutorials on [[http://www.google.com/search?q=rsync+ssh+key|ssh keys and rsync]].
#!/usr/bin/perl
### CONFIG
$rsyncopts="-azv --delete --no-o --no-g --chmod=Dg+wx,ug+rw";
$myssh="ssh -i /var/opt/id_rsa -l username";
@excludelist = ( "_darcs", "cache/", "attic/", "private/", "index/" );
$src="/var/www/data/";
$dstpath="/site/docroot/data/";
$dsthost="example.org";
$dst=$dsthost.":".$dstpath;
###prevent multiple instances
use File::Pid;
$pidfile = File::Pid->new({ file => "/var/lock/rwikisync.pid"});
if ( my $num = $pidfile->running ) {
# touch restart-file
system("touch /var/lock/rsyncrestart");
die "Already running: $num - restart scheduled\n";
}
$pidfile->write;
### build commandline
$command="rsync $rsyncopts -e \"$myssh\" ";
foreach (@excludelist) {
$command.=" --exclude '$_'";
}
$command.=" $src $dst";
### and execute it..
system("date");
system($command);
### fix group permissions
system("$myssh $dsthost \"chgrp -R www-data $dstpath 2>/dev/null\"");
# check if restart was attempted -> rm restart file and rsync again..
while ( -e "/var/lock/rsyncrestart" ) {
unlink "/var/lock/rsyncrestart";
system($command);
}
$pidfile->remove;
{{tag>dokuplugin FLOSS WWW development}}