这是我的代码:

if !::File.exist?("#{node['iis']['home']}\\backup\\BkpB4Chef")
 windows_batch "Backup IIS Config" do
  code <<-EOH
   "#{node['iis']['home']}"\\appcmd add backup BkpB4Chef
  EOH
 end
end

它总是说文件存在并执行循环。

最佳答案

您应该在这里使用 Chef guards。 Guards 指定条件执行,但仍将资源插入到资源集合中。在您的示例和 jtblin 答案中,资源永远不会添加到集合中(稍后我将进一步解释)。

以下是一些可以帮助您入门的工作代码:

windows_batch "Backup IIS Config" do
  code %Q|#{node['iis']['home']}"\\appcmd add backup BkpB4Chef|
  not_if { ::File.directory?("#{node['iis']['home']}\\backup\\BkpB4Chef") }
end

使用 creates
许多非幂等的 Chef 资源还支持 creates 参数,该参数解释了资源的作用。换句话说,windows_batch“创建”了什么。这可以是文件、目录或可执行文件。因此,以下代码等效于前一个答案。
windows_batch "Backup IIS Config" do
  code %Q|#{node['iis']['home']}"\\appcmd add backup BkpB4Chef|
  creates"#{node['iis']['home']}\\backup\\BkpB4Chef"
end

为什么 not_if 与条件包装器

Chef 分两个阶段执行——编译阶段和收敛阶段。在编译阶段,将评估配方并将资源添加到资源集合中。在收敛阶段,资源集合中的资源被执行并针对目标系统进行评估。因此,请考虑以下示例:
if false
  service 'foo' do
    action :start
  end
end

这是一个相当直接的方法,它根据某些条件启动服务。但是,在编译阶段结束时,service 资源不会添加到资源集合中。由于配方 DSL 是 instance_eval ed,包装 if false 条件会阻止 Ruby VM 读取该代码。换句话说,就好像那个服务从来不存在一样。

通知资源是相当普遍的。在本节的后面,您可能希望由于配置更改而重新启动 apache。执行此操作的“正确”方法是使用通知:
template '/var/www/conf.d/my.conf.file' do
  # ...
  notifies :restart, 'service[apache2]'
end

这个 template 不能充分通知服务资源,因为它不存在于资源集合中。所以这个食谱会失败。这似乎是一个微不足道的例子,但是如果将条件 if false 更改为节点属性测试:
if node['cookbook']['use_apache']
  service 'apache2' do
    action :start
  end
end

你在你的食谱中创建了一个二分法,它在 50% 的时间里都有效。不幸的是,大多数食谱比两个资源复杂得多,因此资源可以通知不存在的资源的边缘情况的数量随着复杂性的增加而急剧增加。这一切都可以使用资源守卫解决(并表现出正确的行为):
service 'apache2' do
  action :start
  only_if { node['cookbook']['use_apache'] }
end

关于ruby - 如何检查 Chef 中是否存在文件夹?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18370804/

10-16 16:47