Opscode
Home     Introduction to Chef     Cookbooks     Blog     GitHub     Tickets 

Attributes

Version 0.9.x+

This page is updated to reflect the latest changes in the ways that attributes are used, per ticket CHEF-838, which was a major change in Chef 0.9.0+.

Attributes are node data which describe various information about the node such as the IP address, hostname, loaded kernel modules, version of programming languages available on the system and more. New attributes can be dynamically added to the node in a variety of ways.

Node attributes are persisted between Chef runs when using Chef Client with a Chef Server. They are also indexed and searchable. All the attributes added to the node in the variety of ways they can be set are saved during the chef run. When Chef runs again, it will retrieve the attributes that were saved previously and merge in attributes per the priority rules described below.

Attribute Type and Precedence


Attributes in Chef nodes are comprised of three types of attributes in order of precedence, highest to lowest.

  • override
  • normal
  • default

These levels are available so you can write your cookbooks with sane defaults, but still use role-specific or node-specific data as necessary.

A fourth type is also available: automatic. Automatic attributes are where data from ohai are stored, and have the highest precedence. Chef doesn't provide any way to modify automatic attributes because any modifications you make will be overwritten with ohai data again on the next run.

Attributes are a special key-value store called a Mash within the Ruby DSL context, meaning the key can use either a Ruby symbol (:key) or a string ("key"). The keys are also auto-vivvified into methods, which we'll talk about in a moment.

Setting Attributes


The three levels of attributes that can be set have three places where they can be applied.

  • cookbook
  • role
  • node

Combining the level of priority described under the attribute types above and the places where attributes can be set, we derive this chart:

? ? Attributes File Role Recipe
Default 1 2 3
Normal 4 n/a 5
Override 6 7 8

According to this matrix, default attributes applied in an attributes file have the lowest priority and override attributes applied on a node directly in a recipe have the highest priority. Again, the exception to this are automatic attributes, as these are regenerated by Ohai every time Chef runs.

Cookbook Attributes

Cookbook attribute files are in the context of the Node object and use Node methods to set attribute values. Attributes files are in the attributes subdirectory of the cookbook. For example, here's an excerpt from Opscode's Apache cookbook:

cookbooks/apache2/attributes/default.rb

The use of the node object is implicit here. The following is exactly equivalent:

cookbooks/apache2/attributes/default.rb

Attributes can be set in a recipe as well, but node must be used.

Cookbook Attribute Methods

The following attributes are available to set Node attributes with in a cookbook's attributes file, or in a recipe. They correspond to the attribute type of the same name (set is an alias for normal).

  • override
  • default
  • normal (or set)

Additionally, there are _unless methods available as well, see the end of this document for information on setting attributes only if there isn't already a value.

Another handy method available related to attributes is the attribute? method. This will check for the existence of an attribute, so you can do processing in an attributes file or recipe only if a specific attribute exists.

attribute?() in attributes file
attribute?() in recipe

In the recipe, we need to use the method on the node object. In the attributes file, the node object is implicit. In either, we can also look for a sub-key of an attribute by chaining the attribute as methods:

attribute?() in recipe

Cookbook Attribute File Ordering

When Chef loads cookbook attribute files, it does so in alphabetical order for all the cookbooks. If you need to ensure that one attribute file is loaded before another (for example, if your Rails cookbook requires that the Apache attributes are available first) you can use the include_attribute method, like so:

include_attribute

This loads apache/attributes/default.rb before continuing the processing of the current attribute file.

The syntax for this follows the same "double colon" pattern as include_recipe, so a statement like:

include_attribute

This loads the attributes/tunables.rb file in a rails cookbook.

Auto-vivvication

Attributes are auto-vivvified into methods, and the method invocation can be used interchangeably with the keys. The following is the same as the usage above:

cookbooks/apache2/attributes/default.rb

This is a matter of style, and may be seen when "retrieving" the value of an attribute.

Role Attributes

Roles can only set default and override attributes, they cannot set normal attributes. This is done with the default_attributes and override_attributes methods in a Role's Ruby DSL file, or the default_attributes and override_attributes hashes in the Role's JSON data. It is common to assign attributes that pertain to a particular role. For example, a php_apache2_server role might use different tuning parameters for the same apache attributes than a mod_perl_apache2_server.

Node Attributes

Finally, the node object can be modified directly to set the attributes. Typically, this is going to be setting the attributes at the normal priority level, and can be done by editing the node with knife or through the WebUI, or passing JSON data to the node.

JSON Attributes

You can also specify attributes to use on a node with a JSON file. These are applied at the normal priority level.

For example, to set up some different ports for Apache to listen on:

JSON attribute example

How to Use Attributes


Good candidates for Attributes are:

  • Cross-Platform abstractions for an application such as the path to a config file.
  • Default values for "tunable" settings such as memory assigned to processes or number of workers to spawn.
  • Anything else you want to make persistent between Chef runs.

Setting Attributes at the Same Precedence Level

A common use case is that you'll want to set default attributes in your cookbooks' attribute files, and also set the same default attributes (but with different values) using a role. In this scenario, the attributes set in the role will be deep merged on top of the attributes from the attributes file, so the attributes set by the role will win if there is a conflict.

Setting a Value Only If the Attribute Has No Value

In attribute files, you can also set a value only if no value is currently set for that attribute using the _unless variants of the attribute priority methods: default_unless, set_unless, and override_unless. These can be handy in some use cases, but be careful: when you use these methods, the attributes applied to your nodes will become out-of-sync with the values in your cookbooks whenever you update your cookbooks. This means that building a new node with an identical set of recipes and roles as an existing node could result in a different configuration--a problem that can be frustrating to debug. For this reason, you should avoid using the _unless methods whenever possible.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Aug 05

    Edmund Haselwanter says:

    there is a deep merge automatic attributes, right? e.g. if I set a node.ec2.myke...

    there is a deep merge automatic attributes, right? e.g. if I set a node.ec2.mykey attribute, in any of my cookbooks and I'm NOT running on ec2 the test node.attributes?(:ec2) will get semantically incorrect. right?


Copyright © 2009 Opscode, Inc. All Rights Reserved.