Может кто-нибудь объяснить мне, как работает шеф-повар? Это довольно широкий вопрос, поэтому, чтобы сузить его, у меня есть очень простой рецепт, который перебирает список пользователей и создает каждого из них, если они еще не существуют. Это не работает.
Из того, что я могу сказать, цикл, кажется, происходит так, как я и ожидал. После завершения цикла выполняются команды bash для создания каждого пользователя, по одному разу для каждой итерации цикла. Однако когда команды bash выполняются, кажется, что они имеют пользовательское значение только с первой итерации цикла.
Как правильно написать рецепт, который перебирает переменные данные, как в этом примере?
Вот рецепт:
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
Я тестирую это с помощью Vagrant со следующей настройкой:
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
Сообщения, генерируемые инструкциями put в рецепте, выглядят так:
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
Поведение, которое вы видите, можно объяснить, понимая разницу между двумя ключевыми этапами запуска клиента Chef: компиляцией и конвергенцией.
На этапе «компиляции» клиент Chef запускает код в ваших рецептах для создания коллекции ресурсов . Это список ресурсов, которые вы указали Chef для управления в вашей системе, вместе с их целевым состоянием. Например, ресурс Справочника, который
/tmp/foo
должен существовать и принадлежать пользователю root:На этапе «конвергенции» клиент Chef использует провайдеров для загрузки текущего состояния каждого ресурса, а затем сравнивает его с целевым состоянием. Если они разные, Chef обновит систему. Для нашего ресурса Directory Chef создаст каталог, если он не существует, и при необходимости изменит его владельца на «root».
Ресурсы однозначно идентифицируются по их имени и типу - наш каталог будет
directory[/tmp/foo]
. Странные вещи произойдут, когда у вас есть два ресурса с одинаковыми именами, но разными атрибутами, - это объясняет вашу проблему, и это можно исправить с помощью ответа Даррина Холста:Тем не менее, в этом конкретном случае вы бы выиграли от использования ресурса пользователя Chef. Вот замена для вашего рецепта (без сообщений отладки):
Почему это лучше, чем набор ресурсов Bash?
Но лучшая причина для использования правильных ресурсов заключается в том, что они более четко отражают ваши намерения. Ваша цель, вероятно, состоит не в том, чтобы запускать несколько команд оболочки, а в том, чтобы обеспечить присутствие некоторых пользователей в вашей системе. Команды, используемые для этого, являются просто деталями реализации.
Поставщики инкапсулируют эти детали, что позволяет нам сосредоточиться на описании того, что мы хотим.
источник