Puppet exportierte Ressourcen für .erb-Dateivariablen?

8

Szenario: Meine Konfigurationsdatei wird durch eine .erbDatei definiert, die das folgende Snippet enthält.

<% backupclients.each do |backup_files| -%>
Job {
  Name = "Server"
  JobDefs = "DefaultJob"
  Client = <%= backup_files %>-fd
  Pool = TeraMonth
  Write Bootstrap = "/var/lib/bacula/<%= backup_files %>.bsr"
}
<% end -%>

Die Konfigurationsdatei des Servers benötigt einen wiederholten Eintrag für jeden Client-Host. Wenn ich ein einfaches Array erstellen würde, würde dies ohne Probleme funktionieren. Was ich jedoch tun möchte, ist, dass jeder Host sich selbst registriert und dann die Daten mit dem <<| |>>Pragma sammelt, ähnlich wie man es mit den nagios_*Typen tun würde .

Das Standardbeispiel hierfür ist das Exportieren eines Typs.

class ssh {
  @@sshkey { $hostname: type => dsa, key => $sshdsakey }
  Sshkey <<| |>>
}

Ich kann jedoch nicht genau herausfinden, wie ein Typ geschrieben oder auf eine Weise referenziert werden soll, die es mir ermöglicht, dieses Array von Werten aus der .erbVorlage zu lesen . Gibt es eine Möglichkeit, exportierte Ressourcen in Kombination mit einer Variablenschleife in einer .erbDatei zu verwenden?

