Affichage des articles dont le libellé est svn. Afficher tous les articles
Affichage des articles dont le libellé est svn. Afficher tous les articles

jeudi 13 juin 2013

Administration d'un serveur SVN à l'aide de SVN

Ma vie trépidante d'administrateur m'a amené dernièrement à mettre en place un serveur SVN en place (en utilisant le module Apache couplé avec authentification LDAP) et surtout l'isolement de ce serveur dans une bulle derrière des firewalls.

D'un côté c'est vrai que c'est bien la sécurité et tout ça, mais de l'autre, à chaque fois que j'ai envi de modifier un truc sur mon serveur, je suis un peu obligé de me connecter via un VPN + tunnel SSH. Comme chacun sait, je suis un gros feignant et c'est pas par gaîté de coeur que je m'y connecte. C'est donc assez naturellement que je me suis dit : et si j'utilisais un repository SVN pour faire mon administration ? Diabolique non ? De plus je gagnais instantanément un suivi de qui modifié quoi sur mon serveur SVN. Très pratique pour savoir qui taper en cas de problème.

Création du repos adminsvn

La première étape a été de créer un repository sur mon serveur qui allait me servir à ça. Pour cela, rien de plus simple, on crée un repository SVN :
$ svnadmin create /var/svn/adminsvn
On crée ensuite un trunk pour faire jolie ainsi qu'un sous-répertoire admin :
$ svn mkdir --parent file:///var/svn/adminsvn/trunk/admin -m "Création d'un trunk/admin"
Nous allons maintenant alimenter le fichier /etc/httpd/svn.d/droits-svn.conf afin de protéger le repository d'administration :
[groups]
admins_svn = yannig,cnorris

[/]
* = rw

[adminsvn:/]
# Personne ne peut lire le contenu de ce repository
* =
# Par contre, les admins SVN ont le droit de tout faire
@admins_svn = rw
Alimentons maintenant nos utilisateurs dans le fichier svn.passwd :
$ htpasswd -nb yannig mdpdeyannig > /etc/httpd/svn.d/svn.passwd
$ htpasswd -nb cnorris chucknorrisnapasbesoindemdp >> /etc/httpd/svn.d/svn.passwd
Ajoutons maintenant ces fichiers dans le repository avec la commande suivante :
$ svn add svn.passwd droits-svn.conf

Mise en place du mécanisme de post commit

