Qual è il modo corretto di eseguire il loop in una ricetta Chef (solo)?


8

Qualcuno può spiegarmi come funziona lo chef? Questa è una domanda piuttosto ampia, quindi per restringere il campo ho questa ricetta molto semplice che scorre su un elenco di utenti e crea ciascuno se non esistono già. Non funziona.

Da quello che posso dire il ciclo sembra accadere come mi sarei aspettato. Una volta completato il ciclo, i miei comandi bash per creare ogni utente vengono eseguiti, una volta per ogni iterazione nel ciclo. Tuttavia, quando i comandi bash vengono eseguiti sembrano avere solo il valore utente dalla prima iterazione del ciclo.

Qual è il modo corretto di scrivere una ricetta che scorre su dati variabili simili a questo esempio?

Ecco la ricetta:

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

Sto testando questo usando Vagrant con la seguente configurazione:

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

I messaggi generati dalle istruzioni put nella ricetta si presentano così:

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

Risposte:


5

rendere unico il nome del tuo script ...

bash "create_user_#{user}" do

FWIW, ho usato più volte https://github.com/fnichol/chef-user che ti consente di creare / rimuovere utenti in base ad attributi e databags.


Sembra così semplice, grazie! La ricetta per la creazione di utenti era solo un esempio che stavo usando per capire perché il mio loop non funzionava in altre ricette. Grazie ancora!
Matthew J Morrison,

10

Il comportamento che stai vedendo può essere spiegato comprendendo la differenza tra due delle fasi chiave in una corsa client Chef: compilazione e convergenza.

Durante la fase di "compilazione", il client Chef esegue il codice nelle ricette per creare una raccolta di risorse . Questo è un elenco delle risorse che hai detto a Chef di gestire sul tuo sistema, insieme al loro stato target. Ad esempio, una risorsa Directory per dire che /tmp/foodovrebbe esistere ed essere di proprietà di root:

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

Durante la fase di "convergenza", il client Chef utilizza i provider per caricare lo stato corrente di ciascuna risorsa, quindi lo confronta con lo stato di destinazione. Se sono diversi, Chef aggiornerà il sistema. Per la nostra risorsa Directory, Chef creerebbe la directory se non esistesse e cambierà il suo proprietario in "root" se necessario.

Le risorse sono identificate in modo univoco dal loro nome e tipo - lo sarebbe la nostra Directory directory[/tmp/foo]. Accadranno cose strane quando hai due risorse con lo stesso nome ma attributi diversi - questo spiega il tuo problema e può essere risolto usando la risposta di Darrin Holst:

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

Tuttavia, in questo caso particolare, trarrai vantaggio dall'utilizzo della risorsa Utente dello Chef. Ecco un sostituto per la tua ricetta (senza i messaggi di debug):

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

Perché è meglio di un insieme di risorse bash?

  1. La risorsa Utente funziona allo stesso modo su varie piattaforme: la stessa ricetta funzionerà su sistemi operativi che usano qualcosa di diverso da "useradd" per creare utenti.
  2. I fornitori responsabili di questo sanno come verificare se l'utente esiste già, quindi non è necessario not_if.
  3. Gli stessi provider possono anche essere utilizzati per rimuovere utenti, bloccare o sbloccare le loro password e aggiornare altri attributi su account utente esistenti.

Ma il miglior motivo per usare le giuste risorse è che comunica più chiaramente le tue intenzioni. Il tuo obiettivo probabilmente non è quello di eseguire un sacco di comandi di shell: è quello di garantire che alcuni utenti siano presenti sul tuo sistema. I comandi usati per farlo sono solo un dettaglio di implementazione.

I fornitori incapsulano questi dettagli, lasciandoci liberi di concentrarci sulla descrizione di ciò che vogliamo.


1
Grazie, questo chiarisce un po 'le cose. La ricetta per la creazione dell'utente era solo un esempio con cui potevo giocare per capire meglio perché i loop che avevo altrove non funzionavano come mi aspettavo.
Matthew J Morrison,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.