Puppet: Style pruefen mit puppet-lint als pre-commit hook

Ich hatte bereits puppet-lint in einem eigenen Blogeintrag vorgestellt. Noch schoener als das manuelle Aufrufen ist natuerlich das ganze als pre-commit Hook zu haben und gar nichts ins Repository rein zu lassen, was nicht den eigenen Regeln entspricht.

Folgendes ist mein pre-commit Hook:

#!/bin/bash
 
echo "Checking syntax with puppet-lint"
 
for i in $(git diff --name-only --cached | grep -E '.(pp)'); do
        if [ -f "${i}" ]; then
                # --no-80chars-check because of sshkey.pub and
                # https://github.com/rodjek/puppet-lint/issues/70
 
                puppet-lint --no-80chars-check --no-single_quote_string_with_variables-check --with-filename ${i}
 
                if [ $? -ne 0 ]; then
                        echo "ERROR: Bad syntax, see errors above. Aborting!"
                        exit 1
                else
                        echo "Nice work in: ${i} :-)"
                fi
        fi
done

Puppet: Manifest Dokumentation mit puppet doc / post-commit Hook

Wie ueberall im Leben bietet es sich auch an puppet Manifest Dateien zu dokumentieren. Die Dokumentation dort basiert auf rdoc. Die Syntax wird in der Puppet Manifest Documentation Wiki Seite unten ganz gut beschrieben. Hier ein paar Beispiele:

  1. Eine Testklasse mit Dokumentation davor. Wichtig ist, dass zwischen Ende der Dokumentation und Definition der Klasse KEINE Leerzeile ist, sondern die Kommentare bis direkt an die class test() {} Zeile gehen:
    Bildschirmfoto vom 2014-05-18 20:02:08
  2. Die einfachste Art- und Weise die Dokumentation zu lesen ist, diese auf der Kommandozeile auszugeben. Das tut man mit dem folgenden Befehl:
    puppet doc /path/to/manifest.pp

    Bildschirmfoto vom 2014-05-18 20:01:17

  3. Schoener zu lesen ist das ganze als HTML Seite. Ich persoenlich habe in dem GIT Repository in dem ich die Puppet Konfiguration verwalte einen post-commit Hook, der mir die Dokumentation erzeugt und in einem Verzeichnis ablegt, das mit Apache freigegeben ist. Der Aufruf dafuer ist in der post-commit Datei:
    puppet doc --all --mode rdoc --outputdir /var/www/example.org/puppetdocs/

    Und es sieht dann am Ende wie folgt aus:
    Bildschirmfoto vom 2014-05-18 20:02:44

    Wenn im Modul root Verzeichnis eine Datei README liegt, wird diese als Gesamtdokumentation fuer das Modul mit hinzugenommen.

Puppet: Pruefung auf Syntaxfehler von .pp und .erb Dateien

In dem Blogeintrag Konfiguration in GIT Repository verwalten / push-to-deploy habe ich den update Hook verlinkt, der eine Syntaxpruefung von .pp Dateien macht. Diesen habe ich heute morgen noch erweitert, so das auch die Templates mit der Endung .erb ueberprueft werden.

Wer die beiden Kommandos manuell ausfuehren moechte, sie sind wie folgt:

  1. Pruefen der Syntax von .pp Dateien:
    puppet parser validate /path/to/file.pp

    Im Fehlerfall gibt es eine Ausgabe wie zum Beispiel:

    Error: Could not parse for environment production: Syntax error at 'jails' at /home/user/git/puppet/modules/fail2ban/manifests/init.pp:13
  2. Pruefen der Syntax von .erb Template Dateien:
    erb -x -T '-' /path/to/file.erb  | ruby -c

    Im Fehlerfall gibt es eine Ausgabe wie zum Beispuel:

    -:44: syntax error, unexpected ')', expecting $end
    ...:jails').include? "ssh" ).to_s); _erbout.concat "n"
    ...

Wie bereits frueher geschrieben, richtig praktisch ist das ganze als update Hook im Git Repository. Die Fehler werden zwar trotzdem nicht zu 100% korrekt abgefangen, dafuer muss man noch Tests ausfuehren (dazu spaeter mehr), aber fuers Erste fangen die beiden Pruefungen schon eine Menge ab.

