Puppet: Hiera und Puppet – Installation, Einrichten, Moduleinbindung

Hiera ist eine key-/value Datenbank von Konfigurationsdaten fuer Puppet. Als ersten Schritt moechte ich aufzeigen wie man es installiert, minimal einrichtet und testweise in ein Modul einbindet.

Zuerst muss auf dem Puppetmaster Server (ich arbeite unter Debian Wheezy) das folgende Paket inklusive seiner Abhaengigkeiten installiert werden:

aptitude install ruby-hiera-puppet

Nach der Installation muss eine Konfigurationsdatei fuer Hiera unter Puppet erzeugt werden. Die Datei ist per Definition die /etc/puppet/hiera..yaml. Sie hat folgenden Inhalt:

---
:backends:
    - yaml

:hierarchy:
    - common

:yaml:
    :datadir: '/etc/puppet/hieradata'

Erklaerung der hier gemachten Einstellungen:

  • : Definiert den Beginn der Datei
  • :backends: Gibt das Format an in dem die die Daten vorliegen. In diesem Fall ist YAML definiert.
  • :hierarchy: Definiert die Hierarchie der Datenquellen. In diesem Fall gibt es nur eine moegliche Datenquelle ‚common‘
  • :yaml::datadir:Definiert fuer das YAML Backend das Verzeichnis in dem die Daten gespeichert sind. In diesem Fall das Verzeichnis /etc/puppet/hieradata

Sicherstellen das das gerade angesprochene Verzeichnis existiert:

mkdir -p /etc/puppet/hieradata

Anschliessend die folgende Datei common.yaml in dem Verzeichnis anlegen:

---
testmessage: hallo welt

Testen ob alles funktioniert kann man das ganze danach mit dem folgenden Aufruf:

hiera -c /etc/puppet/hiera.yaml testmessage

Zum Schluss noch ein Beispiel wie man den Wert nun in Puppet in einer Klasse ausliesst und in einer Datei speichert:

class hieratest {
    $testmessage = hiera("testmessage")
    file { '/tmp/hieratest.txt':
        content => inline_template("<%= testmessage %>n"),
    }
}

Wenn man daraus zum Beispiel ein Modul ‚hieratest‘ macht, auf einem Node einbindet und Puppet laufen laesst, dann findet man dort die Datei /tmp/hieratest.txt mit dem definierten Inhalt ‚hallo welt‘.

Puppet: Informationen des Nodes mit facter auslesen

In heterogenen Setups ist es wichtig das sich die Module und Klassen den nodespezifischen Eigenheiten anpassen. Dafuer koennen in Puppet Informationen aus facter verwendet werden.

Facter is an independent, cross-platform Ruby library designed to gather information on all the nodes you will be managing with Puppet. It is available on all platforms that Puppet is available.

Facter ist auch ein eigenstaendiges Tool. Nach dem Aufruf werden die zur Verfuegung stehenden Informationen ausgegeben.

Ein Anwendungsbeispiel ist mit einem Modul sicherzustellen, dass SSH installiert und der SSH Serverdienst auch laeuft. Auf Debian basierten Systemen heisst der Dienst ’ssh‘, waerend auf RedHat basierten Systemen der Dienst ’sshd‘ heisst. In einem Puppet Modul laesst sich das mit Informationen aus facter wie folgt abbilden:

class ssh_server {
  case $::osfamily {
    Debian: {
      $serviceName = 'ssh'
    }
    RedHat: {
      $serviceName = 'sshd'
    }
  }
 
  service { $serviceName:
    ensure => 'running',
  }

Aber nicht nur in den manifest Dateien kann man auf die Informationen aus facter zurueckgreifen, auch in den Templates stehen diese zur Verfuegung. Eine sinnvolle Modifikation des Templates jail.local.erb das ich in dem fail2ban Modul gezeigt habe ist, die Emails nicht an fail2ban@localhost sondern an fail2ban@FQDN zu verschicken. Dafuer muss die folgende Zeile geaendert werden:

  • alt:
    destemail = fail2ban@localhost
  • neu:
    destemail = fail2ban@<%= fqdn %>

Puppet: Konfigurationsdateien manipulieren mit Augeas

Ich stand vor der Frage, wie ich auf allen puppet Nodes die /etc/puppet/puppet.conf editiere. Dabei sollten zwei Eintraege sichergestellt sein:

  1. In der [main] Sektion soll pluginsync=true stehen
  2. In der [agent] Sektion soll report=true stehen

Kurz habe ich ueberlegt ob ich die Datei selbst ueber puppet verteilen soll. Dann wurde ich aber auf Augeas gestossen. Augeas ist ein Tool, das ueber sogenannte Linsen (lenses) verschiedene Konfigurationsdateien in einer baum-Struktur darstellen und bearbeiten kann. Puppet hat Augeas ueber die Ruby Language Bindings bereits integriert. Es ist also problemlos moeglich damit die puppet.conf zu editieren. Hier meine Loesung aus der Klasse:

  augeas { 'puppet.conf':
    context => '/files/etc/puppet/puppet.conf',
    changes => [
      'set main/pluginsync true',
      'set agent/report true',
    ],
    notify  => Service['puppet'],
  }
 
  service { 'puppet':
    ensure  => 'running',
  }

und so sieht es aus wenn es denn durchlaeuft:

notice: Augeas[puppet.conf](provider=augeas): 
--- /etc/puppet/puppet.conf	2014-05-23 20:30:48.000000000 +0200
+++ /etc/puppet/puppet.conf.augnew	2014-05-23 20:30:54.000000000 +0200
@@ -8,9 +8,12 @@
 prerun_command=/etc/puppet/etckeeper-commit-pre
 postrun_command=/etc/puppet/etckeeper-commit-post
 
+pluginsync=true
 [master]
 # These are needed when the puppetmaster is run by passenger
 # and can safely be removed if webrick is used.
 ssl_client_header = SSL_CLIENT_S_DN 
 ssl_client_verify_header = SSL_CLIENT_VERIFY
 
+[agent]
+report=true
 
notice: /Stage[main]/Basics/Augeas[puppet.conf]/returns: executed successfully
info: /Stage[main]/Basics/Augeas[puppet.conf]: Scheduling refresh of Service[puppet]
notice: /Stage[main]/Basics/Service[puppet]: Triggered 'refresh' from 1 events

Weitere Moeglichkeiten wie immer in der entsprechenden Puppet Type Reference.

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