Artisan Numérique

/développement/gestionnaire de version/sgv/subversion/ Mise en oeuvre d'un serveur SubVersion

L'objectif est ici de mettre en place un serveur subversion comprenant la mise en place du dépôt, la configuration d'apache et le paramétrage des messages de notifications.

Subversion

Subversion est un projet libre initié par la société Tigris pour remplacer le vieillissant CVS. Par rapport au vénérable ancêtre, et d'un point de vue strictement architectural, subversion apporte avant tout les transactions atomiques, ainsi qu'une bien plus grande modularité dans le choix des protocoles de communication et des systèmes de stockages. Du point de vue fonctionnel il apporte bien plus encore, mais ce n'est pas notre sujet :-)

Subversion exploite un système de greffons lui permettant la prise en charge de trois protocoles différents. Nous avons évidement, comme avec CVS, le pseudo-protocole" dit "local" qui permet d'attaquer le dépôt sans passer par le réseau. Toujours comme CVS, nous avons aussi un protocole spécialisé, ultra-rapide et binaire appelé SVN (une sorte d'équivalent à CVSSERV). Cependant ce protocole SVN utilisant le port 3690/TCP, il a le "défaut" de passer relativement mal par les infrastructures réseau rompues au HTTP. Il reste cependant une très bonne option qui a déjà le mérite de ré-apprendre leur métier à certains admins "pousses-boutons" pour qui OSI est une marque de crème contre l'eczéma, tout en arrêtant de parler de sécurité en faisant passer tout et n'importe quoi par le port 80... Mais je là digresse...

La prise en charge de ce protocole est assurée par l'outil svnserve. Comme vous le voyez, l'univers CVS reste malgré tout très présent

Pour l'instant nous somme en présence de choses très équivalentes à ce que CVS offrait. La vraie nouveauté de Subversion n'est effectivement pas là, mais dans l'exploitation du protocole WEBDAV. WebDAV étant une extension d'HTTP, ce protocole utilise exactement les mêmes canaux que le WEB classique, passe à travers les pare-feux et les proxies (avec un peu de paramétrage).

Le choix de WEBDAV n'est pas anodin. Ce protocole a en effet été conçu pour ajouter à HTTP une couche "système de fichier" en ajoutant un jeu d'instructions permettant d'ajouter, supprimer, détruire, déplacer et lister. Mais plus intéressant encore, WEBDAV dispose d'une extension appelée DELTAV qui prend en charge l'historisation et la transmission de deltas de fichier, ce qui le rend idéal pour l'usage que Subversion peut en faire.

Le protocole WEBDAV est pris en charge par le module apache mod_dav et les extensions nécessaires à Subversion par mod_dav_svn. L'ensemble est donc très facile à ajouter sur une installation Apache existante et bénéficie du coup des fonctionnalités du célèbre serveur HTTP (compression, https, traces, authentification, etc.).

L'autre point de souplesse offert par Subversion est la possibilité de choisir le greffons qui va se charger du stockage physique des fichiers et des changements. En standard il est donc possible d'utiliser la "base de donnée" Bercley DB ou simplement le système de fichier local (FSFS). Maintenant dans les faits, Bercley DB n'est pas utilisé et Subversion n'a réellement décollé (ex. Projet KDE) qu'à partir du moment où le greffon FSFS a été disponible. La raison est assez simple, Bercley DB est d'une fiabilité plus que discutable et provoquait de blocages tellement grave que les dépôts qu'ils pouvaient rendre inutilisable le dépôt (situation vécue personnellement...)

A noter pour finir que Subversion apporte quelque chose de fondamental par rapport à CVS, les transactions atomiques. En termes claires, si quelque chose se passe mal lors d'un transaction (connexion coupée par exemple), Subversion l'annule comme si elle n'avait jamais eu lieu.

Création du dépôt

Pour créer le dépôt, nous utilisons la commande svnadmin comme suit :

rootsvnadmin create  --fs-type fsfs /svnroot
rootls /svnroot
conf/  dav/  db/  format  hooks/  locks/  README.txt

Une fois la commande exécutée, le dépôt est préparé et n'attend plus que nos fichiers. Le paramètre --fs-type fsfs est indispensable si l'on ne veut pas se retrouver avec un dépôt utilisant le calamiteux BerkleyDB. Avec cette option, subversion va utiliser le système de fichier standard pour stocker ces données en toute sécurité.

Choix du mode d'accès

Il existe de nombreuses manières d'accéder à un dépôt subversion. Nous allons étudier trois de ces possibilités :

  • Accès directe au service svnserve,
  • Accès indirecte au service svnserve en passant par SSH,
  • Accès au dépôt par le protocole WebDAV, via Apache.

Mise en oeuvre d'un service svnserve autonome

Le protocole SVN, pris en charge par le serveur svnserve, ne manque pas d'atouts. Utilisateurs virtuels, au bas mot deux fois plus rapide que WEBDAV, peu gourmand en ressources, simple à mettre en oeuvre et utilisable avec tous les clients sans restrictions, c'est l'option de choix pour le développement intensif et le refactoring de code. Pour ce donner une idée, même ligne, même client, même serveur, la récupération d'un projet de 50mo de code prend en 54s en WEBDAV contre 23s en SVN...

