Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to check for the existence of a nested attribute in Chef?

There are multiple ways to check for the existence of a nested attribute in chef, and I'm not sure which is correct/best, and if any will result in empty attributes being stored on the node:

node[:parent] and node[:parent][:child]

node.attribute?(:parent) and node[:parent].attribute?(:child))

node[:parent].nil? and node[:parent][:child].nil?

It'd be greatly preferred to be able to check for the parent and child at the same time, but I don't know if that's possible. I am using Chef 10, not Chef 11, though answers explaining either are welcome.

like image 783
borntyping Avatar asked Sep 24 '13 15:09

borntyping


3 Answers

Node attribute object is HashMap. You can use ruby native API to lookup nested attributes.

Chef Node Object provides a number of helper methods like:

node.attribute?()
node[:foo].attribute?(:bar)
node[:foo].member?(:bar)

There is also a new method node.debug_value() in chef 11 to help you debug node attributes which is also helpful:

node.debug_value(:foo, :bar)

Details can be found from the article Chef 11 In-Depth: Attributes Changes

like image 115
shawnzhu Avatar answered Nov 15 '22 08:11

shawnzhu


The correct "modern" way to do this is to use the exist?() helper:

if node.exist?('foo', 'bar', 'baz')
  # do stuff with node['foo']['bar']['baz']
end

This supersedes the old chef-sugar deep_fetch mechanism and has been built into chef-client for a very long time at this point.

There is also a read() helper to get the value out, which will return nil if any intermediate key does not exist:

fizz = node.read('foo', 'bar', 'baz')

It is identical to the Hash#dig method which was later added to ruby which is also supported as an alias:

fizz = node.dig('foo', 'bar', 'baz')
like image 31
lamont Avatar answered Nov 15 '22 08:11

lamont


The way I've solved this more recently has been to always set default values for attributes used in a cookbook where possible.

For example, cookbook/attributes/default.rb would contain:

default[:parent][:child] = nil

And the in the recipe, any check for the attributes value can be reduced to:

node[:parent][:child].nil?

Of course, it's usually far more useful to have a usable default value and to not have to check at all.

like image 5
borntyping Avatar answered Nov 15 '22 08:11

borntyping