Was ist der richtige Weg, um ein Kochrezept (Solo) zu wiederholen?

8

Kann mir bitte jemand erklären, wie der Koch arbeitet? Das ist eine ziemlich weit gefasste Frage. Um sie einzugrenzen, habe ich dieses sehr einfache Rezept, das eine Liste von Benutzern durchläuft und jedes einzelne erstellt, wenn sie noch nicht vorhanden sind. Es funktioniert nicht.

Soweit ich weiß, scheint die Schleife so zu verlaufen, wie ich es erwarten würde. Sobald die Schleife abgeschlossen ist, werden meine Bash-Befehle zum Erstellen jedes Benutzers einmal für jede Iteration in der Schleife ausgeführt. Wenn die Bash-Befehle ausgeführt werden, scheinen sie jedoch nur den Benutzerwert aus der ersten Schleifeniteration zu haben.

Was ist der richtige Weg, um ein Rezept zu schreiben, das ähnliche Daten wie in diesem Beispiel durchläuft?

Hier ist das Rezept:

node[:users].each do |user|
  puts "in loop for #{user['username']}"
  bash "create_user" do
    user "root"
    code do
      puts "running 'useradd' for #{user['username']}"
      "useradd #{user['username']}"
    end
    not_if do
      puts "checking /etc/passwd for #{user['username']}"
      "cat /etc/passwd | grep #{user['username']}"
    end
  end
end

Ich teste dies mit Vagrant mit dem folgenden Setup:

Vagrant::Config.run do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
  config.vm.provision :chef_solo do |chef|
    chef.add_recipe "sample"
    chef.json = {
      :users => [
        {:username => 'testA'},
        {:username => 'testB'},
        {:username => 'testC'},
        {:username => 'testD'},
        {:username => 'testE'},
      ],
    }
  end
end

Die Nachrichten, die von den Puts-Anweisungen im Rezept generiert werden, sehen folgendermaßen aus:

2013-03-08T01:03:46+00:00] INFO: Start handlers complete.
in loop for testA

in loop for testB

in loop for testC

in loop for testD

in loop for testE

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Processing bash[create_user] action run (sample::default line 5)
checking /etc/passwd for testA

[2013-03-08T01:03:46+00:00] INFO: Chef Run complete in 0.026071 seconds
Matthew J Morrison
quelle

Antworten:

5

Machen Sie Ihren Skriptnamen einzigartig ...

bash "create_user_#{user}" do

FWIW, ich habe https://github.com/fnichol/chef-user mehrmals verwendet, um Benutzer basierend auf Attributen und Datenbags zu erstellen / entfernen.

Darrin Holst
quelle
Das scheint so einfach, danke! Das Rezept zum Erstellen von Benutzern war nur ein Beispiel, mit dem ich mir ein Bild davon machte, warum meine Schleife in anderen Rezepten nicht funktionierte. Danke noch einmal!
Matthew J Morrison
10

Das Verhalten, das Sie sehen, kann erklärt werden, indem Sie den Unterschied zwischen zwei der wichtigsten Phasen eines Chef-Client-Laufs verstehen: Kompilierung und Konvergenz.

Während der "Kompilierungs" -Phase führt der Chef-Client den Code in Ihren Rezepten aus, um eine Ressourcensammlung zu erstellen . Dies ist eine Liste der Ressourcen , die Chefkoch auf Ihrem System verwalten soll, sowie deren Zielstatus. Beispiel: Eine Verzeichnisressource, die besagt, dass /tmp/foosie vorhanden sein und Eigentum von root sein sollte:

directory "/tmp/foo" do
  owner "root"
end

Während der "Konvergenz" -Phase verwendet der Chef-Client Anbieter , um den aktuellen Status jeder Ressource zu laden, und vergleicht diesen dann mit dem Zielstatus. Wenn sie unterschiedlich sind, aktualisiert Chef das System. Für unsere Verzeichnisressource würde Chef das Verzeichnis erstellen, wenn es nicht vorhanden wäre, und seinen Besitzer bei Bedarf in "root" ändern.

Ressourcen werden durch ihren Namen und Typ eindeutig identifiziert - unser Verzeichnis wäre directory[/tmp/foo]. Seltsame Dinge passieren, wenn Sie zwei Ressourcen mit demselben Namen, aber unterschiedlichen Attributen haben - das erklärt Ihr Problem und kann mithilfe der Antwort von Darrin Holst behoben werden:

node[:users].each do |user|
  puts "in loop for #{user['username']}"
  bash "create_user_#{user}" do
    user "root"
    code do
      puts "running 'useradd' for #{user['username']}"
      "useradd #{user['username']}"
    end
    not_if do
      puts "checking /etc/passwd for #{user['username']}"
      "cat /etc/passwd | grep #{user['username']}"
    end
  end
end

In diesem speziellen Fall würden Sie jedoch von der Verwendung der Benutzerressource von Chef profitieren. Hier ist ein Ersatz für Ihr Rezept (ohne die Debugging-Meldungen):

node[:users].each do |u|
  user u['username'] do
    action :create
  end
end

Warum ist dies besser als eine Reihe von Bash-Ressourcen?

  1. Die Benutzerressource funktioniert auf verschiedenen Plattformen auf dieselbe Weise. Das gleiche Rezept funktioniert auf Betriebssystemen, die zum Erstellen von Benutzern etwas anderes als "useradd" verwenden.
  2. Die dafür verantwortlichen Anbieter können prüfen, ob der Benutzer bereits vorhanden ist, sodass Sie not_if nicht benötigen.
  3. Dieselben Anbieter können auch verwendet werden, um Benutzer zu entfernen, ihre Kennwörter zu sperren oder zu entsperren und andere Attribute für vorhandene Benutzerkonten zu aktualisieren.

Der beste Grund, die richtigen Ressourcen zu verwenden, ist jedoch, dass Ihre Absicht klarer kommuniziert wird. Ihr Ziel ist es wahrscheinlich nicht, eine Reihe von Shell-Befehlen auszuführen, sondern sicherzustellen, dass einige Benutzer auf Ihrem System vorhanden sind. Die dazu verwendeten Befehle sind nur ein Implementierungsdetail.

Die Anbieter kapseln diese Details, sodass wir uns darauf konzentrieren können, zu beschreiben, was wir wollen.

zts
quelle
1
Danke, das klärt die Dinge ziemlich viel. Das Rezept zur Benutzererstellung war nur ein Beispiel, mit dem ich spielen konnte, um besser zu verstehen, warum die Schleifen, die ich an anderer Stelle hatte, nicht wie erwartet funktionierten.
Matthew J Morrison