Côté mise en oeuvre, tout passe par l'ami Xinetd. Vous devez pour cela disposer d'une configuration /etc/xinetd.d/svnserve qui ressemble à cela :

service svnserve {
    disable             = no
    port                = 3690
    socket_type         = stream
    protocol            = tcp
    wait                = no
    user                = svn
    server              = /usr/bin/svnserve
    server_args         = -i -r /svnroot
}
/etc/xinetd.d/svnserve

Une fois la configuration créée ou modifiée, il suffit de relancer xinetd pour que le port 3690 soit placé sous écoute.

Comme c'est l'utilisateur svn qui va effectivement accéder au dépôt, faisons une passe de droits pour éviter les problèmes :

rootchown svn:svn /svnroot -R

Il ne nous reste maintenant plus qu'à paramétrer svnserve et modifiant le fichier /svnroot/conf/svnserve.conf

[general]
anon-access = none
auth-access = write
password-db = passwd
authz-db = authz
realm = Mon dépôt
/svnroot/conf/svnserve.conf

Notez tout d'abord qu'il est impossible de mettre des espaces devant les directives sous peine d'erreur du serveur.

anon-access = none interdit les accès anonymes au serveur tandis que auth-access = write donne un accès en lecture et écriture aux utilisateurs authentifiés. A vous de choisir pour ces deux directives entre read, write et none.

password-db = passwd indique que les mots de passes et les utilisateurs associés sont dans le fichier passwd qui se trouve au même niveau que svnserve.conf. Ce fichier reprend la même structure que svnserve.conf :

[users]
gaston = mon_de_passe
robert = mot_de_passe
josette = mot_de_passe
/svnroot/conf/passwd

authz-db = authz indique quant à elle que les autorisations trouvent dans le fichier passwd qui lui aussi se trouve au même niveau que svnserve.conf.

[groups]
equipe=robert,josette

[/]
gaston = rw
* =

[/projet_gaston]
gaston = rw

[/projet_equipe]
@equipe = rw
/svnroot/conf/authz

Déjà seul gaston a le droit d'écrire à la racine et pas les autres (* =). Ensuite nous définissons un groupe equipe contenant Robert et Josette et qui a les droits en lecture-écriture sur projet_equipe. Enfin gaston peut lire et écrire sur /projet_gaston. Notez qu'il y a héritage des droits, il n'est donc pas nécessaire d'interdire à tous la lecture sur les projets, c'est déjà fait à la racine.

C'était le dernier fichier à paramétrer, nous pouvons maintenant tester :

gastonsvn mkdir svn://mon_site/projet_gaston/test
test du protocole SVN

Utilisation du service svnserve via SSH

Dans le mode précédent, nous sommes obligé de créer une sorte de compte, et les accès qui vont avec, pour chaque utilisateur. Avec SSH, svnserve est lancé directement par l'utilisateur qui tente l'accès. Le service ainsi lancé dispose des droits de cet utilisateur, ne nécessitant du coup pas de création de compte. C'est pour moi un gros avantage, doublé de celui de ne pas avoir à ouvrir un port supplémentaire sur le monde extérieur. En effet, toutes les transactions passent par le tube chiffré de SSH. L'inconvénient est évidement que chaque utilisateur ayant à utiliser subversion doit avoir son compte sur la machine distante.

Pour ce qui est des autorisations d'accès à telle ou telle ressource, cela se passe exactement comme pour le mode précédent, en utilisant le fichier authz, mais en référençant cette fois des utilisateurs "réels" de la machine distante.

Pour utiliser ce mode, il n'y a rien à faire de bien particulier. Vous devez juste configurersvnserver.conf comme indiqué dans le mode précédent en prenant cependant soin de commenter la ligne password-db = passwd. Ensuite, vous devez créer un groupe commun à tous les utilisateurs et régler les droits sur le dépôt de sorte à ce que les fichiers de celui-ci conservent une autorisation en écriture pour le groupe (c'est expliqué ici). Enfin, comme le service svnserve est lancé par SSH, vous n'avez plus à configurer (ou même installer) xinetd.

Lorsque tout est en place, vous pouvez tester comme ceci :

gastonsvn mkdir svn+ssh://mon_site/svnroot/projet_gaston/test
test du protocole SVN+SSH

Vous pouvez simplifier encore l'accès en ajoutant une clef publique au serveur distant, sinon la commande vous demandera votre mot de passe avant de vous connecter. Notez enfin la présence de /svnroot/ dans l'URL qui permet au service svnserve que vous allez lancer de savoir où se trouve votre dépôt.

Accès par le protocole WEBDAV

Dans la mesure où c'est Apache qui va devoir gérer ce dépôt, il est important de lui donner les droits sur le dossier /svnroot. Si vous désirez utilisez WEBDAV en plus de SVN, ajoutez plutôt apache au groupe svn.

rootchown apache:apache /svnroot -R

