Abhängigkeiten

Im vorherigen Abschnitt hatten wir bereits kurz das Thema Abhängigkeiten angeschnitten. Um im späteren Produktivbetrieb schwer zu identifizierende Probleme zu vermeiden, sollte man die Abhängigkeiten zwischen Ressourcen immer möglichst sauber definieren.

Hierzu greifen wir unser altes Beispiel nochmals auf und erweitern dieses um eine Abhängigkeit im Service. Für diesen gilt das gleiche Schema wie für die Konfigurationsdatei:

class modulname { 
   package { "apache2":
      ensure => "installed"
   }

   service { "apache2":
     ensure => "running",
     enable => true,
     require => Package['apache2']
   }

   file { "httpd.conf":
      path => "/etc/apache2/httpd.conf",
      ensure => file,
      require => Package['apache2'],
      source => "puppet:///modules/modulname/httpd.conf"
   }
}

Wozu gibt es Abhängigkeiten, wenn die Definitionen untereinander bereits in der richtigen Reihenfolge stehen?

Puppet beachtet die Reihenfolge nicht. Die Reihenfolge wird von Puppet auf die höchste Effizienz hin optimiert und damit nicht zwingend in der deklarierten Reihenfolge ausgeführt. Hierzu lassen sich manuell Abhängigkeiten definieren.

Neben require stehen noch weitere Abhängigkeiten zur Verfügung. Hier die Liste aller möglichen Optionen:

  • before - Definition wird vor der angegebenen Ressource angewendet
  • require - Definition wird nach der angegebenen Ressource angewendet
  • notify - Definition wird vor der angegebenen Ressource angewendet. Bei Änderungen wird die referenzierte Ressource aktualisiert. (z.B. Apache Reload nach Konfigurationsänderung)
  • subscribe - Definition wird nach der angegebenen Ressource angewendet. Bei Änderungen wird die aktuelle Definition aktualisiert.

Um den Unterschied zwischen notify und subscribe zu verdeutlichen, hier nochmals zwei Beispiele, welche die gleiche Funktion erfüllen.

Möglichkeit 1

class modulname { 
   package { "apache2":
      ensure => "installed"
   }

   service { "apache2":
     ensure => "running",
     enable => true,
     require => Package['apache2']
   }

   file { "httpd.conf":
      path => "/etc/apache2/httpd.conf",
      ensure => file,
      notify => Service['apache2'],
      source => "puppet:///modules/modulname/httpd.conf"
   }
}

Möglichkeit2

class modulname { 
   package { "apache2":
      ensure => "installed"
   }

   service { "apache2":
     ensure => "running",
     enable => true,
     require => Package['apache2']
     subscribe => Package["httpd.conf"]
   }

   file { "httpd.conf":
      path => "/etc/apache2/httpd.conf",
      ensure => file,
      source => "puppet:///modules/modulname/httpd.conf"
   }
}

Für die Datei benötigen wir hier nun keine Abhängigkeit zum Paket, da die Datei vom Dienst abhängig ist und dieser nicht ohne das Paket existieren kann (require). Die Abhängigkeit wird auf die httpd.conf praktisch „vererbt“.

Kurzschreibweise / Übersichtlichkeit

Um bei diesen Verkettung dennoch den Überblick zu behalten, gibt es eine Kurzschreibweise. Hierdurch kann die Lesbarkeit verbessert werden.

class modulname {
   package { "apache2":
      ensure => "installed"
   } ->

   file { "httpd.conf":
      path => "/etc/apache2/httpd.conf",
      ensure => file,
      source => "puppet:///modules/modulname/httpd.conf"
   } ~>

   service { "apache2":
      ensure => "running",
      enable => true,
      require => Package['apache2']
      subscribe => Package["httpd.conf"]
   }
}

Hierbei verwenden wir am Ende jeder Ressource / Definition Pfeile zur Signalisierung der Abhängigkeiten.

  • -> Von links nach rechts bzw. oben nach unten (vgl. before)
  • ~> Von links nach rechts bzw. oben nach unten. Zusätzlich wird die rechte bzw. untere Ressource bei Änderungen aktualisiert (vgl. notify)

Die Abhängigkeiten und Sortierungen von Puppet bieten noch viel mehr Möglichkeiten. Diese sind ebenfalls in der offiziellen Dokumentation zu finden.