Skip to end of metadata
Go to start of metadata

Overview

Attributes are Node data 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.

During the Chef run, the Chef Client saves these node attributes on the Chef Server where they are indexed for Search. When the Chef Client runs again, it will retrieve the attributes that were saved previously and merge in attributes based on the priority rules described below.

Attribute Type and Precedence

There are three types of attributes in order of precedence, highest to lowest.

  • override
  • normal
  • default

Write your cookbooks with default attributes, but override these with role-specific or node-specific values as necessary.

A fourth attribute type, automatic, contains Ohai data and has 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. Review Automatic Attributes for those reserved namespaces.

Attributes are a special key-value store called a Mash within the Ruby DSL context. A Mash is just a Hash where the key can be either a Ruby symbol (:key) or a string ("key"). The keys are also auto-vivified into accessor methods, which we'll talk about in a moment.




Attributes that Aren't
A number of pieces of data related to a node are methods rather than attributes. As such, they cannot be accessed using the syntax for attributes, but rather must be accessed as method. Important node methods include:

Attribute Persistence

At the beginning of each chef-client run, default, override, and automatic attributes are completely reset.
They are then rebuilt using the currently applicable cookbooks, recipes, roles, environment and Ohai data.
Thus, default and override attributes set in cookbook attribute files, roles, recipes, or environments will disappear once the recipe, role, or environment is removed from the node and chef-client is run on the node.

Normal attributes are not reset.
Rather, on each chef-client run, any new attributes passed to chef-client in a JSON file are merged with the existing normal attributes in the node's data(using Deep Merge).
This means that any normal attribute set in a recipe or cookbook attribute file will remain even after the cookbook or role has been removed from the node's run list.

Setting Attributes

Attributes may be set on the node from the following objects

  • cookbooks
  • environments (Chef 0.10.0 or above only)
  • roles
  • nodes

Precedence

The precedence of the attributes is as follows, from low to high:

  • default attributes applied in an attributes file
  • default attributes applied in an environment
  • default attributes applied in a role
  • default attributes applied on a node directly in a recipe
  • normal or set attributes applied in an attributes file
  • normal or set attributes applied on a node directly in a recipe
  • override attributes applied in an attributes file
  • override attributes applied in a role
  • override attributes applied in an environment
  • override attributes applied on a node directly in a recipe

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.

Write your cookbooks with default attributes, but override these with role-specific or node-specific values as necessary.
See examples here...

Again, the exception to this are automatic attributes. They have the highest precedence and may not be modified, as they are regenerated by Ohai every time Chef runs.

Notation

Attributes are a special key-value store called a Mash within the Ruby DSL context. A Mash is just a Hash where the key can be either a Ruby symbol (:key) or a string ("key"). It's easier to stick with string notation if you are just starting out with Chef and/or Ruby. This allows you to just "quote it", rather than also having to learn about special cases, name space overlap (and method_missing), character constraints, and escaping work at the beginning.

That way, by the time you may want to use symbols stylistically or contextually, you can learn to wield them with an existing base of knowledge. Our examples and detail on attributes use a string notation for that reason. If you already know your way around symbols in ruby, you may of course use them.

Cookbook Attributes

Cookbook attribute files are found in the attributes subdirectory of the cookbook. They are evaluated in the context of the Node object and Node methods are used to set attribute values.

e.g. from Opscode's Apache cookbook:

cookbooks/apache2/attributes/default.rb

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

cookbooks/apache2/attributes/default.rb

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

Cookbook Attribute Methods

Use the following methods within 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. See the end of this document for information on conditionally setting attributes

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.

Reloading Attribute Files From Recipes

Attributes sometimes depend on actions taken from within recipes, so it may be necessary to reload a given attribute from within a recipe. For example: if you have an attribute that reads firewall rules, and a recipe that installs a firewall package, the firewall attributes will not be set the first time you execute the cookbook. Since include_attribute is not available from inside recipes, you will need to manually reload your firewall::default attribute:

reloading attributes from recipes

Attribute Accessor Methods

Attribute accessor methods are automatically created and the method invocation can be used interchangeably with the keys. The following is equivalent to 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.

Environment Attributes

Environments can set default and override attributes.

This is done with the default_attributes and override_attributes methods (respectively) in an Environment's Ruby DSL file, or the default_attributes and override_attributes hashes in the Environment's JSON data. It is common to assign attributes that pertain to a particular environment. For example, the external load balancer's public DNS may be different in "production" than in "staging".

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 sets attributes at the normal priority level, and can be done by editing the node with knife or through the WebUI, or by passing JSON data to the node.

