What is the correct way to check for the existence of a nested attribute in Chef?
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
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.
Check out the chef-sugar cookbook deep_fetch
extension that allows for safe references to deep attributes.
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')