我们存储库中的两个不同文件包含以下行:
# library_cookbook_1/attributes/default.rb
default[:library_cookbook_1][:foo] = true
# library_cookbook_2/attributes/default.rb
default[:library_cookbook_2][:foo] = true
我想合并这两个属性。仅仅将一个设置为另一个是不够的,因为它们都可以互换使用。我最担心的是有人犯了这个错误:
"environment_json_attributes": {
"library_cookbook_1": {
"foo": false //Now it's false half of the time...
}
}
在我们当前的结构下,忘记在我们的代码中设置两个变量的值是一个致命的错误。我想以维护覆盖层次结构的方式合并属性,这样如果 library_cookbook_1 具有角色级别覆盖,但 library_cookbook_2 具有环境级别覆盖,则厨师将处理覆盖,就好像属性只是一个属性一样。
理想的合并代码如下所示:
> node.attributes.debug_value('library_cookbook_1', 'foo')
{'precedence1' => true, 'precendence3' => false}
> node.attributes.debug_value('library_cookbook_2', 'foo')
{'precedence1' => false, 'precendence2' => true}
> attr_merge(['library_cookbook_1', 'foo'], ['library_cookbook_2', 'foo'])
> node.attributes.debug_value('library_cookbook_1', 'foo')
{'precedence1' => true, 'precendence2' => true, 'precendence3' => false}
> node.attributes.debug_value('library_cookbook_2', 'foo')
{'precedence1' => true, 'precendence2' => true, 'precendence3' => false}
> node[:library_cookbook_1][:foo].precedence4 = true
> node.attributes.debug_value('library_cookbook_2', 'foo')
{'precedence1' => true, 'precendence2' => true, 'precendence3' => false, 'precedence4' => true}
理想情况下,我希望每个属性都是指向同一事物的指针,这样,未来的调用和分配都适用于两者。
现在,显而易见的答案是简单地重构掉其中一个属性。不幸的是,chef 使重构属性变得困难——我们有 10 个不同的环境、7 个不同的角色、每个环境 20 个节点等。如果我们尝试重构整个事物,我们肯定会犯一个以微妙方式出现的错误。