2013-01-31 54 views
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公司擁有here的通知在cloud_volume LWRP正在使用的伎倆(所以它會落入文檔中所示的反模式)

所以,這一切後,我的問題是,有什麼辦法可以避免在編譯時知道disk_uuid的值?

回答

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 
13

免責聲明:這是與老廚師(< 11.6.0),然後他們加入lazy attribute evaluation之前的方式。

將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]不會在編譯時是已知的,但它也不會在編譯的時候訪問。它只會在運行階段被訪問,當它已經被設置。

+0

呃,這就是我正在尋找的!像魅力一樣工作,謝謝:-) – Matt

+0

我已經爲您+1了,但非常感謝您指出添加了懶惰屬性評估的版本。 –

相關問題