有人可以向我解释厨师是如何工作的吗?这是一个相当广泛的问题,所以为了缩小范围,我有一个非常简单的方法,它循环遍历用户列表并创建每个用户(如果它们尚不存在)。这是行不通的。
据我所知,循环似乎正如我所期望的那样发生。一旦循环完成了我创建每个用户的 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
Run Code Online (Sandbox Code Playgroud)
我正在使用具有以下设置的 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
Run Code Online (Sandbox Code Playgroud)
配方中的 puts 语句生成的消息如下所示:
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
Run Code Online (Sandbox Code Playgroud)
zts*_*zts 10
您所看到的行为可以通过理解 Chef 客户端运行中的两个关键阶段之间的差异来解释:编译和收敛。
在“编译”阶段,Chef 客户端运行您的配方中的代码以构建资源集合。这是您告诉 Chef 在您的系统上管理的资源列表,以及它们的目标状态。例如,一个目录资源表示/tmp/foo
应该存在,并且由 root 拥有:
directory "/tmp/foo" do
owner "root"
end
Run Code Online (Sandbox Code Playgroud)
在“收敛”阶段,Chef 客户端使用提供程序加载每个资源的当前状态,然后将其与目标状态进行比较。如果它们不同,Chef 将更新系统。对于我们的目录资源,如果目录不存在,Chef 将创建该目录,并在必要时将其所有者更改为“root”。
资源由它们的名称和类型唯一标识 - 我们的目录将是directory[/tmp/foo]
. 当您有两个具有相同名称但属性不同的资源时,会发生奇怪的事情 - 这解释了您的问题,并且可以使用 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
Run Code Online (Sandbox Code Playgroud)
但是,在这种特殊情况下,您将受益于使用 Chef 的用户资源。这是您的配方的替代品(没有调试消息):
node[:users].each do |u|
user u['username'] do
action :create
end
end
Run Code Online (Sandbox Code Playgroud)
为什么这比一组 bash 资源更好?
但使用正确资源的最佳理由是它更清楚地传达了您的意图。您的目标可能不是运行一堆 shell 命令——而是确保某些用户存在于您的系统上。用于执行此操作的命令只是一个实现细节。
提供者封装了这些细节,让我们可以自由地专注于描述我们想要的东西。
小智 5
使您的脚本名称唯一...
bash "create_user_#{user}" do
FWIW,我已经多次使用https://github.com/fnichol/chef-user,它允许您根据属性和数据包创建/删除用户。
归档时间: |
|
查看次数: |
20746 次 |
最近记录: |