10

我正在为厨师属性中的服务生成配置。但是,在某些时候,我需要将属性 mash 转换为简单的 ruby​​ 哈希。这曾经在 Chef 10 中运行良好:

node.myapp.config.to_hash

但是,从 Chef 11 开始,这不起作用。只有顶级属性被转换为哈希,然后嵌套值保留不可变的 mash 对象。修改它们会导致如下错误:

Chef::Exceptions::ImmutableAttributeModification -------------------------------------------------------- ----- 当您不指定要设置的优先级时,节点属性是只读的。要设置属性,请使用类似 `node.default["key"] = "value"' 的代码

我尝试了很多方法来解决这个问题,但这些方法不起作用:

node.myapp.config.dup.to_hash
JSON.parse(node.myapp.config.to_json)

json 解析 hack 看起来应该很好用,结果是:

JSON::ParserError
unexpected token at '"#<Chef::Node::Attribute:0x000000020eee88>"'

除了在每本食谱中包含嵌套解析函数之外,是否有任何实际可靠的方法将属性转换为简单、普通、良好的旧 ruby​​ 哈希?

4

5 回答 5

11

在此处和 opscode chef 邮件列表上都缺乏答案之后,我最终使用了以下 hack:

class Chef
  class Node
   class ImmutableMash
      def to_hash
        h = {}
        self.each do |k,v|
          if v.respond_to?('to_hash')
            h[k] = v.to_hash
          else
            h[k] = v
          end
        end
        return h
      end
    end
  end
end

我把它放在我食谱的图书馆目录中;现在我可以在厨师 10(已经正常工作并且不受此猴子补丁影响)和厨师 11 中使用 attribute.to_hash。我也将此作为错误报告给 opscode:

如果你不想给你的厨师打猴子补丁,请在这个问题上说出来:http: //tickets.opscode.com/browse/CHEF-3857

更新: monkey-patch 票被这些 PR标记为关闭

于 2013-02-08T22:28:36.597 回答
4

我希望我参加聚会还不算太晚,但是将节点对象与空哈希合并为我做到了:

chef (12.6.0)> {}.merge(node).class
 => Hash
于 2016-03-29T18:35:37.493 回答
3

我遇到了同样的问题,经过多次修改后想出了这个:

json_string = node[:attr_tree].inspect.gsub(/\=\>/,':')
my_hash = JSON.parse(json_string, {:symbolize_names => true})

inspect 执行其他建议的方法中缺少的深度解析,我最终得到一个哈希,我可以根据需要修改和传递它。

于 2015-03-02T19:02:18.277 回答
2

这已经修复了很长时间:

[1] pry(main)> require 'chef/node'
=> true
[2] pry(main)> node = Chef::Node.new
[....]
[3] pry(main)> node.default["fizz"]["buzz"] = { "foo" => [ { "bar" => "baz" } ] }
=> {"foo"=>[{"bar"=>"baz"}]}
[4] pry(main)> buzz = node["fizz"]["buzz"].to_hash
=> {"foo"=>[{"bar"=>"baz"}]}
[5] pry(main)> buzz.class
=> Hash
[6] pry(main)> buzz["foo"].class
=> Array
[7] pry(main)> buzz["foo"][0].class
=> Hash
[8] pry(main)>

可能在 Chef 12.x 或 Chef 13.x 中或周围的某个时间修复,在 Chef 15.x/16.x/17.x 中肯定不再是问题

于 2021-04-15T16:08:36.500 回答
-2

上面的答案有点不必要。你可以这样做:

json = node[:whatever][:whatever].to_hash.to_json
JSON.parse(json)
于 2013-08-30T17:59:03.173 回答