Synchronisation de répertoires distants + AjaXplorer

Ces derniers jours, j’ai voulu régler la problématique suivante :
Avoir la possibilité de faire des sauvegardes des documents (Papiers, musique, ebooks etc.) qui sont chez moi, sur mon petit media center. Le plus important étant de faire une sauvegarde distante, j’avais le choix entre faire ces sauvegardes sur le serveur que j’ai chez OVH, et les faire chez un hébergeur qui propose des solutions prêtes à l’emploi (style Dropbox). Comme je n’aime pas du tout le principe des Dropbox-like, et que je préfère faire les choses moi-même (on apprend généralement plus de choses…), j’ai choisi la première solution. En plus de la problématique des sauvegardes, je souhaitais avoir un accès simple aux données que je sauvegarde en ligne, de la même façon que j’ai un accès simple aux données de mon media center (Samba pour les fichiers, Homeplayer pour les medias, via la Freebox). Ayant un accès aux sauvegardes en ligne, je souhaitais également pouvoir ajouter et supprimer des fichiers en ligne, et que ça soit répercuté sur mon media center. Il ne s’agirait donc plus vraiment d’une sauvegarde, mais plutôt d’une synchronisation bidirectionnelle.

La synchronisation

Ceux qui ont de la synchronisation unidirectionnelle à faire connaissent certainement rsync, qui est un très bon outil pour faire des sauvegardes via ssh. Seulement, il n’est pas adapté à la synchronisation bidirectionnelle.
J’ai donc cherché un autre outil, et je l’ai trouvé : unison (je le dis comme s’il s’agissait d’une grande découverte, mais je suppose que les personnes qui ont déjà dû faire de la synchronisation bidirectionnelle connaissent déjà l’outil…).

Unison

Unison fonctionne via un fichier de configuration (un fichier de configuration par dossier à synchroniser… récursivement, évidemment).
Personnellement, j’ai eu besoin d’un fichier de configuration très simple, car je voulais synchroniser l’intégralité des répertoires (pas de fichiers à ignorer à l’intérieur des répertoires). Voici donc à quoi ressemble un fichier de configuration (« photos.prf ») sur mon serveur OVH :

root=ssh://mael@media-center:22//mnt/data/Photos
root=/home/www-data/Photos/

Bien entendu, si on souhaite par la suite utiliser unison en mode non-interactif, il faut effectuer un échange de clés SSH entre les deux serveurs.

On indique donc qu’on veut synchroniser le répertoire « /mnt/data/Photos » du media center avec le répertoire « /home/www-data/Photos » du serveur.
Pour commencer la synchronisation, il suffit alors de lancer la ligne de commande suivante (il faut que le fichier « photos.prf » soit situé dans le répertoire ~/.unison) :

unison photos.prf

Unison va alors comparer les contenus des dossiers – ça peut être assez long la première fois, s’il y a beaucoup de fichiers – , puis demander à l’utilisateur ce qu’il souhaite faire. Personnellement, j’ai systématiquement choisi l’option « g », qui indique à unison de se débrouiller à « merger » les deux répertoires.
Une fois la première synchronisation effectuée, il est possible de lancer unison en mode « silent », pour qu’il synchronise les répertoires d’une manière non interactive. L’option « -silent » sert à ça :

unison -silent photos.prf

Je conseille, si possible, de synchroniser les deux répertoires à la main avant de lancer unison la première fois.

On peut alors imaginer de lancer unison régulièrement grâce à un cron, sachant qu’il n’y a pas à craindre de conflits : si unison se lançait 2 fois en même temps pour la synchronisation des 2 mêmes répertoires, la deuxième synchronisation serait bloquée :

The file /home/user/.unison/lk89675453041cac3ae95768a69fc3f068 on host media-center should be deleted
The file /home/user/.unison/lka0e37cd07ee834a1856ac0d86f24b840 on host serveur should be deleted