JSON Attributes

You can also specify node attributes 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

Remember, that attributes passed via JSON file are merged with those stored on node and actually there is no way to override them in that way, however if there is a conflict, attributes from JSON file will win with those stored on node.

Automatic Attributes

This fourth attribute type cannot be modified, as any modifications you make will be overwritten with Ohai data again on the next run.

How to Use Attributes

Good Candidates for Attributes
  • 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 may want to persist (in node data) between Chef runs.

Usage Best Practices

The general pattern for attributes precedence is that cookbooks and roles should be setting defaults.

  • If you need to change the values for a specific node, use, the normal attributes on the node.
  • Overrides are there so roles can force a certain value even if the node already has a value there.

There are certainly other ways to use it, but that is the pattern it was designed for.

Setting Attributes at the Same Precedence Level

A common use case is to set default attributes in a cookbook's 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. 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.






Chef Essentials


Automatic Attributes



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

    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?

  2. Sep 22, 2010

    Is there any way to UN-set an attribute?

    1. Mar 23, 2011

      In Chef 0.9.14+ you can use delete to remove an attribute.

  3. Oct 12, 2010

    Can I merge attributes? For example, if I want to build an auth.users.trusted hash that is populated by roles and nodes:

    role a
    auth.users.trusted => [ "bob" ]

    role b
    auth.users.trusted => [ "sue" ]

    node c
    auth.users.trusted => [ "armand" ]

    I want the recipe would have access to:

    auth.users.trusted => [ "bob" , "sue" , "armand" ]

    1. Nov 01, 2010

      Just use push, rather than assign

      role a
      auth.users.trusted.push("bob")

      role b
      auth.users.trusted.push("sue")

      etc...

    2. Nov 17, 2010

      Actually, arrays are handled by the deep merge as you have listed as long as the attributes in your role are override attributes. I believe if you were to instead use default attributes, only the attribute from the first role applied would appear and then only if it wasnt already set on the node by the recipe's attribute definitions (someone correct me if I'm wrong on this).

      1. Jun 19, 2011

        Maybe it's a different story when roles aren't involved, but I've been trying to deal with this for the sudo cookbook, and I didn't find that override operated this way.

        To explain, default was a set in the sudo cookbook, normal was set in another cookbook, and override was set in my vagrant_main cookbook. It seems that just the vagrant_main override worked (no array merge).

        I realize this isn't chef's issue, per se, but for anyone else, tried using chef.json.merge! in Vagrantfile, and couldn't deal with arrays either (just json object as a whole).

  4. Jan 26, 2011

    The precedence order given for attribute setting locations is rather confusing. Firstly, it doesn't specify whether it's ascending or descending, although this can be inferred from the subsequent table.

    More importantly, however, it's rather ambiguous and arguably contradicts the table, listing attributes set in "cookbooks" as having lowest precedence, and those set in "nodes" as having the highest. Yet in the table, nodes and recipes have the highest precedence, and it's just cookbook attributes files that have lowest precedence. Yet recipes are the main part of cookbooks, aren't they?

    Also, it might be helpful to note exactly how the attribute type and location precedences are combined; again, it was only by inference from the derived table that I could see that type precedence takes priority over location precedence.

    (I'm not editing the page because I'm a total newbie, and am purely going on the information here; can an experienced user confirm I'm not talking complete cobblers? )

  5. Jun 20, 2011

    Is there a way to access the value of a node attribute inside and attribute file? I would like to build up strings in the attribute file.

    I would like to do something like this but as far as I can tell it doesn't work if I override foo[:name] in the role. It always uses the value for foo[:name] from the attribute file, not from the override.

    If I remove the default for foo[:name] from the attribute file the value is empty even if its set in the role's override.

    I have also tried using node[:foo][:path] and that ends up as empty as well.

    1. Jul 07, 2011

      Hi Robert,

      You might want to try something like this instead:

      This should work, but you'll want to be careful about modifying this value from other resources such as a recipe and try to keep it fairly simple. This is because of the order Chef loads files: http://wiki.opscode.com/display/chef/Anatomy+of+a+Chef+Run

      It could be possible to set an attribute in a cookbook, and then try to read it a few lines later and for this to not be set to the final attribute. This is because the attributes are not fully converged until the end.