Chef::Rest to Chef::ServerAPI - attribute unwinding


#1

We recently upgraded from Chef client 12.2 to 12.8 and good deal of our backend automation broke with a change in the way the server api seems to handle node objects.

It seems that when using 12.2 and Chef::Rest API we received a node object with the attribute tree collapsed in terms of precedence type attributes already parsed. In simpler language we referenced attribute without their scope. node[‘macaddress’] rather than node[‘automatic’][‘macaddress’]

When we upgraded to 12.8 it seems that collapsing of the node object no longer happens and that we need to use scoped attributes. node[‘macaddress’] no longer is defined we need to use node[‘automatic’][‘macaddress’]

My questions are: (1) Is this expected behavior and (2) Is there a way/method use to perform attribute collapsing on the node object such that we do not have to know the scope of a particular attribute?

Thanks!

########
# 12.2 #
########

#!/opt/chef/embedded/bin/ruby

require 'chef'
Chef::Config.from_file("/var/lib/automator/.chef/knife.rb")
rest = Chef::Rest.new(Chef::Config[:chef_server_url])
node = rest.get_rest("/nodes/node001")
macaddress = node['macaddress']

########
# 12.8 #
########

#!/opt/chef/embedded/bin/ruby

require 'chef'
Chef::Config.from_file("/var/lib/automator/.chef/knife.rb")
rest = Chef::ServerAPI.new(Chef::Config[:chef_server_url])
node = rest.get_rest("/nodes/node001")
macaddress = node['automatic']['macaddress']

#2

Yeah, that’s sort of the point of the difference between those. The autoinflation by Chef::REST into the Chef::Node object uses the json_class from the rest response which creates terrible bugs and if the API wasn’t fully auth’d could create interesting attack vectors. That was 100% deliberately broken with a vengeance in the change from Chef::REST to Chef::ServerAPI.

You should either just use Chef::Node.load in 12.8 or else if you want to be backcompat, I think you can feed the hash from Chef::ServerAPI#get_rest into Chef::Node#json_create which will work on 12.2 as well (but will throw a deprecation warning on 12.8)


#3

Thanks for the quick response and explanation - Chef community support is just great!

Chef::Node.json_create(Chef::ServerAPI.new(Chef::Config[:chef_server_url]).get_rest("/nodes/noe001")) does what I need.


#4

you might be ultimately happier with something like:

node = if Chef::Node.repsond_to?(:load)
  Chef::Node.load("node001")
else
  Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("node001")
end

or use that long Chef::ServerAPI-based chain in the second clause.

the difference is that it gracefully will pick up the new API which will be more future-proof.


#5

Yes that is better - I now fully grok what you are talking about here. Thanks again