我的食谱配置如下:
package "scribe" do
action :install
end
package "supervise-scripts" do
action :install
end
remote_directory "/var/service/" do
source "#{node['site-scribe']['cluster']}"
end
Dir.foreach('/var/service') do |dir|
next if dir == '..'|| dir == '.'
execute "svc_add_#{dir}" do
command "/usr/bin/svc-add #{dir}"
not_if { ::Dir.exists?("/var/service/#{dir}/supervise") }
end
execute "svc_restart_#{dir}" do
command "/usr/bin/svc-restart #{dir}"
end
end
现在我遇到了奇怪的行为。在服务器上第一次运行 chef-client 时,它只执行remote_directory
块,而不启动Dir.foreach
循环。第二次运行时,它Dir.foreach
正常运行(始终在remote_directory
未下载时)。为什么Dir.foreach
如果执行了块,我的循环就不会启动remote_directory
?
当我删除它时会出现同样的行为not_if
。
//holosian
答案1
在远程目录操作实际发生之前执行循环Dir.foreach
。Chef 分为两个阶段执行。在第一阶段,运行所有配方代码,并将资源放置在数组中以供稍后评估。在第二阶段,然后运行这些资源以实际完成工作。正如 StephenKing 所暗示的那样,您的情况是:
- 您的
remote_directory
块运行,并在模板上放置一个资源来拉下该远程目录。 - 您的
Dir.foreach
循环已运行,但由于 #1 的资源仍在数组中(尚未执行),/var/service
目录中没有子项。因此循环遍历 0 个元素并退出。 - 在第二次运行中
chef-client
,您将获得值,/var/service
因此循环可以正常工作。
除非您需要在一次 Chef 运行中完成完全收敛,否则您实际上不会遇到问题。只需确保使用not_if
and语句来确保每个资源仅在需要时运行。但是,如果您需要在一次运行中完成所有操作,则必须破解解决方案。最简单的选择是通过执行以下操作来only_if
强制立即评估您的资源:remote_directory
remote_directory "/var/service/" do
source "#{node['site-scribe']['cluster']}"
end.run_action(:create)
这将强制操作在 Chef 执行的第一阶段实际执行,然后您的循环就会起作用。