chef 11: any way to turn attributes into a ruby ha

2019-04-26 17:51发布

I'm generating a config for my service in chef attributes. However, at some point, I need to turn the attribute mash into a simple ruby hash. This used to work fine in Chef 10:

node.myapp.config.to_hash

However, starting with Chef 11, this does not work. Only the top-level of the attribute is converted to a hash, with then nested values remaining immutable mash objects. Modifying them leads to errors like this:

Chef::Exceptions::ImmutableAttributeModification ------------------------------------------------ Node attributes are read-only when you do not specify which precedence level to set. To set an attribute use code like `node.default["key"] = "value"'

I've tried a bunch of ways to get around this issue which do not work:

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

The json parsing hack, which seems like it should work great, results in:

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

Is there any actual reliable way, short of including a nested parsing function in each cookbook, to convert attributes to a simple, ordinary, good old ruby hash?

4条回答
等我变得足够好
2楼-- · 2019-04-26 18:01

I had the same problem and after much hacking around came up with this:

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

inspect does the deep parsing that is missing from the other methods proposed and I end up with a hash that I can modify and pass around as needed.

查看更多
【Aperson】
3楼-- · 2019-04-26 18:09

after a resounding lack of answers both here and on the opscode chef mailing list, i ended up using the following 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

i put this into the libraries dir in my cookbook; now i can use attribute.to_hash in both chef 10 (which already worked properly and which is unaffected by this monkey-patch) and chef 11. i've also reported this as a bug to opscode:

if you don't want to have to monkey-patch your chef, speak up on this issue: http://tickets.opscode.com/browse/CHEF-3857

查看更多
4楼-- · 2019-04-26 18:14

The above answer is a little unnecessary. You can just do this:

json = node[:whatever][:whatever].to_hash.to_json
JSON.parse(json)
查看更多
对你真心纯属浪费
5楼-- · 2019-04-26 18:17

I hope I am not too late to the party but merging the node object with an empty hash did it for me:

chef (12.6.0)> {}.merge(node).class
 => Hash
查看更多
登录 后发表回答