Bei der Migration von Subversion auf einen neuen und aktuelleren Server steht irgendwann auch die Migration der Repositories an. Je nach Umfang und Anzahl kann das einige Zeit und Handarbeit in Anspruch nehmen.
Um den Ablauf zu vereinfachen und zu automatisieren, kann man folgendermaßen vorgehen:
Migration der Dumps
Die Repositories können als Dump abgespeichert werden und dienen als Container, um sie auf dem neuen System wieder einspielen zu können. Ich gehe jetzt hier davon aus, dass die Dumps regelmäßig auf dem Produktivserver erstellt werden und sich immer am gleichen Platz befinden.
Hier liegen die Dumps unter /data/backups/svn liegen. In meinem Fall mit Datumsangaben und “_dump_” Bezeichnung im Namen:
Die Struktur des neues Subversion Systems ist die selbe. Die Pfade unterscheiden sich also nicht.
Um die Dumps vom alten System auf das neue zu migrieren, wird folgendes Rsync-Kommando als Cronjob abgesetzt.
rm /data/backups/copy-from-svn.log && sshpass -p "***" rsync -ru --delete-after --progress root@subversion-server:/data/backups/svn /data/backups >> /data/backups/copy-from-svn.log 2>&1
Hierbei wird zunächst das Log des letztes Kopiervorgangs entfernt und sich dann via SSH auf dem alten System angemeldet. Mittels sshpass werden die notwendigen Anmeldedaten mitgegeben. Es wird der Ordner “/data/backups/svn” vom alten System nach “/data/backups” auf das neue System kopiert. Ebenfalls werden alte Dumps, die in der Quelle nicht mehr vorhanden sind, auf dem Zielsystem entfernt
Die Resultate werden nach “/data/backups/copy-from-svn.log” geschrieben:
[...] 1,767,145,472 99% 30.51MB/s 0:00:00 1,767,177,519 100% 17.95MB/s 0:01:33 (xfr#4, to-chk=47/133) svn/XXX_dump_20170220_221113_164.svn 0 0% 0.00kB/s 0:00:00 16,252,928 12% 11.18MB/s 0:00:10 31,162,368 23% 12.36MB/s 0:00:08 34,308,096 25% 9.59MB/s 0:00:09 44,269,568 33% 9.53MB/s 0:00:09 51,085,312 38% 7.96MB/s 0:00:09 58,490,880 44% 6.28MB/s 0:00:11 62,095,360 46% 6.17MB/s 0:00:11 63,143,936 47% 4.20MB/s 0:00:16 64,192,512 48% 2.81MB/s 0:00:23 64,978,944 49% 1.29MB/s 0:00:50 66,289,664 50% 839.52kB/s 0:01:18 68,648,960 51% 1.07MB/s 0:00:58 108,888,064 82% 9.26MB/s 0:00:02 132,429,452 100% 8.32MB/s 0:00:15 (xfr#5, to-chk=6/133) 0 files... 100 files... deleting svn/XXX_dump_20170217_202748_150.svn deleting svn/CCC_dump_20170112_204550_269.svn deleting svn/AAA_dump_20170216_202115_2703.svn deleting svn/BBB_dump_20170219_200018_4552.svn deleting svn/VVV_dump_20170125_200906_990.svn
Nachdem der neue Server damit auf dem neusten Stand ist, kann das Import Skript ausgeführt werden.
Import der Dumps
cd /tmp
nano restore-all-dumps.sh (Inhalte rein und speichern)
chmod +x restore-all-dumps.sh
Inhalt des Skripts:
#!/bin/bash rm /tmp/dumps find "/data/backups/svn" -type f | sort >> "/tmp/dumps" COUNT=1 SVNROOT="/data/srv/svn-parent" sed -i -e '1d' "/tmp/dumps" # Wegschneiden der ersten Zeile NUMBEROFDUMPS=$(cat /tmp/dumps | wc -l) while read p; do #String ohne _dump... NEW=$(echo $p | sed s/"_dump.*"/""/) #anfang pfad abschneiden REPO=${NEW:18} echo "### $COUNT von $NUMBEROFDUMPS###" #kompletter Pfad echo "Backupfile: $p" #Pfad ohne das Ende _dump... #echo $NEW #Pfad vorne abgeschnitten, also nur Name des Repos echo "Repository: $REPO" echo "Pruefe aktuelles Repository gegen den letzten Copy Job" for fn in `cat /data/backups/copy-from-svn.log | grep "svn/" | grep -v "deleting"`; do if [[ $fn == *"svn/$REPO"* ]]; then echo "* Aktuelles Repository in der Liste gefunden!" echo "* String im Log: $fn" echo "* Passendes Repository: $REPO" echo "* Repository muss neu erstellt werden, loesche die alte Version" rm -R $SVNROOT/$REPO if [ ! -d "$SVNROOT/$REPO" ]; then echo "* Alte Version geloescht" fi fi done if [ -d "$SVNROOT/$REPO" ]; then echo "Der Pfad zum aktuellen Repository besteht. Es gibt keine neuere Version." fi #Wenn Pfad vom Repo nicht vorhanden, dann direkt erstellen if [ ! -d "$SVNROOT/$REPO" ]; then echo "Repository noch nicht vorhanden, starte Import" svnadmin create $SVNROOT/$REPO chown www-data:www-data -R $SVNROOT/$REPO gunzip -c $p | svnadmin load $SVNROOT/$REPO > restore_log.log cp $SVNROOT/pre-commit_ $SVNROOT/$REPO/hooks/pre-commit chmod +x $SVNROOT/$REPO/hooks/pre-commit chown www-data:www-data -R $SVNROOT/$REPO fi ((COUNT++)) done < /tmp/dumps echo "Durchlauf abgeschlossen"
Was passiert hier?
- Zeile 2-3: Die alte Datei, die die Auflistung der Dumps enthält wird gelöscht und anschließend wird sie neu erstellt (Liste aller Dateien, die im Verzeichnis gefunden wurden)
- Zeile 6: Die erste Zeile der Datei wird entfernt, da dort das Verzeichnis an sich aufgeführt wird, was allerdings kein Repository wiederspiegelt.
- Zeile 8-53: Loop über die erstellte Datei
- Zeile 9-19: Bearbeiten der Zeilenrückgaben, die den Pfad und Namen des Dumps beinhalten, sodass am Ende nur der Name des Repositories erreicht wird
- Zeile 21-34: Das aktuelle Repository $REPO wird mit den Inhalten des RSYNC Logs abgeglichen, wenn ein Repository vorhanden ist, welches allerdings einen neuen Dump besitzt, wird es gelöscht.
- Zeile 40-50: Wenn das Verzeichnis des aktuellen Repositories nicht vorhanden ist, wird der Dump importiert.
So werden bestehende Repositories übersprungen, neue angelegt und aktualisierte Dumps, die auf dem alten Server in neuer Version vorliegen und kopiert wurden, neu angelegt, damit der Stand nach dem Durchlauf auf beiden Systemen gleich ist.
Seit den neusten SVN Versionen muss der Apache Dienst nach einem Dump-Import neu gestartet werden, da es sonst zu diversen Fehlern im Repository kommt.
Diese könnten sein:
- Corrupt node-revision
- Corrupt representation
- svnadmin: E160004: r1516’s root node’s predecessor is r1514 but should be r1515
- filesystem corrupt
- …
service apache2 restart
Nach dem Ausführen des Skripts sieht es in etwa so aus:
bzw.