popularity
question
2

Overriding attributes referenced by other attributes

attributes
roles
overriding

I am having trouble understanding the proper way to define my recipe’s attributes and allow for certain ones to be overridden in roles. The classic example is where you have one attribute for the version of an external library and then another attribute that constructs a URL which references the first version attribute. Then, if the version number is overridden, the URL gets updated as well.
The problem is, setting an attribute in a role does not seem to affect other attributes that reference the changed attribute.

Example:

attributes/default.rb

default['noodle']['foo'] = "foo-version-1"
default['noodle']['bar'] = "bar-version-1"
default['noodle']['baz'] = "#{noodle['foo']} & #{noodle['bar']}"

recipes/default.rb

Chef::Log.info "NOODLE: Value for foo = #{node['noodle']['foo']}"
Chef::Log.info "NOODLE: Value for bar = #{node['noodle']['bar']}"
Chef::Log.info "NOODLE: Value for baz = #{node['noodle']['baz']}"

roles/noodle.rb

name 'noodle'
run_list(
  'recipe[noodle]'
)
default_attributes({
    :noodle => {
      :bar => 'bar-version-2'
    }
  })

chef-client run output

INFO: NOODLE: Value for foo = foo-version-1
INFO: NOODLE: Value for bar = bar-version-2
INFO: NOODLE: Value for baz = foo-version-1 & bar-version-1

Using ‘override_attributes’ instead of ‘default_attributes’ doesn’t make a difference:

name 'noodle'
run_list(
  'recipe[noodle]'
)
override_attributes({
    :noodle => {
      :bar => 'bar-version-2'
    }
  })

chef-client run output

INFO: NOODLE: Value for foo = foo-version-1
INFO: NOODLE: Value for bar = bar-version-2
INFO: NOODLE: Value for baz = foo-version-1 & bar-version-1

I have discovered that if I literally set one of those attributes on the node, it gets picked up.

Set node attribute with ‘knife node edit NODE’:

{
  ...
  "normal": {
    "noodle": {
      "foo": "foo-version-NODE"
    }
  },
  "run_list": [
    "role[noodle]"
  ]
}

Then a chef-client run shows:

INFO: NOODLE: Value for foo = foo-version-NODE
INFO: NOODLE: Value for bar = bar-version-2
INFO: NOODLE: Value for baz = foo-version-NODE & bar-version-1

Isn’t this what roles are for? I need to be able to manage attributes like this en masse and in source control (role files). There are several official cookbooks that are designed the same way such as java, couchdb, and munin so it seems like it should be supported somehow.

 
Answers: 1
2

The problem you are running into is the result of how attributes are loaded during a Chef run. In order to maintain the documented attribute precedence. Attributes from roles and environments are loaded after attribute files are loaded. Thus at the time you are accessing that attribute within the attribute file, the role has not yet been loaded.

We typically recommend that interactions between attributes (such as concatenation) are done inside recipes to ensure that the final attribute value is being used. However, this does sometime interfere with the most straightforward way to define your attributes.

Other then moving the interaction to a recipe, it is possible to force the role and environment attributes to be evaluated using the following at the top of your attribute file:

apply_expansion_attributes(expand!)

However, we do not typically recommend this as it ties your recipes to an particular implementation detail of the current version of Chef (which could easily change) and since it means that you may run into situations in which your chef client run is not applying attributes with the documented precedence.

Answered
Mar 08 '12 at 23:39
 

Thanks, Steven. I tried what you suggested above with apply_expansion_attributes but it did not seem to change anything. I even tried with various combinations of node.set and ‘normal’ versus ‘default’ but no improvement.
At this point, I agree with your recommendation about attribute interactions such as concatenation being done in recipes. That is the same suggestion I got from Sean Horn at Opscode (via support email). He referred me to this issue:
http://help.opscode.com/discussions/questions/245-dynamic-defaults-for-attributes

But, it sure would be nice to have some kind of attribute notation for string patterns with late-eval'ed node attribute values. Maybe I’ll explore that if I ever get some free time.

Mar 10 '12 at 17:10