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

Puppet: Aufsetzen der Infrastruktur

Durch die Arbeit inspiriert, habe ich nun auch fuer mich Privat einen puppet Server zur Verwaltung meiner virtuellen Maschinen aufgesetzt.

Wikipedia schreibt zu puppet:

Puppet ist ein Tool zum Konfigurationsmanagement von Computern mit Betriebssystemen 
wie Unix, Linux und FreeBSD. Ein IT-Administrator kann damit an zentraler Stelle 
die Konfiguration von Rechnern in seinem Netzwerk verwalten. Puppet eignet sich 
sowohl für einzelne Rechner als auch für große Rechnerverbünde

Als erstes wurde die generelle Infrastruktur aufsetzen. Das bedeutet fuer mich:

  1. Einen puppet master Server zu haben
  2. Auf den Clients einen puppet agent laufen zu haben der mit dem Master verbunden ist.

Alles hier beschriebene passiert auf der Basis von Debian wheezy. Auf dem Server der als puppet master dienen soll habe ich zuerst das entsprechende Paket mit seinen Abhaengigkeiten installiert:

sudo aptitude install puppetmaster

Anschliessend habe ich in der /etc/default/puppetmaster den Parameter START=yes gesetzt. Wichtig ist nun noch sicherzustellen, dass der Port 8140 von den Clients aus erreichbar ist.

Danach habe ich auf den Clients den puppet agent installiert:

sudo aptitude install puppet

Auch hier habe ich in der /etc/default/puppet wieder den Parameter START=yes gesetzt. Weiter habe ich in den DAEMON_OPTS den Parameter zu dem Server angegeben. Beispiel:

--server puppetmaster.example.org

Dann habe ich probiert mich mit dem puppet agent an den puppet master Server zu verbinden:

puppet agent --server puppetmaster.example.org --test

Auf dem puppet master konnte ich danach das unsignierte Zertifikat des Clients mit dem folgenden Befehl sehen:

puppet cert list

Danach musste es mit dem folgenden Befehl signiert werden, wobei puppetclient.example.org der FQHN des puppet clients ist:

puppet cert sign puppetclient.example.org

Alle signierten Zertifikate kann man sich uebrigens mit dem folgenden Befehl anzeigen lassen:

puppet cert list --all

Danach konnte ich den puppet agent auf dem Client erneut laufen lassen und die Verbindung war erfolgreich. Zum Ende das neu starten des puppet agents auf den Clients nicht vergessen, damit der Prozess mit den neuen DAEMON_OPTS laeuft.

Notizen:

  • Wenn es zu einer „Connection refused“ Fehlermeldung wie unten gezeigt kommt, sicherstellen, dass der Port erreichbar ist. Eventuell auch erst einmal ausprobieren mit der IP Adresse auf dem Port zu verbinden (telnet IP PORT)
    root@host:~# puppet agent --test --server puppetmaster.example.org
    err: Could not retrieve catalog from remote server: Connection refused - connect(2)
    warning: Not using cache on failed catalog
    err: Could not retrieve catalog; skipping run
    err: Could not send report: Connection refused - connect(2)
    root@host:~#
    
  • Wenn es zu einer „Server hostname did not match server certificate“ Fehlermeldung kommt, dann kann es helfen fuer den Server einen entsprechenden Eintrag in die /etc/hosts zu packen
    root@host:~# puppet agent --test --server 192.168.1.100
    err: Could not retrieve catalog from remote server: Server hostname '192.168.1.100' did not match server certificate; expected one of puppetmaster.example.org, DNS:puppet, DNS:puppet.example.org, DNS:puppetmaster.example.org
    warning: Not using cache on failed catalog
    err: Could not retrieve catalog; skipping run
    err: Could not send report: Server hostname '192.168.1.100' did not match server certificate; expected one of puppetmaster.example.org, DNS:puppet, DNS:puppet.example.org, DNS:puppetmaster.example.org
    root@host:~#
    

puppet: „err: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not parse YAML data for node“

Wenn der puppet agent auf dem node die folgende Fehlermeldung ausgibt:

err: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not parse YAML data for node

Ist die Loesung des Problems, auf dem puppet master die folgenden beiden Dateien zu loeschen:

rm /var/lib/puppet/yaml/node/*
rm /var/lib/puppet/yaml/facts/*

Danach auf dem client den puppet agent testen und alles ist gut:

puppet agent --test --server puppet.example.net

Hier genauso uebernommen 1:1 von da.