Dans ce qui suit Apache est considéré comme installé et opérationnel sur votre serveur. Mais pour permettre l'utilisation de Subversion, il nous faut quelques modules supplémentaires : apache-mod_dav et apache-mod_dav_svn. En effet, WebDav est le protocole utilisé par subversion pour communiquer à travers le WEB. Le premier module va donc ajouter le protocole webdav à Apache, et le second d'étendre se protocole pour gérer spécifiquement les dépôts subversion.

Ensuite, il nous faut modifier le fichier de configuration d'apache /etc/httpd/conf/httpd2.conf en ajoutant le bloc suivant:

<Location /subversion>
  DAV svn
  SVNPath /svnroot
  AuthzSVNAccessFile /svnroot/droits
</Location>
Mise en place de subversion dans la configuration d'Apache

Cela a pour résultat d'ajouter à Apache une URL http://mon_site/subversion permettant l'accès au dépôt situé en /svnroot. L'option AuthzSVNAccessFile indique quant à elle le chemin vers un fichier texte contenant les droits associés au dépôt.

[/]
* = r
robert  = rw

[/un_projet]
gaston = rw
ginette = r
exemple de fichier de droits subversion

Tels que nous avons défini les droits, Robert a un accès complet en lecture et écriture à tous les projets. Gaston a un accès en lecture/écriture au projet un_projet et Ginette (sexisme !!) n'a accès qu'en lecture à ce même projet.

Maintenant pour que cela fonctionne, il faudrait qu'Apache ait le login de l'utilisateur. Il est donc nécessaire d'ajouter un bloc d'authentification à notre section location. Dans ce domaine, c'est à chacun de choisir : fichier apache, shadow, etc. Jetez un œil ici pour avoir des idées sur quel système utiliser.

Une fois que tout est en place, il suffit de relancer apache et d'aller à l'URL http://mon_site/subversion. En effet, Subversion fonctionne aussi bien en WebDav qu'en HTTP. Dans le second cas il est possible, si l'on a les bon droits, d'explorer le dépôt en lecture seule.

Ensuite, nous pouvons tester en ligne de commande :

gastonsvn mkdir http://mon_site/subversion/un_projet
Utilisateur:gaston
Mot de passe:$ mon_secret
Révision 1 propagée.
gaston$
Test du serveur

Rajouter des scripts de notification

Un aspect très sympathique de subversion est la facilité avec laquelle il est possible d'ajouter des actions sur les divers événements générés dans un dépôt.

svnadmin a normalement créé un dossier hooks dans votre dossier /svnroot. Ce dossier contient déjà les modèles des cinq événements qu'il est capable de prendre en charge. Par défaut ces fichiers ont l'extension .tmpl ce qui les rends inactifs. Il faut donc ôter cette extension sur chacun des fichiers que vous désirez utiliser :

  • post-commit, appelé après un commit.
  • post-lock, appelé après un lock.
  • pre-lock, appelé avant un lock.
  • pre-unlock, appelé avant un unlock.
  • post-revprop, appelé après un changement de révision.
  • pre-commit, appelé avant la fin du commit.
  • start-commit,appelé avant le commit.
  • pre-revprop-change, appelé avant un changement de révision.

Comme exemple, imaginons que nous voulons envoyer un courriel aux développeurs d'un projet à chaque commit dans le dépôt. Pour cela nous allons créer un fichier /svnroot/hooks/post-commit :

#! /bin/sh

REPOS="$1"
REV="$2"

/usr/bin/svnnotify -r $REV -C -d -H HTML::ColorDiff -p $REPOS -x gaston@mon_site.com=projet1 --from no-reply@mon_site.com --reply-to no-reply@mon_site.com

svnnotify fait partie du projet perl-svn-notify qu'il faut donc installer. Pas la peine d'aller le télécharger, il est sûrement inclus dans les dépôts de votre distribution.

Une fois installé, il faut changer les droits sur ce hook pour permettre à apache de l'exécuter. Le plus simple est de relancer la commande chmod que nous avions utilisé au début pour tout le dépôt :

chown apache:apache /svnroot -Rc

Maintenant à chaque commit, si ce dernier appartient au projet projet1, cela provoquera un envoi de courriel à gaston. On peut spécifier plusieurs arguments -x ainsi que plusieurs adresses séparées par des virgules. Par exemple -x toto@mondomaine,tutu@mondomain=mon_module.

Erreur "502 Bad Gateway"

Si vous avez droit un jour à un svn: COPY of package.sh: 502 Bad Gateway (https://mon_serveur/subversion), il est probable que vous ayez tenté une copie/déplacement à travers une connexion HTTPS et ça ne marchera pas.

Sinon, autre cas problématique, celui de l'utilisation de reverse proxy sur le serveur cible (la cible est une machine apache A qui est accédée via HTTPS et qui relaye les requêtes sur une machine apache B qui gère le dépôt).

Dernière possibilité, une mauvaise définition du nom de serveur au niveau de la cible (le servername du vhost est mal configuré).

Conclusion

Voilà, c'est tout. Votre dépôt subversion est maintenant pleinement opérationnel. Enfin j'espère :-) .