Typically you’ll get an error that looks like this:
NoMethodError————-undefined method `[]’ for nil:NilClassCookbook Trace:—————/cookbooks/test/recipes/default.rb:15:in `from_file’Relevant File Content:———————-/cookbooks/test/recipes/default.rb:12:13: puts “JPM Recipe start”14: puts node[‘att1’]15>> puts node[‘att2’][‘att3’]16:
What just happened? Well, this recipe just referenced a sub-attribute (‘att3’) of a primary attribute (‘att2’) that never existed. So if no attributes exist at all, a call to:
node[‘attr1’]
simply returns nil. If you are unlucky enough to need this set, and didn’t check for it, then the recipe may still fail. The most disturbing case is when it is automatically transmuted to an empty string by code like this:
mypath = “#{node[‘base_path’]}/file.txt”
Now, this attribute which should have been set by a node-variable or an environment-variable goes unseen. And worse, because mypath becomes “/file.txt”, which is a perfectly valid path, the recipe may complete without error, but result in a completely invalid install.
In this case:
node[‘att2’][‘att3’]
becomes
nil[‘attr’]
which clearly fails because nil isn’t defined with the “[]” operator.
What should we do instead? You could always have better error checking. Clearly, the standard approach is input validation.
Chef does provide a helper function “attribute?” located here. But the standard ruby approach works for me. A attribute set like:
default[‘my_attrs’][‘firstname’]=”Jon”
default[‘my_attrs’][‘lastname’]=”Malachowski”
Could be generically verified:
raise “Attribute: my_attrs is not defined well” unless Hash === node[‘my_attrs’]
raise “Attribute: my_attrs->firstname is not defined well” unless String === node[‘my_attrs’][‘firstname’]
raise “Attribute: my_attrs->lastname is not defined well” unless String === node[‘my_attrs’][‘lastname’]
Until the robots take over,
Jonathan Malachowski