Munki mit Git

Ich setze für meine Softwareverteilung auf Macs Munki ein. Das ist eine Software, die serverseitig nur einen Webserver und ein paar XML-Dateien benötigt. Der Client fragt dann regelmäßig am Server an und erhält so Updates. Die Funktion und Einrichtung von Munki ist aber im offiziellen Wiki viel besser dokumentiert.

In diesem Beitrag soll es um die Versionierung des Munki-Repositories mit Git und anschließender Veröffentlichung auf einem Server gehen.

Ich habe einen Webserver lokal auf meinem iMac laufen. Hier werden neue Pakete in Munki importiert, Software getestet und die ganze Verteilung geprüft. Ein weiterer Webserver läuft im Internet, der das gleiche Munki-Repo anbietet, sodass alle meine (und befreundete) Macs den Update-Server erreichen und Software installieren können.

Ich gehe davon aus, dass deine Munki-Installation funktioniert und so oder so ähnlich wie im Demonstration Setup konfiguriert ist.

Munki-Repository mit Git versionieren

Um nun das Repo zu versionieren, muss zuerst ein Git-Repository erstellt werden. Dazu wechselt du im Terminal in dein Munki-Repo und gibst folgenden Befehl ein:

$ git init

Danach müssen noch sämtliche Dateien eingecheckt werden, die versioniert werden sollen. Da das mit Binärdaten aber eher nicht so toll funktioniert, ignoriere ich den Ordner pkgs per .gitignore im Hauptverzeichnis meines Git-Repos.

$ cat .gitignore
/pkgs/
.DS_Store
$ git add .
$ git commit -m "First commit"

So sind alle Dateien – außer die Installer-Dateien –  eingecheckt und somit versioniert. Wenn ich nun ein Softwarepaket verändere (im Beispiel den Katalog von testing auf production ändere), dann kann ich dies also in Zukunft nachvollziehen und im Zweifel rückgängig machen.

Bildschirmfoto 2015-09-04 um 14.32.01

Remote-Repository einrichten

Nun möchte ich dieses lokal konfigurierte und getestete Repository auf meinem Server im Internet bereitstellen. Dies ist relativ einfach mittels Remote-Repository zu erreichen.

Hierzu muss auf dem Webserver ein Git-Server laufen und ein Headles-Repository eingerichtet sein. Wie ein Git-Server installiert und eingerichtet wird, erfährst du an anderer Stelle.

$ mkdir munki-test.git
$ cd munki-test.git
$ git --bare init

Danach wird das Remote-Repository dem lokalen Git-Repository hinzugefügt.

Bildschirmfoto 2015-09-04 um 14.48.07

Und nun kann das lokale Branch an den Remote-Server gepusht werden.

Bildschirmfoto 2015-09-04 um 23.48.34

Die Eigenheit von einem Bare-Repository ist, dass es nur die Git-Metadaten vorhält und nicht einen Branch auscheckt. Somit liegt das Munki-Repository nicht im direkten Zugriff auf dem Server. Das Git-Repo muss nach dem Push noch in Richtung Webserver ausgecheckt werden.

git --work-tree=/var/www/munki_repo --git-dir=/home/git/munki-test.git checkout -f

Da dieser Befehl nach jedem Push (also Upload zum Server) passieren muss, kann man es über die sog. Git Hooks lösen. In dem Git-Ordner auf dem Server sollte eigentlich schon ein Unterordner namens hooks mit ein paar Beispiel-Dateien liegen. Hier wird eine neue Datei namens post-receive angelegt, die in etwa so aussehen kann:

#!/bin/sh
git --work-tree=/var/www/munki_repo --git-dir=/home/git/munki-test.git checkout -f

Eingangs hatte ich geschrieben, dass ich die Binaries nicht mittracke. Wenn ich das nicht tue, werden sie natürlich auch nicht mit hochgeladen und auf dem Webserver bereitgestellt. Dies mache ich separat mit einem rsync. Und damit es auch automatisch läuft, nutze ich in meinem lokalen Repository den pre-push-hook.

$ cat pre-push
#!/bin/sh

remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000

IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
    if [ "$local_sha" = $z40 ]
    then
        # Handle delete
        :
    else
        if [ "$remote_sha" = $z40 ]
        then
            # New branch, examine all commits
            range="$local_sha"
        else
            # Update to existing branch, examine new commits
            range="$remote_sha..$local_sha"
        fi

        ### do the rsync
        rsync -hrLvzp --size-only --ignore-errors --stats --timeout=60 --delete-after --progress --exclude-from="/Users/admin/munki/syncfolders.exclude" /Users/admin/munki/munki_repo/pkgs/ username@server:/var/www/munki_repo/pkgs
        if [ $? != 0 ]; then
            echo "rsync error"
            exit 1
        fi
        ssh username@server "chown -R www-data:www-data /var/www/munki_repo/pkgs"

        # Check for WIP commit
        commit=`git rev-list -n 1 --grep '^WIP' "$range"`
        if [ -n "$commit" ]
        then
            echo "Found WIP commit in $local_ref, not pushing"
            exit 1
        fi
    fi
done

exit 0

Nun wird also der Ordner pkgs per rsync zum Server synchronisiert, das Git-Repo zum Server gepusht und serverseitig das Git-Repo in den www-Ordner ausgecheckt.

Dieses ganze Szenario habe ich bisher nur in eine Richtung getestet. Also von meinem Client zum Server. Git ist ja für die verteilte Versionskontrolle bekannt. Besonders das rsync-Script ist aktuell nicht darauf ausgelegt, mehrere Quellen (also 2-3 Rechner von Munki-Admins, die Updates bereitstellen) zu bedienen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.