About Attributes

[edit on GitHub]

An attribute is a specific detail about a node. Attributes are used by Chef Infra Client to understand:

  • The current state of the node
  • What the state of the node was at the end of the previous Chef Infra Client run
  • What the state of the node should be at the end of the current Chef Infra Client run

Attributes are defined by:

  • The state of the node itself
  • Attributes passed via JSON on the CLI
  • Cookbooks (in attribute files and/or recipes)
  • Roles
  • Environments
  • Policyfiles

During every Chef Infra Client run, Chef Infra Client builds the attribute list using:

  • Attributes passed via JSON on the CLI
  • Data about the node collected by [Ohai].
  • The node object that was saved to the Chef Infra Server at the end of the previous Chef Infra Client run.
  • The rebuilt node object from the current Chef Infra Client run, after it is updated for changes to cookbooks (attribute files and/or recipes), roles, and/or environments, and updated for any changes to the state of the node itself.

After the node object is rebuilt, all of the attributes are compared, and then the node is updated based on attribute precedence. At the end of every Chef Infra Client run, the node object that defines the current state of the node is uploaded to the Chef Infra Server so that it can be indexed for search.

So how does Chef Infra Client determine which value should be applied? Keep reading to learn more about how attributes work, including more about the types of attributes, where attributes are saved, and how Chef Infra Client chooses which attribute to apply.

Attribute Persistence

All attributes except for normal attributes are reset at the beginning of a Chef Infra Client run. Attributes set via chef-client -j with a JSON file have normal precedence and are persisted between Chef Infra Client runs. Chef Infra Client rebuilds these attributes using automatic attributes collected by Ohai at the beginning of each Chef Infra Client run, and then uses default and override attributes that are specified in cookbooks, roles, environments, and Policyfiles. All attributes are then merged and applied to the node according to attribute precedence. The attributes that were applied to the node are saved to the Chef Infra Server as part of the node object at the conclusion of each Chef Infra Client run.

Attribute Types

Chef Infra Client uses six types of attributes to determine the value that is applied to a node during a Chef Infra Client run. In addition, Chef Infra Client gathers attribute values from up to five locations. The combination of attribute types and sources makes up to 15 different competing values available during a Chef Infra Client run:

Attribute Type Description
default A default attribute is automatically reset at the start of every Chef Infra Client run and has the lowest attribute precedence. Use default attributes as often as possible in cookbooks.
force_default Use the force_default attribute to ensure that an attribute defined in a cookbook (by an attribute file or by a recipe) takes precedence over a default attribute set by a role or an environment.
normal A normal attribute is a setting that persists in the node object. A normal attribute has a higher attribute precedence than a default attribute.
override An override attribute is automatically reset at the start of every Chef Infra Client run and has a higher attribute precedence than default, force_default, and normal attributes. An override attribute is most often specified in a recipe, but can be specified in an attribute file, for a role, and/or for an environment. A cookbook should be authored so that it uses override attributes only when required.
force_override Use the force_override attribute to ensure that an attribute defined in a cookbook (by an attribute file or by a recipe) takes precedence over an override attribute set by a role or an environment.
automatic An automatic attribute contains data that is identified by Ohai at the beginning of every Chef Infra Client run. An automatic attribute cannot be modified and always has the highest attribute precedence.

Attribute Sources

Attributes are provided to Chef Infra Client from the following locations:

  • JSON files passed via the chef-client -j
  • Nodes (collected by Ohai at the start of each Chef Infra Client run)
  • Attribute files (in cookbooks)
  • Recipes (in cookbooks)
  • Environments
  • Roles
  • Policyfiles

Notes:

  • Many attributes are maintained in the chef-repo for Policyfiles, environments, roles, and cookbooks (attribute files and recipes)
  • Many attributes are collected by Ohai on each individual node at the start of every Chef Infra Client run
  • The attributes that are maintained in the chef-repo are uploaded to the Chef Infra Server from the workstation, periodically
  • Chef Infra Client will pull down the node object from the Chef Infra Server and then reset all the attributes except normal. The node object will contain the attribute data from the previous Chef Infra Client run including attributes set with JSON files via -j.
  • Chef Infra Client will update the cookbooks on the node (if required), which updates the attributes contained in attribute files and recipes
  • Chef Infra Client will update the role and environment data (if required)
  • Chef Infra Client will rebuild the attribute list and apply attribute precedence while configuring the node
  • Chef Infra Client pushes the node object to the Chef Infra Server at the end of a Chef Infra Client run; the updated node object on the Chef Infra Server is then indexed for search and is stored until the next Chef Infra Client run

