有没有办法将资源的属性解析延迟到“执行”阶段?

我有两个LWRP。 第一部分涉及创建磁盘卷,格式化它并将其安装在虚拟机上,我们将此资源cloud_volume 。 第二个资源(它的作用并不重要)需要一个UUID用于新格式化的卷,这是一个必需的属性,我们将这个资源称为foobar

资源cloud_volumefoobar用于如下的配方中。

 volumes.each do |mount_point, volume| cloud_volume "#{mount_point}" do size volume['size'] label volume['label'] action [:create, :initialize] end foobar "#{mount_point}" do disk_uuid node[:volumes][mount_point][:uuid] # This is set by cloud_volume action [:do_stuff] end end 

所以,当我做一个厨师运行时,我得到一个Required argument disk_identifier is missing! 例外。

在做了一些挖掘之后,我发现配方分两个阶段进行处理,即编译阶段和执行阶段。 看起来问题是在编译时,因为这是node[:volumes][mount_point][:uuid]未设置的时间点。

不幸的是,我不能使用OpsCode在这里的技巧,因为通知正在cloud_volume LWRP中使用(因此它将落入文档中显示的反模式)

所以,经过这一切,我的问题是,有没有办法解决在编译时知道disk_uuid值的要求?

更简洁的方法是使用惰性属性评估 。 这将在执行时而不是编译期间评估node[:volumes][mount_point][:uuid]

 foobar "#{mount_point}" do disk_uuid lazy { node[:volumes][mount_point][:uuid] } action [:do_stuff] end 

免责声明 :在添加惰性属性评估之前,这是与老厨师(<11.6.0)相关的方法。

将foobar资源包装到ruby_block中并动态定义foobar。 这样在编译阶段之后,您将在资源集合中获得ruby代码,并在运行阶段对其进行评估。

 ruby_block "mount #{mount_point} using foobar" do block do res = Chef::Resource::Foobar.new( mount_point, run_context ) res.disk_uuid node[:volumes][mount_point][:uuid] res.run_action :do_stuff end end 

这样, node[:volumes][mount_point][:uuid]在编译时将不会被知道,但在编译时也不会被访问。 它只能在运行阶段访问,它应该已经设置好。