Bildschirmfoto vom 2014-05-07 07:26:27

Puppet: Konfiguration in GIT Repository verwalten / push-to-deploy

Es ergibt Sinn die puppet Konfiguration in einem GIT Repository zu verwalten. So kann man immer auf alte Versionen zurueckgehen sowie automatische Pruefungen zwischenschalten bevor man Aenderungen Live schaltet. Sexy wird das ganze mit push-to-deploy. So wird es gemacht:

Vorbereitungen auf dem puppet server

mkdir -p /srv/git/puppet
cd /srv/git/puppet
git init --bare
addgroup puppet-push
chgrp -R puppet-push /srv/git/puppet
find /srv/git/puppet -type d -exec chmod 0775 {} ;
find /srv/git/puppet -type d -exec chmod +s {} ;
chgrp -R puppet-push /etc/puppet
chmod 775 /etc/puppet

Damit mein Benutzername auch in das GIT Repository schreiben darf muss dieser Mitglied in der Gruppe puppet-push sein:

adduser USERNAME puppet-push

Nun benoetigen wir zwei Hooks in dem Repository. Einen update Hook der die Syntax ueberprueft, und ein post-receive Hook, der bei Bedarf die gepushten Dateien gleich an die richtige Stelle kopiert:

cd /srv/git/puppet/hooks/
wget http://git.pregos.info/scripts.git/blob_plain/HEAD:/push-to-deploy/update
chmod +x update
http://git.pregos.info/scripts.git/blob_plain/HEAD:/push-to-deploy/post-receive
chmod +x post-receive

Anschliessend sind auf Server Seite keine weiteren Aenderungen mehr notwendig.

Vorbereitungen auf dem lokalen Rechner

Bei sich lokal auf dem Rechner muss man nun ein Verzeichnis erzeugen, die aktuellen Dateien vom puppetmaster.example.org:/etc/puppet dorthin kopieren, GIT Repository initialisieren und committen:

mkdir ~/puppet
cd ~/puppet
scp user@puppetmaster.example.org:/etc/puppet .
git init
git add .
git commit -m "initial commit"

Nun noch das remote Repository hinzufuegen und pushen:

git remote add live user@puppetmaster.example.org:/srv/git/puppet
git push live master

Wenn alles richtig ist, dann ist die Ausgabe in etwa wie folgt:

user@client:~/git/puppet$ git push live master
Counting objects: 22, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (16/16), done.
Writing objects: 100% (22/22), 4.91 KiB | 0 bytes/s, done.
Total 22 (delta 2), reused 0 (delta 0)
remote: fatal: bad object 0000000000000000000000000000000000000000
remote: 
remote: diff-tree:
remote: Already on 'master'
remote: DEPLOY: master(bd01768f198a2513ba82f5f8765b4b222908ce4b) copied to '/etc/puppet'
To user@puppetmaster.example.org:/srv/git/puppet
 * [new branch]      master -> master

Syntaxfehler fuehren dazu, dass die Aenderungen nicht uebernommen werden:

user@client:~/git/puppet$ git push live master
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 328 bytes | 0 bytes/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: 
remote: diff-tree:
remote: :100644 100644 c31414e094fbbf3af3792965f2f706ede6a70d24 f47cd2be9c7b3a9d4e23b885b2252ac0579319d2 M	manifests/site.pp
remote: 
remote: err: Could not parse for environment production: Syntax error at end of file; expected '}' at manifests/site.pp:6
remote: err: Try 'puppet help parser validate' for usage
remote: For more details run this:  git diff c31414e094fbbf3af3792965f2f706ede6a70d24 f47cd2be9c7b3a9d4e23b885b2252ac0579319d2 
remote: 
remote: error: hook declined to update refs/heads/master
To user@puppetmaster.example.org:/srv/git/puppet
 ! [remote rejected] master -> master (hook declined)
error: Fehler beim Versenden einiger Referenzen nach 'user@puppetmaster.example.org:/srv/git/puppet'

Die Informationen sind zusammengetragen von: