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: 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: Das erste eigene Modul mit einer MOTD

Nachdem die puppet Infrastruktur steht moechte ich nun auf alle Server eine eigene, individuelle MOTD nach dem Ubuntu Vorbild verteilen. Damit alles funktioniert muessen verschiedene Bedingungen erfuellt sein:

  1. Auf allen Systemen muss /etc/motd ein Symlink nach /var/run/motd sein
  2. Auf allen Systemen muss das Verzeichnis /etc/update-motd.d/ existieren
  3. Auf allen Systemen muessen die Skripte von Nick Charlton im /etc/update-motd.d/ Verzeichnis existieren
  4. Auf allen Systemen muss das Paket ‚figlet‘ installiert sein.

Die perfekte Ausgangslage um ein eigenes Modul fuer puppet zu schreiben, dass automatisch alle Bedingungen sicherstellt. #

Ich habe unter /etc/puppet/modules/ die folgende Verzeichnisstruktur erzeugt:

└── motd
    ├── files
    │   └── etc
    │       └── update-motd.d
    │           ├── 00-header
    │           ├── 10-sysinfo
    │           └── 99-footer
    └── manifests
        └── init.pp

Die Skripte im Unterverzeichnis files habe ich von der Seite Debian/Ubuntu: Dynamic MOTD. Im Verzeichnis manifests ist eine init.pp abgelegt. Diese hat den folgenden Inhalt:

class motd {
 
  package { 'figlet':
    ensure => 'installed'
  }
 
 
 
  file { '/etc/motd':
    ensure => 'link',
    target => '/var/run/motd',
  }
 
 
 
  file { '/etc/update-motd.d/':
    ensure => 'directory',
    owner  => 'root',
    group  => 'root',
    mode   => '0755'
  }
 
 
 
  file { '/etc/update-motd.d/00-header':
    ensure => 'present',
    source => 'puppet:///modules/motd/etc/update-motd.d/00-header',
    owner  => 'root',
    group  => 'root',
    mode   => '0755'
  }
 
  file { '/etc/update-motd.d/10-sysinfo':
    ensure => 'present',
    source => 'puppet:///modules/motd/etc/update-motd.d/10-sysinfo',
    owner  => 'root',
    group  => 'root',
    mode   => '0755'
  }
 
  file { '/etc/update-motd.d/99-footer':
    ensure => 'present',
    source => 'puppet:///modules/motd/etc/update-motd.d/99-footer',
    owner  => 'root',
    group  => 'root',
    mode   => '0755'
  }
}

Ich denke sie ist relativ selbsterklaerend. Als erstes wird sichergestellt, dass das Paket figlet installiert ist. Danach wird der symbolische Link erzeugt falls er nicht existiert. Als drittes validiert, dass das Verzeichnis /etc/update-motd.d/ existiert und danach die Skripte an die richtige Stelle kopiert.

Damit dieses Modul auch an alle puppet nodes verteilt wird, habe ich einen default node definiert. Dieser greift immer dann, wenn ein node nicht explizit aufgelistet wurde. Dafuer wurde die Datei /etc/puppet/manifests/site.pp mit dem folgenden Inhalt angelegt:

node default {
  class { 'motd': }
}

Nach dem manuellen Aufruf des puppet agents auf dem node wird die Konfiguration uebernommen:

user@host:~# puppet agent --server puppetmaster.example.org --test
info: Caching catalog for host.example.org
info: Applying configuration version '1398539626'
info: FileBucket adding {md5}d41d8cd98f00b204e9800998ecf8427e
info: /Stage[main]/Motd/File[/etc/motd]: Filebucketed /etc/motd to puppet with sum d41d8cd98f00b204e9800998ecf8427e
notice: /Stage[main]/Motd/File[/etc/motd]/ensure: ensure changed 'file' to 'link'
notice: /Stage[main]/Motd/File[/etc/update-motd.d/]/ensure: created
notice: /Stage[main]/Motd/File[/etc/update-motd.d/10-sysinfo]/ensure: defined content as '{md5}684e660175b367c21bbf0bf5b4cb2475'
notice: /Stage[main]/Motd/File[/etc/update-motd.d/00-header]/ensure: defined content as '{md5}13ab41fc9d68d2e2b05c31185aecfab5'
notice: /Stage[main]/Motd/File[/etc/update-motd.d/99-footer]/ensure: defined content as '{md5}8609d989ae2538fbb15f9055c995d050'
notice: Finished catalog run in 1.16 seconds
user@host:~#

Anschliessend ist die MOTD zu sehen wenn ich mich mit dem Server verbinde:

Bildschirmfoto vom 2014-04-26 21:17:22