Cette solution avec le cron ne me plaît qu’à moitié : je préfère avoir une synchronisation en temps réel : dès qu’un fichier est ajouté sur le media center ou le serveur, la modification est répercutée sur l’autre. Il y a éventuellement la possibilité de lancer des cron très régulièrement, mais c’est sale, et ça doit certainement mobiliser des ressources inutilement.
J’ai donc cherché un moyen de synchroniser en temps réel avec unison.

Synchronisation en temps réel

Unison propose une option qui permet de faire de la copie en temps réel. Pour cela, il suffit normalement d’ajouter l’option : « -repeat watch » à la commande unison. Mais visiblement, l’option ne fonctionne pas sous la version de Unison utilisée par debian Squeeze : je n’ai jamais réussi à faire fonctionner la synchronisation en temps réel avec la version d’unison présente dans les dépôts.
J’ai donc commencé par créer un script bash utilisant Inotify. Ca fonctionnait plutôt bien, mais j’ai cherché une meilleure solution. Et la seule que j’aie trouvée, c’est de compiler unison depuis le trunk de leur svn.

Il faut d’abord installer les dépendances :

# apt-get install python-pyinotify ocaml subversion emacs23-bin-common

Je ne suis pas certain que « emacs23-bin-common » soit nécessaire : la compilation semblait bien me générer un binaire sans cette dépendance, mais une erreur était tout de même lancée, alors dans le doute…

On peut ensuite récupérer les sources :

# svn checkout https://webdav.seas.upenn.edu/svn/unison/trunk

Puis compiler :

# cd trunk && make NATIVE=true UISTYLE=text

Edit : Sous une architecture arm, pour que ça fonctionne, il faut compiler comme ceci :

# cd trunk && make NATIVE=false UISTYLE=text

Il faut ensuite copier les deux fichiers src/unison et src/fsmonitor.py dans le PATH

Désormais, la synchronisation en temps réel fonctionne bien. Il suffit donc de modifier la commande pour qu’elle ressemble à ça :

unison photos.prf -repeat watch

Et la synchro en temps réel fonctionne parfaitement. Magique, non ?
On peut également faire un petit script de démarrage :

#!/bin/sh
### BEGIN INIT INFO
# Provides:          unison_sync
# Required-Start:    $local_fs $remote_fs $syslog $network $named
# Required-Stop:     $local_fs $remote_fs $syslog $network $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts unison sync at boot time
### END INIT INFO

UNISON_CONFIGS="bouquins.prf documents.prf"
PID_DIR="/var/run/unison"
PID_FILE="unison_sync.pid"
LOG_FILE="/var/log/unison_sync.log"

stop() {

        if [ ! -f $PID_DIR/$PID_FILE ]; then
                echo -e "Unison is not running"
                exit 1
        fi
        echo -n "Stopping unison processes... "
        cat $PID_DIR/$PID_FILE | while read PID
        do
                echo -n "Killing $PID... "
                kill $PID
                echo -n "OK. "
        done
        killall fsmonitor.py
        rm $PID_DIR/$PID_FILE
        log "Unison stopped"
}

start() {
        if [ ! -d $PID_DIR ]; then
                mkdir $PID_DIR
        fi
        if [ -f $PID_DIR/$PID_FILE ]; then
                echo -e "Unison is running with pid(s) :\\n$(cat $PID_DIR/$PID_FILE)"
                exit 1
        fi
        for conf in $UNISON_CONFIGS
        do
                nohup unison $conf -repeat watch -logfile $LOG_FILE >> $LOG_FILE 2>&1 &
                echo "$! " >> $PID_DIR/$PID_FILE
                log "Started unison for $conf"
        done
}

log() {
        echo "[$(date '+%d-%m-%y %T')] : $1" >> $LOG_FILE
        echo $1
}

case $1 in
        start)
                start
        ;;
        stop)
                stop
        ;;
        *)
                echo "Usage : `basename $0` {start|stop}"
                exit 1
        ;;
esac

Pour debian, à placer dans /etc/init.d
Attention : avec ce mode de fonctionnement, seuls les fichiers ajoutés/modifiés/supprimés après le lancement de la commande sont synchronisés. Il faut donc lancer la commande une fois que les deux dossiers sont déjà synchronisés.

