11

我有两个 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在编译时知道值的要求?

4

2 回答 2

15

一种更清洁的方法是使用Lazy Attribute Evaluationnode[:volumes][mount_point][:uuid]这将在执行期间评估而不是编译

foobar "#{mount_point}" do
  disk_uuid lazy { node[:volumes][mount_point][:uuid] }
  action [:do_stuff]
end
于 2013-11-20T00:17:35.060 回答
13

免责声明:这是老厨师(<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]在编译时不为人所知,但在编译时也不会被访问。它只会在运行阶段访问,当它应该已经设置时。

于 2013-01-31T20:41:31.157 回答