rubychef-infrachef-recipe

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.


Solution

  • 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')