如何检查Chef中是否存在文件夹?

这是我的代码:

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 

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

你应该在这里使用厨师守卫 。 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 vs条件包装器

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更改为节点属性test:

 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 

使用Dir.exists? 。 您也可以替换if ! condition if ! conditionunless condition读得更好。

 unless Dir.exist? "#{node['iis']['home']}\\backup\\BkpB4Chef" windows_batch "Backup IIS Config" do code <<-EOH "#{node['iis']['home']}"\\appcmd add backup BkpB4Chef EOH end end