====== 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}}