Odd node.default behavior

In a test recipe I’m trying to determine whether a node attribute was explicitly set and I’m seeing some odd behavior. Here is the code:
log "Resolved value before: #{node[‘mysql’][‘server_root_password’]}"
log "Default value: #{node.default[‘mysql’][‘server_root_password’]}"
log "Normal value: #{node.normal[‘mysql’][‘server_root_password’]}"
log “Resolved value after: #{node[‘mysql’][‘server_root_password’]}”

Here is the relevant log output:

[2014-08-12T19:19:15+00:00] INFO: Resolved value before: ilikerandompasswords
[2014-08-12T19:19:15+00:00] INFO: Default value: ilikerandompasswords
[2014-08-12T19:19:15+00:00] INFO: Normal value: {}
[2014-08-12T19:19:15+00:00] INFO: Resolved value after: {}

Note that the attribute value was not explicitly set and the “default” value is “ilikerandompasswords”.

It looks like the “default” node value for the attribute is overridden after reading the “normal” node value for the purposes of logging.

Note that I get the same behavior if I simply assign the “normal” value to a variable (and don’t log it), i.e.:

val = node.normal[‘mysql’][‘server_root_password’]

Is this behavior expected?

Thanks,

John

On Tuesday, August 12, 2014 at 12:32 PM, John Warren wrote:

In a test recipe I’m trying to determine whether a node attribute was explicitly set and I’m seeing some odd behavior. Here is the code:

log "Resolved value before: #{node['mysql']['server_root_password']}"
log "Default value: #{node.default['mysql']['server_root_password']}"
log "Normal value: #{node.normal['mysql']['server_root_password']}"
log "Resolved value after: #{node['mysql']['server_root_password']}"

Here is the relevant log output:

[2014-08-12T19:19:15+00:00] INFO: Resolved value before: ilikerandompasswords
[2014-08-12T19:19:15+00:00] INFO: Default value: ilikerandompasswords
[2014-08-12T19:19:15+00:00] INFO: Normal value: {}
[2014-08-12T19:19:15+00:00] INFO: Resolved value after: {}

Note that the attribute value was not explicitly set and the “default” value is “ilikerandompasswords”.

It looks like the “default” node value for the attribute is overridden after reading the “normal” node value for the purposes of logging.

Note that I get the same behavior if I simply assign the “normal” value to a variable (and don’t log it), i.e.:

val = node.normal['mysql']['server_root_password']

Is this behavior expected?

Thanks,

John

Yes, this is expected. It’s a trade-off of supporting “auto-vivification” of attributes. For example:

h = Hash.new
h[“foo”][“bar”] = “baz”

Is not valid in Ruby, you’d have to do:

h = Hash.new
h[“foo”] = Hash.new

h[“foo”][“bar”] = “baz”

Which is annoying.

So the way attributes work is that when you reference a specific precedence level, it’s assumed that you intend to set a new value, and unknown keys are set to new, empty Hash-like objects. (Code is here: https://github.com/opscode/chef/blob/ec0a273404b6485e134798fa417b678d496a6d8f/lib/chef/node/attribute_collections.rb#L92)

To peek at the values of attributes among the different precedence levels, use node.debug_value(), which is here: https://github.com/opscode/chef/blob/ec0a273404b6485e134798fa417b678d496a6d8f/lib/chef/node/attribute.rb#L212-238

HTH,

--
Daniel DeLeo