如何在Ruby块中覆盖Chef节点属性值,解决编译收敛阶段差问题
问题根因
Chef执行分为两个核心阶段:
- 编译阶段:读取所有食谱代码,解析所有资源的属性值,生成资源执行队列,此时不会执行任何资源的实际操作
- 收敛阶段:按照队列顺序依次执行资源的action
你定义的ruby_block的block内部代码仅在收敛阶段才会执行,但log资源的message属性在编译阶段就完成了字符串插值求值,此时属性还未被修改,因此输出的仍然是初始的default_value。
修复方案(使用Chef Lazy)
Chef的lazy关键字可以将资源属性的求值时间,从编译阶段推迟到对应资源执行前的收敛阶段,刚好匹配ruby_block修改属性的执行时机。
修改后的代码如下:
ruby_block 'test_block' do block do node.override['custom_attributes']['custom_attribute_1'] = "overridden_value" end action :run end log 'message' do # 用lazy包裹求值逻辑,延迟到收敛阶段执行log资源前再读取属性值 message lazy { "attribute value = #{node[:custom_attributes][:custom_attribute_1]}" } level :info end
修改后log输出的就是修改后的overridden_value。
扩展说明
- 新增属性的操作逻辑和覆盖完全一致,只要在
ruby_block内给node属性赋值,后续引用该属性的资源属性都用lazy包裹即可 - 如果有多个依赖这个动态修改属性的资源,每个资源的对应属性都需要单独加
lazy修饰
内容的提问来源于stack exchange,提问作者Alfred
相关产品推荐
相关产品推荐