Accès aux fichiers du serveur

On a donc un système qui permet de synchroniser en temps réel 2 répertoires distants. Il faudrait maintenant un moyen simple (et agréable) d’accéder aux fichiers qui sont sur le serveur en ligne. J’ai d’abord pensé à Webdav. C’est simple, et généralement bien intégré au sein d’un explorateur de fichier. Seulement, et j’ignore pourquoi exactement, Webdav s’avère hyper lent au niveau de la navigation et de la copie de fichiers (testé sous Crunchbang Linux, avec thunar). J’ai donc cherché quelque chose de rapide, et aussi de plus « user friendly » (je ne serai à priori pas le seul à accéder aux fichiers). Et j’ai trouvé AjaXplorer. AjaXplorer est une application développée en PHP côté serveur (pas de base de données), et possède une interface entièrement en Ajax côté client.
Voilà à quoi ça ressemble :
.
Dans l’administration de l’application, on peut ajouter des « dépôts », qui vont permettre d’autoriser l’accès à des dossiers situés sur le serveur, entre autres, car on peut également ajouter des dépôts correspondant à un serveur FTP, un partage samba, un partage webdav, et d’autres encore. Les fichiers présents dans les dépôts sont ensuite directement accessible dans le navigateur, et, petit bonus, sont également accessible via webdav, si l’on active l’option. J’ai beaucoup aimé également la possibilité de partager un fichier : on peut créer un lien (virtuel) vers un fichier : AjaXplorer génère un lien, pour lequel on peut indiquer une durée de validité, et qu’on peut protéger par un mot de passe. Il suffit alors de donner ce lien à la personne avec qui ont veut partager le fichier.

On peut aussi créer des utilisateurs et des rôles, et leur affecter des droits sur les dépôts.
AjaXplorer permet également d’éditer les fichiers en ligne (fichier textes, documents doc ou odt), de lire les MP3 directement, de naviguer entre les images via un « viewer » et de visualiser les PDF. Comme pour un navigateur de fichiers, on peut forcer l’ouverture d’un type de fichiers par un éditeur particulier.
Une fonctionnalité très intéressante est la possibilité d’ajouter des fichiers directement par un glisser-déposer (drag-and-drop) dans le navigateur. Ca ne semble pas fonctionner sur Iceweasel, sous GNU/Linux : j’ai testé avec différentes versions, pas moyen de le faire fonctionner, alors que ça fonctionne sous chromium, et sous Firefox pour d’autres OS (A noter que j’ai essayé sur d’autres appli, comme wordpress, et que ça ne fonctionne pas non plus, donc le soucis ne vient pas de AjaXplorer).

Evidemment, il ne faut pas s’attendre à naviguer entre les dossiers d’AjaXplorer d’une manière aussi fluide que dans un navigateur de fichiers locaux, mais j’ai quand même trouvé l’utilisation agréable. Il faudrait tester sur des machines moins puissantes comme un netbook, pour voir si le javascript ne ralentit par trop la navigation.

Conclusion

L’association d’un petit outil très puissant (unison), et d’une très bonne application web (ajaXplorer) permet de répondre totalement à l’objectif que je m’étais fixé. Le tout en utilisant uniquement des solutions libres, bien entendu.
Il faut noter que AjaXplorer est entièrement bâtie sur une architecture faite de plugins : d’après ce que j’ai vu, le moindre fonctionnement de l’application fait appel à un plugin, et il est possible de créer des interdépendances entre les plugins. Du coup, le développement d’un plugin pour répondre à un besoin spécifique (j’ai par exemple pensé à un plugin qui permettrait de faire de l’édition/compilation/visualisation de LaTeX) est grandement facilité.
A voir si la solution tiendra dans le temps. Par exemple, si unison plante régulièrement et arrête la synchronisation, ça va vite m’énerver. Mais il n’y a pas de raison, à priori.

Vus : 4608
Publié par mael : 17