如何为Chef的ruby_block或非模板资源实现Accumulator模式?
Chef累加器自定义资源:非类变量的状态存储方案
可行的状态存储位置
- node.run_state:Chef Run的临时内存存储,仅当前运行有效,不会写入节点属性,是临时累加数据的首选方案
- run_context自定义属性:直接在run_context对象上挂载自定义哈希,功能和run_state类似,但run_state更符合官方规范
- 辅助占位资源:创建无操作的自定义资源,用其属性存储对应file_path的累加数据
按file_path区分的实现方案(基于node.run_state)
最推荐使用node.run_state,可以轻松按file_path分组存储不同的累加数据,修改后的示例代码如下:
action :add do # 初始化当前file_path对应的累加容器,避免nil报错 accumulator_key = "auth_accumulator_#{new_resource.file_path}" node.run_state[accumulator_key] ||= {} # 向对应路径的累加器添加当前实例数据 node.run_state[accumulator_key][new_resource.host] = { 'user' => new_resource.user, 'password' => new_resource.password } path = new_resource.file_path with_run_context :root do edit_resource(:ruby_block, "set-auth #{path}") do block do # 处理文件不存在的边界情况 json = if ::File.exist?(path) JSON.parse(::IO.read(path)) else { 'auths' => {} } end # 从run_state取出对应路径的累加数据,写入JSON文件 json['auths'] = node.run_state[accumulator_key] ::IO.write(path, JSON.pretty_generate(json)) end action :run end end end
方案说明
- 用
node.run_state["auth_accumulator_#{file_path}"]作为每个文件路径的专属累加容器,确保不同file_path的数据完全隔离 - 初始化时用
||= {}保证首次访问时不会出现NilClass错误 - ruby_block中直接读取对应路径的累加数据,覆盖或合并到目标JSON结构中
- 补充了文件不存在的处理逻辑,初始化默认的JSON结构
替代方案(基于run_context自定义存储)
如果不想使用node.run_state,也可以直接在run_context上挂载自定义累加器:
action :add do path = new_resource.file_path # 初始化run_context的累加器哈希 unless run_context.instance_variable_defined?(:@auth_accumulators) run_context.instance_variable_set(:@auth_accumulators, {}) end accumulators = run_context.instance_variable_get(:@auth_accumulators) accumulators[path] ||= {} # 添加当前实例数据 accumulators[path][new_resource.host] = { 'user' => new_resource.user, 'password' => new_resource.password } with_run_context :root do edit_resource(:ruby_block, "set-auth #{path}") do block do json = ::File.exist?(path) ? JSON.parse(::IO.read(path)) : { 'auths' => {} } json['auths'] = run_context.instance_variable_get(:@auth_accumulators)[path] ::IO.write(path, JSON.pretty_generate(json)) end action :run end end end
不过这种方式不如node.run_state直观,且run_state是Chef官方推荐的临时存储方式,更符合最佳实践。
内容的提问来源于stack exchange,提问作者Thayne
相关产品推荐
相关产品推荐