Procédons maintenant à un checkout de ce repository SVN dans un coin de notre serveur (en tant qu'utilisateur apache ou www-data selon que vous soyez sous RH ou Debian like) :
$ svn co file:///var/svn/adminsvn/trunk/admin /etc/httpd/svn.d
Nous allons maintenant mettre en place un mécanisme de mise à jour de ce checkout. Rendez-vous dans le répertoire /var/svn/adminsvn/hooks et créons un fichier shell post-commit avec la commande suivante :
echo "svn up /etc/httpd/svn.d" > post-commit
chmod +x post-commit
Comme vous pouvez le voir, le script n'est pas super complexe.

Si vous n'avez pas utiliser le bon utilisateur pour faire le checkout, vous pouvez modifier les droits avec la commandes suivantes :
chown -R apache:apache /etc/httpd/svn.d

Déclaration d'un ensemble de repository dans apache

Déclarons maintenant la racine contenant le repository dans apache en créant le fichier /etc/httpd/conf.d/svn.conf avec le contenu suivant :
<Location /svn>
  DAV svn
  SVNParentPath /var/svn/
  SVNListParentPath On

  Options +Indexes
  AuthType Basic
  AuthName "SVN"

  # Gestion authentification
  AuthBasicProvider file
  AuthzSVNAccessFile /etc/httpd/svn.d/droits-svn.conf
  AuthUserFile /etc/httpd/svn.d/svn.passwd
  Require valid-user
</Location>
Un arrêt/relance de l'ami Apache et nous voilà prêt pour la suite.

NB : Il est bien sûr évidant que vous devez disposer de l'extension mod_dav_svn. Sous RHEL, vous devrez lancer la commande yum suivante pour procéder à l'installation :
yum install mod_dav_svn
Sous Debian, ce module s'appelle libapache2-svn. Vous devrez dans ce cas utiliser la commande suivante :
apt-get install libapache2-svn

Test de notre mécanisme

Cette partie est plus simple puisqu'elle va consister à faire des commits dans notre repository. Pour se faire, vous devez donc vous munir d'un client SVN. En tant que vieux barbu, je fais ça en ligne de commande depuis mon poste Linux :
svn co --username yannig http://monserveursvn/svn/adminsvn/trunk ~/adminsvn
Éditons maintenant votre fichier droits-svn.conf de la manière qu'il nous plaira et lançons le commit :
$ svn diff
Index: changelog.txt
===================================================================
--- droits-svn.conf       (revision 1)
+++ droits-svn.conf       (working copy)
@@ -1,3 +1,4 @@
-admins_svn = yannig,cnorris
+admins_svn = yannig,cnorris,nobody

[/]
* = rw

$ svn ci -m "Ajout de l'utilisateur nobody."
Sending        droits-svn.conf
Transmitting file data .
Committed revision 2.
Allons maintenant faire un tour sur notre serveur pour vérifier que le fichier droits-svn.conf a bien été mis à jour :
$ grep nobody /etc/httpd/svn.d/droits-svn.conf
admins_svn = yannig,cnorris,nobody
La modification a bien été prise en compte. Le mécanisme fonctionne bien comme prévu !

mercredi 13 mars 2013

Mécanisme de hook de SVN


Je sais, vous allez me dire que SVN est vieillot et que de toute façon, en bon geek qui se respecte, ça fait longtemps que vous êtes passé sous git.

Mais voilà, si vous n'êtes pas encore complètement convaincu que SVN n'est pas une solution si mauvaise que ça et que vous utilisez ça chez votre client/employeur, j'ai quelques astuces pour vous.

Tout d'abord, les hooks sont présent dans le répertoire hooks de votre repository. De base, votre repository SVN, à sa création, vient avec un template pour toutes les opérations de hooks possible sous SVN. Ça se présente sous la forme suivante :


ls *.tmpl
post-commit.tmpl
post-unlock.tmpl
pre-revprop-change.tmpl
post-lock.tmpl
pre-commit.tmpl
pre-unlock.tmpl
post-revprop-change.tmpl
pre-lock.tmpl
start-commit.tmpl

Comme vous pouvez le constater, toutes les opérations possible et imaginable sont disponible. Personnellement, j'ai eu l'occasion d'en mettre deux en oeuvre :

  • pre-revprop-change : lancé avant une modification sur une révision ;
  • post-commit : lancé au moment de la fin d'un commit.


Ces hooks vont servir à changer/régler le comportement de votre repository à l'aide de script. Pour les mettre en place, rien de plus simple :

  • Faîtes un script dans le langage qui vous amuse (même si j'aurais tendance à privilégier un script shell Unix tout simple) ;
  • Copier/lier ce script dans le répertoire du hooks en respectant le nom de l'opération à laquelle vous voulez le lier.

Exemple de hooks SVN : pre-revprop-change


Prenons le cas du pre-revprop-change. Ce script est lancé pour vérifier que l'opération de modification d'une révision de votre repository est bien autorisé. Je sais, vous aller me dire que ce type de demande vous parez étrange. Mais comme chacun sait, le client est roi et à coeur vaillant, rien d'impossible !

Dans le cas présent, nous allons justement restreindre cette opération à la modification du message de log de votre révision. Nous allons également interdire que cette modification puisse se faire par un autre utilisateur que celui à l'origine de la modification.

Sans plus attendre, voici donc le fameux script en charge de cette modification :

#!/bin/bash
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
ACTION="$5"

if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ] && \
   [ `svnlook author -r "$REV" "$REPOS"` = "$USER" ]; then
  exit 0
fi

echo "Changing revision properties other than svn:log is prohibited" >&2
exit 1

Le principe est simple :
  • On vérifie bien que nous n'allons modifier que le message de la révision (PROPNAME=svn:log) ;
  • L'action est une modification (ACTION=M) ;
  • Enfin, l'auteur de la modification est bien celui à l'origine du commit (svnlook author ... = $USER).
De là, si ces conditions sont remplies, on renvoie un exit 0 et SVN considère que l'opération est valide.

Dans les autres cas, nous renvoyons exit 1 et SVN refusera de lancer la modification.

Couplage avec Jenkins à l'aide d'un événement de post-commit

Prenons maintenant un autre cas : vous voulez coupler votre repository SVN avec un moteur d'intégration continue (type Jenkins) afin de lancer automatiquement vos constructions sans pour autant avoir à poller régulièrement votre repository SVN tout le temps. Ici, l'utilisation d'un évènement de post-commit fera parfaitement l'affaire et pourra lancer automatiquement votre job de construction.

Pour se faire, nous allons créer le script suivant que nous lierons ensuite dans le répertoire hooks avec comme nom post-commit (bien s'assurer également qu'il est exécutable) :

#!/bin/bash
log="/tmp/post_commit.log"
url_jenkins="http://127.0.0.1:8080/job/makeApp-generic/buildWithParameters?token=makeApp"

REPOS="$1"
TRANS="$2"

exec  > $log
exec 2> $log

repository=$(basename $REPOS)

# Définition des paths des différents binaires
for tag in $(svnlook changed -r $TRANS $REPOS | \
             sed 's/tags\//' | awk '{ print $2 }' | \
             sed 's/\/.*//g' | sort -u)
do
  if [ $tag = "trunk" ]; then tag=HEAD ; fi
  echo "Lancement de la construction de '$repository' (tag='$tag')."
  curl "$url_jenkins&application=$repository&tag=$tag" 2> /dev/null
done
NB : Il va sans dire qu'il faudra que votre serveur Jenkins soit en mesure d'accepter le job qui s'appelle makeApp-generic et surtout que vous ayez créé un token d'appel associé pour pouvoir le lancer avec un curl. Tient, je sens que je vais faire un article sur Jenkins dans peu de temps :).

En gros, le script va simplement regarder les répertoires des fichiers qui vont être modifié et, en fonction de ça, lancer une construction (avec les appels curl) auprès de Jenkins. Dans notre exemple, si la modification se fait sur le trunk, le tag est changé en HEAD.

Il ne nous reste plus maintenant qu'à faire une modification dans notre repository et vérifier que le build s'est bien passé en consultat la log /tmp/post_commit.log :

cat /tmp/post_commit.log
Lancement de la construction de 'test' (tag='HEAD').

Voilà, ça sera à peu près tout pour aujourd'hui. A bientôt pour de nouvelle aventure !