Jeff Ferland
quelle
Müssen sie wirklich in derselben Datei landen? Ich möchte jeden Host in einer separaten Datei haben. So etwas wie /etc/bacula/clientdefs/*.conf . Dies sollte einfacher zu handhaben sein.
Zoredache

Antworten:

5

Um Ihre Frage direkt zu beantworten, glaube ich nicht, dass es möglich ist , eine Liste der exportierten Ressourcen direkt von erb zu erhalten. Dies liegt an der Art der exportierten Ressourcen. Für Puppet sind es nur mehr Ressourcen, die auf dem Host erstellt werden müssen.

Es gibt jedoch eine Möglichkeit, das zu erreichen, was Sie tun möchten. Ich mache es an einigen Stellen in meiner Umgebung.

Hier erstellen wir ein Verzeichnis von Dateien, eines für jeden Host, den wir als "bacula_client" kennzeichnen möchten. Wir verwenden die purge, forceund recurseOptionen , um Dateien zu entfernen , die nicht von Puppet verwaltet werden (dh , wenn Sie ein System aus dieser „Liste“ entfernen mögen).

class bacula::client {

  @@file { "/etc/bacula_clients/$fqdn":
    ensure => present,
    content => "",
    require => File['/etc/bacula_clients'],
    tag => "bacula_client",
  }

}

class bacula::server {

  #
  # .. include whatever else the server requires, like package {} file {} service {}
  #

  file { "/etc/bacula_clients":
    ensure => directory,
    purge => true,
    recurse => true,
    force => true,
  }

  # Populate directory of client files.
  File <<| tag == "bacula_client" |>>

}

Als nächstes verwenden wir Ruby-Code in der .erb, um dieses Verzeichnis nach Dateien zu durchsuchen und darauf zu reagieren:

<% 
bacula_clients_dir = '/etc/bacula_clients'
d = Dir.open(bacula_clients_dir)

# Remove directories from the list of entries in the directory (specifically '.' and '..'):
backupclients = d.entries.delete_if { |e| File.directory? "#{bacula_clients_dir}/#{e}" }

backupclients.each do |backup_files| 
-%>
Job {
  Name = "Server"
  JobDefs = "DefaultJob"
  Client = <%= backup_files %>-fd
  Pool = TeraMonth
  Write Bootstrap = "/var/lib/bacula/<%= backup_files %>.bsr"
}
<% end -%>
Kyle Smith
quelle
Jetzt fühle ich mich schlecht, weil ich meine Skripte vor zwei Tagen fertig geschrieben habe und das Format sehr eng ist. Das heißt, ich lasse Sie entscheiden, ob Sie der Meinung sind, dass Ihre Antwort oder meine Antwort für mich angemessener ist.
Jeff Ferland
Ich würde sagen, Ihre Antwort ist angemessener, wenn die Anwendung ein Konfigurationsverzeichnis oder ein Include per Platzhalter unterstützt (wie Bacula scheint). Ich habe dies in meiner Umgebung für Skripte verwendet, die Dateien auf eine Reihe von Zielhosts verschieben. Also machen die Bash-Skripte einfach ls /path/to/flag/files|while read hostname; do ssh $hostname ..; done.
Kyle Smith
4

Nun, zuerst gab ich auf und stellte meinen @@auf den tatsächlichen Dateityp ein. Der Vorteil ist, dass hierfür immer noch die Variablen auf dem Client-Host verwendet werden.

class bacula-client ($database = false) {
    @@file { "${hostname}-bacula-client.conf":
            mode => 600,
            owner => bacula,
            group => root,
            path => "/etc/bacula/conf.d/${hostname}-client.conf",
            content => template("bacula-dir-cliententry.erb"),
            tag => 'bacula-client',
            notify => Service[bacula-director]
    }

    ...
}

Auf diese Weise kann ich Einträge in der erb-Datei verwenden, z.

<% if has_variable?("database") and database== "true" %>
    ...
<% end -%>

und Deklarationen in meinen site.pp-Dateien wie: class { bacula-client: database => "true" }

So behandeln Sie das Verzeichnis selbst:

class bacula-director {
        file { '/etc/bacula/conf.d':
            ensure => directory,
            owner => bacula,
            group => root,
            mode => 600,
            purge => true,
            recurse => true
        }

        ...
}

Durch Löschen und Wiederholen werden alle nicht definierten Elemente entfernt. Wenn ich einen Host offline puppetstoredconfigclean $hostnameschalte , werden die Fakten bereinigt und der nächste Puppet-Lauf auf dem Director setzt die Konfiguration entsprechend zurück.

Mit der Bacula Director-Software selbst kann ich am Ende meiner Datei bacula-dir.conf Folgendes ausführen:

@|"sh -c 'for f in /etc/bacula/conf.d/*.conf ; do echo @${f} ; done'"

Es scheint also immer noch keine direkte Möglichkeit zu geben, eine ERB-Vorlage für einen gesammelten Satz von Ressourcen zu verwenden, aber man kann einen Typ sammeln. Dies kann Augeas-Typen umfassen, um alles in eine Datei zu packen, oder einen Hack zum Sammeln von Dateien in einer Konfiguration. Es enthält jedoch noch nicht, wonach ich bei der Frage gesucht habe.

Jeff Ferland
quelle
1

Ich habe eine Methode mit dem PuppetDB-Dienst gefunden, die für diese Situation ziemlich gut funktioniert, obwohl sie etwas hackisch ist. Um dies zu verwenden, muss PuppetDB betriebsbereit sein (was Sie bereits haben sollten, wenn Sie exportierte Ressourcen verwenden), und die PuppetDB-API muss vom Puppetmaster (localhost) abfragbar sein.

Anschließend möchten Sie alle Ressourcen, die Sie in Ihrem Array sammeln möchten, in ein dediziertes Verzeichnis im Dateisystem exportieren. Dieser Verzeichnispfad wird verwendet, um die Zielressourcen eindeutig zu identifizieren.

Führen Sie dann in Ihrer Vorlage Folgendes aus:

    require 'rest_client'
    require 'json'
    resources=JSON.parse(RestClient.get("http://localhost:8080/v2/nodes/#{nodename}/resources", {:accept => :json}))

    retVal = Array.new
    resources.each do |resource|
       if resource["title"] =~ /^#{pathRegex}$/
           retVal.push(resource["title"])
       end
    end

Wenn Knotenname der vollqualifizierte Domänenname des Servers ist, ist pathRegex der oben erwähnte Suchpfad, der als Ruby Regex formatiert ist, und retVal ist das fertige Array. Dies nutzt die Möglichkeit, dass die Vorlage auf dem Puppetmaster verarbeitet wird, sodass keine speziellen API-Anmeldeinformationen erforderlich sind. Dies setzt auch voraus, dass der Ressourcenname var der vollständig qualifizierte Pfad der Zieldateien ist. Wenn Sie komplexe Namensvars haben und das Pfadattribut verwenden, ist eine komplexere Logik erforderlich. Beachten Sie auch, dass dadurch alle exportierten und lokalen Ressourcen zurückgegeben werden. Die zurückgegebenen Daten haben viele Attribute, die bei Bedarf für komplexere Logik verwendet werden können.

Ein bisschen hacky, aber es funktioniert gut.

TJNII
quelle