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

时间:2013-01-31 19:22:05

标签: ruby attributes chef

我有两个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 here的技巧,因为在cloud_volume LWRP中使用了通知(因此它会落入文档中显示的反模式中)

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

2 个答案:

答案 0 :(得分:15)

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

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

答案 1 :(得分:13)

免责声明:在添加lazy attribute evaluation之前,这是与老厨师(< 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]在编译时不会知道,但在编译时也不会被访问。它只能在运行阶段访问,它应该已经设置。