Automatic (Ohai)

An automatic attribute is a specific detail about a node, such as an IP address, a host name, a list of loaded kernel modules, and so on. Automatic attributes are detected by Ohai and are then used by Chef Infra Client to ensure that they are handled properly during every Chef Infra Client run. The most commonly accessed automatic attributes are:

Attribute Description
node['platform'] The platform on which a node is running. This attribute helps determine which providers will be used.
node['platform_family'] The platform family is a Chef Infra specific grouping of similar platforms where cookbook code can often be shared. For example `rhel` includes Red Hat Linux, Oracle Linux, CentOS, and several other platforms that are nearly identical to Red Hat Linux.
node['platform_version'] The version of the platform. This attribute helps determine which providers will be used.
node['ipaddress'] The IP address for a node. If the node has a default route, this is the IPV4 address for the interface. If the node does not have a default route, the value for this attribute should be nil. The IP address for default route is the recommended default value.
node['macaddress'] The MAC address for a node, determined by the same interface that detects the node['ipaddress'].
node['fqdn'] The fully qualified domain name for a node. This is used as the name of a node unless otherwise set.
node['hostname'] The host name for the node.
node['domain'] The domain for the node.
node['recipes'] A list of recipes associated with a node (and part of that node's run-list).
node['roles'] A list of roles associated with a node (and part of that node's run-list).
node['ohai_time'] The time at which Ohai was last run. This attribute is not commonly used in recipes, but it is saved to the Chef Infra Server and can be accessed using the knife status subcommand.

Ohai collects a list of automatic attributes at the start of each Chef Infra Client run. This list will vary from organization to organization, by server type, and by the platform that runs those servers. All the attributes collected by Ohai are unmodifiable by Chef Infra Client. Run the ohai command on a system to see which automatic attributes Ohai has collected for a particular node.

Attribute Files

An attribute file is located in the attributes/ sub-directory for a cookbook. When a cookbook is run against a node, the attributes contained in all attribute files are evaluated in the context of the node object. Node methods (when present) are used to set attribute values on a node. For example, the apache2 cookbook contains an attribute file called default.rb, which contains the following attributes:

default['apache']['dir']          = '/etc/apache2'
default['apache']['listen_ports'] = [ '80','443' ]

The use of the node object (node) is implicit in the previous example; the following example defines the node object itself as part of the attribute:

node.default['apache']['dir']          = '/etc/apache2'
node.default['apache']['listen_ports'] = [ '80','443' ]

Attribute Evaluation Order

Chef Infra Client evaluates attributes in the order defined by the run-list, including any attributes that are in the run-list because of cookbook dependencies.

Use Attribute Files

An attribute is a specific detail about a node, such as an IP address, a host name, a list of loaded kernel modules, the version(s) of available programming languages that are available, and so on. An attribute may be unique to a specific node or it can be identical across every node in the organization. Attributes are most commonly set from a cookbook, by using knife, or are retrieved by Ohai from each node prior to every Chef Infra Client run. All attributes are indexed for search on the Chef Infra Server. Good candidates for attributes include:

  • any cross-platform abstraction for an application, such as the path to a configuration file
  • default values for tunable settings, such as the amount of memory assigned to a process or the number of workers to spawn
  • anything that may need to be persisted in node data between Chef Infra Client runs

In general, attribute precedence is set to enable cookbooks and roles to define attribute defaults, for normal attributes to define the values that should be specific for a node, and for override attributes to force a certain value, even when a node already has that value specified.

One approach is to set attributes at the same precedence level by setting attributes in a cookbook’s attribute files, and then also setting the same default attributes (but with different values) using a role. The attributes set in the role will be deep merged on top of the attributes from the attribute file, and the attributes set by the role will take precedence over the attributes specified in the cookbook’s attribute files.

Another (much less common) approach is to set a value only if an attribute has no value. This can be done by using the _unless variants of the attribute priority methods:

  • default_unless
  • normal_unless

Use the _unless variants carefully (and only when necessary) because when they are used, attributes applied to nodes may become out of sync with the values in the cookbooks as these cookbooks are updated. This approach can create situations where two otherwise identical nodes end up having slightly different configurations and can also be a challenge to debug.

File Methods

Use the following methods within the attributes file for a cookbook or within a recipe. These methods correspond to the attribute type of the same name:

  • override
  • default
  • normal
  • _unless

attribute?

A useful method that is related to attributes is the attribute? method. This method will check for the existence of an attribute, so that processing can be done in an attributes file or recipe, but only if a specific attribute exists.

Using attribute?() in an attributes file:

if attribute?('ec2')
  # ... set stuff related to EC2
end

Using attribute?() in a recipe:

if node.attribute?('ec2')
  # ... do stuff on EC2 nodes
end

Recipes

A recipe is the most fundamental configuration element within the organization. A recipe:

  • Is authored using Ruby, which is a programming language designed to read and behave in a predictable manner
  • Is mostly a collection of resources, defined using patterns (resource names, attribute-value pairs, and actions); helper code is added around this using Ruby, when needed
  • Must define everything that is required to configure part of a system
  • Must be stored in a cookbook
  • May be included in another recipe
  • May use the results of a search query and read the contents of a data bag (including an encrypted data bag)
  • May have a dependency on one (or more) recipes
  • Must be added to a run-list before it can be used by Chef Infra Client
  • Is always executed in the same order as listed in a run-list

An attribute can be defined in a cookbook (or a recipe) and then used to override the default settings on a node. When a cookbook is loaded during a Chef Infra Client run, these attributes are compared to the attributes that are already present on the node. Attributes that are defined in attribute files are first loaded according to cookbook order. For each cookbook, attributes in the default.rb file are loaded first, and then additional attribute files (if present) are loaded in lexical sort order. When the cookbook attributes take precedence over the default attributes, Chef Infra Client applies those new settings and values during a Chef Infra Client run on the node.

Roles

A role is a way to define certain patterns and processes that exist across nodes in an organization as belonging to a single job function. Each role consists of zero (or more) attributes and a run-list. Each node can have zero (or more) roles assigned to it. When a role is run against a node, the configuration details of that node are compared against the attributes of the role, and then the contents of that role’s run-list are applied to the node’s configuration details. When a Chef Infra Client runs, it merges its own attributes and run-lists with those contained within each assigned role.

An attribute can be defined in a role and then used to override the default settings on a node. When a role is applied during a Chef Infra Client run, these attributes are compared to the attributes that are already present on the node. When the role attributes take precedence over the default attributes, Chef Infra Client applies those new settings and values during a Chef Infra Client run.

A role attribute can only be set to be a default attribute or an override attribute. A role attribute cannot be set to be a normal attribute. Use the default_attribute and override_attribute methods in the Ruby DSL file or the default_attributes and override_attributes hashes in a JSON data file.

Environments

An environment is a way to map an organization’s real-life workflow to what can be configured and managed when using Chef Infra. This mapping is accomplished by setting attributes and pinning cookbooks at the environment level. With environments, you can change cookbook configurations depending on the system’s designation. For example, by designating different staging and production environments, you can then define the correct URL of a database server for each environment. Environments also allow organizations to move new cookbook releases from staging to production with confidence by stepping releases through testing environments before entering production.

Attributes can be defined in an environment and then used to override the default attributes in a cookbook. When an environment is applied during a Chef Infra Client run, environment attributes are compared to the attributes that are already present on the node. When the environment attributes take precedence over the default attributes, Chef Infra Client applies those new settings and values during a Chef Infra Client run.

Environment attributes can be set to either default attribute level or an override attribute level.

Attribute Precedence

Attributes are always applied by Chef Infra Client in the following order:

  1. A default attribute located in a cookbook attribute file
  2. A default attribute located in a recipe
  3. A default attribute located in an environment
  4. A default attribute located in a role
  5. A force_default attribute located in a cookbook attribute file
  6. A force_default attribute located in a recipe
  7. A normal attribute located in a JSON file passed via chef-client -j
  8. A normal attribute located in a cookbook attribute file
  9. A normal attribute located in a recipe
  10. An override attribute located in a cookbook attribute file
  11. An override attribute located in a recipe
  12. An override attribute located in a role
  13. An override attribute located in an environment
  14. A force_override attribute located in a cookbook attribute file
  15. A force_override attribute located in a recipe
  16. An automatic attribute identified by Ohai at the start of a Chef Infra Client run

where the last attribute in the list is the one that is applied to the node.

Note

The attribute precedence order for roles and environments is reversed for default and override attributes. The precedence order for default attributes is environment, then role. The precedence order for override attributes is role, then environment. Applying environment override attributes after role override attributes allows the same role to be used across multiple environments, yet ensuring that values can be set that are specific to each environment (when required). For example, the role for an application server may exist in all environments, yet one environment may use a database server that is different from other environments.

Attribute precedence, viewed from the same perspective as the overview diagram, where the numbers in the diagram match the order of attribute precedence:

image

Attribute precedence, when viewed as a table:

image

Examples

The following examples are listed from low to high precedence.

Default attribute in /attributes/default.rb

default['apache']['dir'] = '/etc/apache2'

Default attribute in node object in recipe

node.default['apache']['dir'] = '/etc/apache2'

Default attribute in /environments/environment_name.rb

default_attributes({ 'apache' => {'dir' => '/etc/apache2'}})

Default attribute in /roles/role_name.rb

default_attributes({ 'apache' => {'dir' => '/etc/apache2'}})

Normal attribute set as a cookbook attribute

set['apache']['dir'] = '/etc/apache2'
normal['apache']['dir'] = '/etc/apache2'  #set is an alias of normal.

Normal attribute set in a recipe

node.normal['apache']['dir'] = '/etc/apache2'

Override attribute in /attributes/default.rb

override['apache']['dir'] = '/etc/apache2'

Override attribute in /roles/role_name.rb

override_attributes({ 'apache' => {'dir' => '/etc/apache2'}})

Override attribute in /environments/environment_name.rb

override_attributes({ 'apache' => {'dir' => '/etc/apache2'}})

Override attribute in a node object (from a recipe)

node.override['apache']['dir'] = '/etc/apache2'

Ensure that a default attribute has precedence over other attributes

When a default attribute is set like this:

default['attribute'] = 'value'

any value set by a role or an environment will replace it. To prevent this value from being replaced, use the force_default attribute precedence:

force_default['attribute'] = 'I will crush you, role or environment attribute'

or:

default!['attribute'] = "The '!' means I win!"

Ensure that an override attribute has precedence over other attributes

When an override attribute is set like this:

override['attribute'] = 'value'

any value set by a role or an environment will replace it. To prevent this value from being replaced, use the force_override attribute precedence:

force_override['attribute'] = 'I will crush you, role or environment attribute'

or:

override!['attribute'] = "The '!' means I win!"

Change Attributes

Attribute precedence levels may be:

  • Removed for a specific, named attribute precedence level.
  • Removed for all attribute precedence levels.
  • Fully assigned attributes.

Remove Precedence Level

A specific attribute precedence level for default, normal, and override attributes may be removed by using one of the following syntax patterns.

For default attributes:

  • node.rm_default('foo', 'bar')

For normal attributes:

  • node.rm_normal('foo', 'bar')

For override attributes:

  • node.rm_override('foo', 'bar')

These patterns return the computed value of the key being deleted for the specified precedence level.

Examples

The following examples show how to remove a specific, named attribute precedence level.

Delete a default value when only default values exist

Given the following code structure under 'foo':

node.default['foo'] = {
  'bar' => {
    'baz' => 52,
    'thing' => 'stuff',
  },
  'bat' => {
    'things' => [5, 6],
  },
}

And some role attributes:

# Please don't ever do this in real code :)
node.role_default['foo']['bar']['thing'] = 'otherstuff'

And a force attribute:

node.force_default['foo']['bar']['thing'] = 'allthestuff'

When the default attribute precedence node['foo']['bar'] is removed:

node.rm_default('foo', 'bar') #=> {'baz' => 52, 'thing' => 'allthestuff'}

What is left under 'foo' is only 'bat':

node.attributes.combined_default['foo'] #=> {'bat' => { 'things' => [5,6] } }

Delete default without touching higher precedence attributes

Given the following code structure:

node.default['foo'] = {
  'bar' => {
    'baz' => 52,
    'thing' => 'stuff',
  },
  'bat' => {
    'things' => [5, 6],
  },
}

And some role attributes:

# Please don't ever do this in real code :)
node.role_default['foo']['bar']['thing'] = 'otherstuff'

And a force attribute:

node.force_default['foo']['bar']['thing'] = 'allthestuff'

And also some override attributes:

node.override['foo']['bar']['baz'] = 99

Same delete as before:

node.rm_default('foo', 'bar') #=> { 'baz' => 52, 'thing' => 'allthestuff' }

The other attribute precedence levels are unaffected:

node.attributes.combined_override['foo'] #=> { 'bar' => {'baz' => 99} }
node['foo'] #=> { 'bar' => {'baz' => 99}, 'bat' => { 'things' => [5,6] }

Delete override without touching lower precedence attributes

Given the following code structure, which has an override attribute:

node.override['foo'] = {
  'bar' => {
    'baz' => 52,
    'thing' => 'stuff',
  },
  'bat' => {
    'things' => [5, 6],
  },
}

with a single default value:

node.default['foo']['bar']['baz'] = 11

and a force at each attribute precedence:

node.force_default['foo']['bar']['baz'] = 55
node.force_override['foo']['bar']['baz'] = 99

Delete the override:

node.rm_override('foo', 'bar') #=> { 'baz' => 99, 'thing' => 'stuff' }

The other attribute precedence levels are unaffected:

node.attributes.combined_default['foo'] #=> { 'bar' => {'baz' => 55} }

Non-existent key deletes return nil

node.rm_default("no", "such", "thing") #=> nil

Remove All Levels

All attribute precedence levels may be removed by using the following syntax pattern:

  • node.rm('foo', 'bar')

Note

Using node['foo'].delete('bar') will throw an exception that points to the new API.

Examples

The following examples show how to remove all attribute precedence levels.

Delete all attribute precedence levels

Given the following code structure:

node.default['foo'] = {
  'bar' => {
    'baz' => 52,
    'thing' => 'stuff',
  },
  'bat' => {
    'things' => [5, 6],
  },
}

With override attributes:

node.override['foo']['bar']['baz'] = 999

Removing the 'bar' key returns the computed value:

node.rm('foo', 'bar') #=> {'baz' => 999, 'thing' => 'stuff'}

Looking at 'foo', all that’s left is the 'bat' entry:

node['foo'] #=> {'bat' => { 'things' => [5,6] } }

Non-existent key deletes return nil

node.rm_default("no", "such", "thing") #=> nil

Full Assignment

Use ! to clear out the key for the named attribute precedence level, and then complete the write by using one of the following syntax patterns:

  • node.default!['foo']['bar'] = {...}
  • node.force_default!['foo']['bar'] = {...}
  • node.normal!['foo']['bar'] = {...}
  • node.override!['foo']['bar'] = {...}
  • node.force_override!['foo']['bar'] = {...}

Examples

The following examples show how to remove all attribute precedence levels.

Just one component

Given the following code structure:

node.default['foo']['bar'] = {'a' => 'b'}
node.default!['foo']['bar'] = {'c' => 'd'}

The '!' caused the entire ‘bar’ key to be overwritten:

node['foo'] #=> {'bar' => {'c' => 'd'}

Multiple components; one “after”

Given the following code structure:

node.default['foo']['bar'] = {'a' => 'b'}
# Please don't ever do this in real code :)
node.role_default['foo']['bar'] = {'c' => 'd'}
node.default!['foo']['bar'] = {'d' => 'e'}

The '!' write overwrote the “cookbook-default” value of 'bar', but since role data is later in the resolution list, it was unaffected:

node['foo'] #=> {'bar' => {'c' => 'd', 'd' => 'e'}

Multiple components; all “before”

Given the following code structure:

node.default['foo']['bar'] = {'a' => 'b'}
# Please don't ever do this in real code :)
node.role_default['foo']['bar'] = {'c' => 'd'}
node.force_default!['foo']['bar'] = {'d' => 'e'}

With force_default! there is no other data under 'bar':

node['foo'] #=> {'bar' => {'d' => 'e'}

Multiple precedence levels

Given the following code structure:

node.default['foo'] = {
  'bar' => {
    'baz' => 52,
    'thing' => 'stuff',
  },
  'bat' => {
   'things' => [5, 6],
  },
}

And some attributes:

# Please don't ever do this in real code :)
node.role_default['foo']['bar']['baz'] = 55
node.force_default['foo']['bar']['baz'] = 66

And other precedence levels:

node.normal['foo']['bar']['baz'] = 88
node.override['foo']['bar']['baz'] = 99

With a full assignment:

node.default!['foo']['bar'] = {}

Role default and force default are left in default, plus other precedence levels:

node.attributes.combined_default['foo'] #=> {'bar' => {'baz' => 66}, 'bat'=>{'things'=>[5, 6]}}
node.attributes.normal['foo'] #=> {'bar' => {'baz' => 88}}
node.attributes.combined_override['foo'] #=> {'bar' => {'baz' => 99}}
node['foo']['bar'] #=> {'baz' => 99}

If force_default! is written:

node.force_default!['foo']['bar'] = {}

the difference is:

node.attributes.combined_default['foo'] #=> {'bat'=>{'things'=>[5, 6]}, 'bar' => {}}
node.attributes.normal['foo'] #=> {'bar' => {'baz' => 88}}
node.attributes.combined_override['foo'] #=> {'bar' => {'baz' => 99}}
node['foo']['bar'] #=> {'baz' => 99}

About Deep Merge

Attributes are typically defined in cookbooks, recipes, roles, and environments. These attributes are rolled-up to the node level during a Chef Infra Client run. A recipe can store attribute values using a multi-level hash or array.

For example, a group of attributes for web servers might be:

override_attributes(
  :apache => {
    :listen_ports => [ 80 ],
    :prefork => {
      :startservers => 20,
      :minspareservers => 20,
      :maxspareservers => 40
    }
  }
)

But what if all of the web servers are not the same? What if some of the web servers required a single attribute to have a different value? You could store these settings in two locations, once just like the preceding example and once just like the following:

override_attributes(
  :apache => {
    :listen_ports => [ 80 ],
    :prefork => {
      :startservers => 30,
      :minspareservers => 20,
      :maxspareservers => 40
    }
  }
)

But that is not very efficient, especially because most of them are identical. The deep merge capabilities of Chef Infra Client allows attributes to be layered across cookbooks, recipes, roles, and environments. This allows an attribute to be reused across nodes, making use of default attributes set at the cookbook level, but also providing a way for certain attributes (with a higher attribute precedence) to be applied only when they are supposed to be.

For example, a role named baseline.rb:

name "baseline"
description "The most basic role for all configurations"
run_list "recipe[baseline]"

override_attributes(
  :apache => {
    :listen_ports => [ 80 ],
    :prefork => {
      :startservers => 20,
      :minspareservers => 20,
      :maxspareservers => 40
    }
  }
)

and then a role named web.rb:

name 'web'
description 'Web server config'
run_list 'role[baseline]'

override_attributes(
  :apache => {
    :prefork => {
      :startservers => 30
    }
  }
)

Both of these files are similar because they share the same structure. When an attribute value is a hash, that data is merged. When an attribute value is an array, if the attribute precedence levels are the same, then that data is merged. If the attribute value precedence levels in an array are different, then that data is replaced. For all other value types (such as strings, integers, etc.), that data is replaced.

For example, the web.rb references the baseline.rb role. The web.rb file only provides a value for one attribute: :startservers. When Chef Infra Client compares these attributes, the deep merge feature will ensure that :startservers (and its value of 30) will be applied to any node for which the web.rb attribute structure should be applied.

This approach will allow a recipe like this:

include_recipe 'apache2'
Chef::Log.info(node['apache']['prefork'].to_hash)

and a run_list like this:

run_list/web.json
{
  "run_list": [ "role[web]" ]
}

to produce results like this:

[Tue, 16 Aug 2011 14:44:26 -0700] INFO:
         {
           "startservers"=>30,
           "minspareservers"=>20,
           "maxspareservers"=>40,
           "serverlimit"=>400,
           "maxclients"=>400,
           "maxrequestsperchild"=>10000
         }

Even though the web.rb file does not contain attributes and values for minspareservers, maxspareservers, serverlimit, maxclients, and maxrequestsperchild, the deep merge capabilities pulled them in.

The following sections show how the logic works for using deep merge to perform substitutions and additions of attributes.

Substitution

The following examples show how the logic works for substituting an existing string using a hash:

role_or_environment 1 { :x => '1', :y => '2' }
+
role_or_environment 2 { :y => '3' }
=
{ :x => '1', :y => '3' }

For substituting an existing boolean using a hash:

role_or_environment 1 { :x => true, :y => false }
+
role_or_environment 2 { :y => true }
=
{ :x => true, :y => true }

For substituting an array with a hash:

role_or_environment 1 [ '1', '2', '3' ]
+
role_or_environment 2 { :x => '1' , :y => '2' }
=
{ :x => '1', :y => '2' }

When items cannot be merged through substitution, the original data is overwritten.

Addition

The following examples show how the logic works for adding a string using a hash:

role_or_environment 1 { :x => '1', :y => '2' }
+
role_or_environment 2 { :z => '3' }
=
{ :x => '1', :y => '2', :z => '3' }

For adding a string using an array:

role_or_environment 1 [ '1', '2' ]
+
role_or_environment 2 [ '3' ]
=
[ '1', '2', '3' ]

For adding a string using a multi-level hash:

role_or_environment 1 { :x => { :y => '2' } }
+
role_or_environment 2 { :x => { :z => '3' } }
=
{ :x => { :y => '2', :z => '3' } }

For adding a string using a multi-level array:

role_or_environment 1 [ [ 1, 2 ] ]
+
role_or_environment 2 [ [ 3 ] ]
=
[ [ 1, 2 ], [ 3 ] ]

Limiting Attribute Persistence

Some organizations find it helpful to control attribute data stored to the Chef Infra Server in order to limit the disk and CPU resources used when processing unused attributes. For example, your organization may find the data from the Ohai Package plugin useful when writing cookbooks, but you don’t see the need in saving ~100k of package information for each Chef Infra Client run. By limiting the data that is saved to the Chef Infra Server, it will still be available on the node within cookbooks, but won’t be saved to the Chef Infra Server where it is available in searches.

Note

In Chef Infra Client 16.3 the node Blacklist and Whitelist features were renamed to Blocklist and Allowlist. For backwards compatibility the old configuration values will continue to work, but this document will describe the Blocklist and Allowlist names. See each section below for the appropriate legacy configuration values if you are running legacy clients in your organization.

Legacy config mapping:

  • automatic_attribute_blacklist -> blocked_automatic_attributes
  • default_attribute_blacklist -> blocked_default_attributes
  • normal_attribute_blacklist -> blocked_normal_attributes
  • override_attribute_blacklist -> blocked_override_attributes
  • automatic_attribute_whitelist -> allowed_automatic_attributes
  • default_attribute_whitelist -> allowed_default_attributes
  • normal_attribute_whitelist -> allowed_normal_attributes
  • override_attribute_whitelist -> allowed_override_attributes
  • enforce_path_sanity -> enforce_default_paths

Attributes Blocklist

Warning

When attribute blocklist settings are used, any attribute defined in a blocklist will not be saved to the Chef Infra Server and any attribute that is not defined in a blocklist will be saved. Each attribute type must be blocklisted independently of the other attribute types. For example, if blocked_automatic_attributes defines attributes that will not be saved, but blocked_normal_attributes, blocked_default_attributes, and blocked_override_attributes are not defined, then all normal attributes, default attributes, and override attributes will be saved, as well as the automatic attributes that were not specifically excluded through blocklisting.

Attributes that should not be saved by a node may be blocklisted in the client.rb file. The blocklist is a Hash of keys that specify each attribute to be filtered out.

Attributes are blocklisted by attribute type, with each attribute type being blocklisted independently. Each attribute type—automatic, default, normal, and override—may define blocklists by using the following settings in the client.rb file:

Setting Description
blocked_automatic_attributes A hash that blocklists automatic attributes, preventing blocklisted attributes from being saved. For example: ['network/interfaces/eth0']. Default value: nil, all attributes are saved. If the array is empty, all attributes are saved.
blocked_default_attributes A hash that blocklists default attributes, preventing blocklisted attributes from being saved. For example: ['filesystem/dev/disk0s2/size']. Default value: nil, all attributes are saved. If the array is empty, all attributes are saved.
blocked_normal_attributes A hash that blocklists normal attributes, preventing blocklisted attributes from being saved. For example: ['filesystem/dev/disk0s2/size']. Default value: nil, all attributes are saved. If the array is empty, all attributes are saved.
blocked_override_attributes A hash that blocklists override attributes, preventing blocklisted attributes from being saved. For example: ['map - autohome/size']. Default value: nil, all attributes are saved. If the array is empty, all attributes are saved.

Blocklisting Ohai (automatic) Attributes

The recommended practice is to use blocked_automatic_attributes to block attributes populated by Ohai’s system information gathering. Ohai gathers a large number of attributes that can consume a signicant amount of storage space on the Chef Infra Server. Many of these attributes may be considered highly valuable, while others could be blocklisted without any impact to data available in search. Normal, default, and override attributes are typically much more important attributes used within cookbooks and are more likely to cause issues if they are blocklisted incorrectly.

For example, automatic attribute data similar to:

{
  "filesystem" => {
    "/dev/disk0s2" => {
      "size" => "10mb"
    },
    "map - autohome" => {
      "size" => "10mb"
    }
  },
  "network" => {
    "interfaces" => {
      "eth0" => {...},
      "eth1" => {...},
    }
  }
}

To blocklist the filesystem attributes and allow the other attributes to be saved, update the client.rb file:

blocked_automatic_attributes ['filesystem']

When a blocklist is defined, any attribute of that type that is not specified in that attribute blocklist will be saved. So based on the previous blocklist for automatic attributes, the filesystem and map - autohome attributes will not be saved, but the network attributes will.

For attributes that contain slashes (/) within the attribute value, such as the filesystem attribute '/dev/diskos2', use an array. For

example:

blocked_automatic_attributes [['filesystem', '/dev/diskos2']]

Attribute Allowlist

Warning

When attribute allowlist settings are used, only the attributes defined in a allowlist will be saved and any attribute that is not defined in a allowlist will not be saved. Each attribute type is allowlisted independently of the other attribute types. For example, if automatic_attribute_allowlist defines attributes to be saved, but normal_attribute_allowlist, default_attribute_allowlist, and override_attribute_allowlist are not defined, then all normal attributes, default attributes, and override attributes are saved, as well as the automatic attributes that were specifically included through allowlisting.

Attributes that should be saved by a node may be allowlisted in the client.rb file. The allowlist is a hash of keys that specifies each attribute to be saved.

Attributes are allowlisted by attribute type, with each attribute type being allowlisted independently. Each attribute type—automatic, default, normal, and override—may define allowlists by using the following settings in the client.rb file:

Setting Description
allowed_automatic_attributes A hash that allowlists automatic attributes, preventing non-allowlisted attributes from being saved. For example: ['network/interfaces/eth0']. Default value: nil, all attributes are saved. If the hash is empty, no attributes are saved.
allowed_default_attributes A hash that allowlists default attributes, preventing non-allowlisted attributes from being saved. For example: ['filesystem/dev/disk0s2/size']. Default value: nil, all attributes are saved. If the hash is empty, no attributes are saved.
allowed_normal_attributes A hash that allowlists normal attributes, preventing non-allowlisted attributes from being saved. For example: ['filesystem/dev/disk0s2/size']. Default value: nil, all attributes are saved. If the hash is empty, no attributes are saved.
allowed_override_attributes A hash that allowlists override attributes, preventing non-allowlisted attributes from being saved. For example: ['map - autohome/size']. Default value: nil, all attributes are saved. If the hash is empty, no attributes are saved.

Allowlisting Ohai (automatic) Attributes

The recommended practice is to use allowed_automatic_attributes to allow specific attributes populated by Ohai’s system information gathering. Ohai gathers a large number of attributes that can consume a signicant amount of storage space on the Chef Infra Server. Many of these attributes may be considered highly valuable, while others could be skipped without any impact to data available in search. Normal, default, and override attributes are typically much more important attributes used within cookbooks and are more likely to cause issues if they are ommited from an allowlist incorrectly.

For example, automatic attribute data similar to:

{
  "filesystem" => {
    "/dev/disk0s2" => {
      "size" => "10mb"
    },
    "map - autohome" => {
      "size" => "10mb"
    }
  },
  "network" => {
    "interfaces" => {
      "eth0" => {...},
      "eth1" => {...},
    }
  }
}

To allowlist the network attributes and prevent the other attributes from being saved, update the client.rb file:

allowed_automatic_attributes ['network/interfaces/']

When a allowlist is defined, any attribute of that type that is not specified in that attribute allowlist will not be saved. So based on the previous allowlist for automatic attributes, the filesystem and map - autohome attributes will not be saved, but the network attributes will.

Leave the value empty to prevent all attributes of that attribute type from being saved:

allowed_automatic_attributes []

For attributes that contain slashes (/) within the attribute value, such as the filesystem attribute '/dev/diskos2', use an array. For example:

allowed_automatic_attributes [['filesystem', '/dev/diskos2']]

© Chef Software, Inc.
Licensed under the Creative Commons Attribution 3.0 Unported License.
The Chef™ Mark and Chef Logo are either registered trademarks/service marks or trademarks/servicemarks of Chef, in the United States and other countries and are used with Chef Inc's permission.
We are not affiliated with, endorsed or sponsored by Chef Inc.
https://docs.chef.io/attributes