Chef 11: any way to turn attributes into a hash ruby?

I am creating a configuration for my service in chef attributes. However, at some point I need to turn the mash attribute into a simple ruby ​​hash. This worked well in Chef 10:

node.myapp.config.to_hash 

However, starting with Chef 11, this will not work. Only the top level of the attribute is converted to a hash, and then the nested values ​​store immutable mash objects. Changing them leads to the following errors:

Chef :: Exceptions :: ImmutableAttributeModification ------------------------------------------- ----- Node attributes are read-only unless you specify which priority level to set. to set the attribute usage code, for example, `node.default [" key "] =" value "'

I tried a bunch of ways to get around this problem, which does not work:

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

A json parsing hack that seems to work fine will result in:

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

Is there any real reliable way, apart from the nested parsing function in each cookbook, to convert attributes into a simple, plain, old old ruby ​​hash code?

+8
source share
4 answers

after a complete lack of answers both here and on the opscode chef's mailing list, I used 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 it in the dir library in my cookbook; now I can use attribute.to_hash both for chef 10 (which already worked properly and is not affected by this monkey patch), and for chef 11. I also reported this as an error in opscode:

if you don’t want your chef to fix problems, talk about this: http://tickets.opscode.com/browse/CHEF-3857

Update: Monkey patch ticket is marked closed by these PR

+9
source

Hopefully I'm not late for the party, but merging the node object with an empty hash did this for me:

 chef (12.6.0)> {}.merge(node).class => Hash 
+4
source

I had the same problem, and after a lot of hacking, it came up with:

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

the check does a deep parsing that is not in the other proposed methods, and in the end I get a hash that I can modify and pass as needed.

+3
source

The above answer is a little redundant. You can simply do this:

 json = node[:whatever][:whatever].to_hash.to_json JSON.parse(json) 
-1
source

All Articles