Chef

Table Of Contents

Common Functionality

All resources (and lightweight resources) share a set of common actions, attributes, conditional executions, notifications, and relative path options.

Actions

The following actions are common to every resource:

Action Description
:nothing Use to do nothing. In the absence of another default action, nothing is the default. This action can be useful to specify a resource so that it can be notified of other actions.

Examples

The following examples show how to use common actions in a recipe.

Use the :nothing action

service "memcached" do
  action :nothing
  supports :status => true, :start => true, :stop => true, :restart => true
end

Attributes

The following attributes are common to every resource:

Parameter Description
ignore_failure Use to continue running a recipe if a resource fails for any reason. Default value: false.
provider Optional. Use to specify a provider by using its long name. For example: provider Chef::Provider::Long::Name. See the Providers section below for the list of providers available to this resource.
retries Use to specify the number of times to catch exceptions and retry the resource. Default value: 0.
retry_delay Use to specify the retry delay (in seconds). Default value: 2.
supports Use to specify a hash of options that contains hints about the capabilities of a resource. The chef-client may use these hints to help identify the correct provider. This attribute is only used by a small number of providers, including User and Service.

Examples

The following examples show how to use common attributes in a recipe.

Use the ignore_failure common attribute

gem_package "syntax" do
  action :install
  ignore_failure true
end

Use the provider common attribute

package "some_package" do
  provider Chef::Provider::Package::Rubygems
end

Use the supports common attribute

service "apache" do
  supports :restart => true, :reload => true
  action :enable
end

Use the supports and providers common attributes

service "some_service" do
  provider Chef::Provider::Service::Upstart
  supports :status => true, :restart => true, :reload => true
  action [ :enable, :start ]
end

Guards

A guard can be used to evaluate the state of a node during the execution phase of the chef-client run. Based on the results of this evaluation, a guard is then used to tell the chef-client if it should continue executing a resource. A guard accepts either a string value or a Ruby block value:

  • A string is executed as a shell command. If the command returns 0, the guard is applied. If the command returns any other value, then the guard is not applied.
  • A block is executed as Ruby code that must return either true or false. If the block returns true, the the guard is applied. If the block returns false, the guard is not applied.

A guard is useful for ensuring that a resource is idempotent by allowing a resource to test for the desired state as it is being executed, and then if the desired state is present, for the chef-client to do nothing.

Note

When using the not_if and only_if guards with the execute resource, the current working directory attribute (cwd) is not inherited from the resource. For example:

execute 'bundle install' do
  cwd '/myapp'
  not_if 'bundle check' # This is not run inside /myapp
end

Attributes

The following guards can be used to define a condition to be evaluated during the execution phase of the chef-client run:

Guard Description
not_if Use to prevent a resource from executing when the condition returns true.
only_if Use to allow a resource to execute only if the condition returns true.

Arguments

The following arguments can be used with the not_if or only_if guard:

Argument Description
:user

Use to specify the user that a command will run as. For example:

not_if "grep adam /etc/passwd", :user => 'adam'
:group

Use to specify the group that a command will run as. For example:

not_if "grep adam /etc/passwd", :group => 'adam'
:environment

Use to specify a Hash of environment variables to be set. For example:

not_if "grep adam /etc/passwd", :environment => { 'HOME' => "/home/adam" }
:cwd

Use to set the current working directory before running a command. For example:

not_if "grep adam passwd", :cwd => '/etc'
:timeout

Use to set a timeout for a command. For example:

not_if "sleep 10000", :timeout => 10

not_if Examples

Update if not already updated

The following example shows how to use not_if to guard against running the apt-get-update command when a file already exists that is the same as the updated file:

execute "apt-get-update" do
  command "apt-get update"
  ignore_failure true
  not_if do ::File.exists?('/var/lib/apt/periodic/update-success-stamp') end
end

Ensure a node can resolve a host

The following example shows how to use a custom block of Ruby code to ensure that a node can resolve the host. If the node can resolve the host, the chef-client will do nothing. If the node cannot resolve the host, the chef-client will configure the host:

ruby_block "ensure node can resolve API FQDN" do
  block do
    fe = Chef::Util::FileEdit.new("/etc/hosts")
    fe.insert_line_if_no_match(/#{node['chef-server']['api_fqdn']}/,
                               "127.0.0.1 #{node['chef-server']['api_fqdn']}")
    fe.write_file
  end
  not_if { Resolv.getaddress(node['chef-server']['api_fqdn']) rescue false }
end

Prevent installs on older versions

The following example shows how to use not_if to prevent ZeroMQ from being installed when the node on which the install is to occur has a version of Red Hat Enterprise Linux that is older than version 6.0:

ark "test_autogen" do
  url 'https://github.com/zeromq/libzmq/tarball/master'
  extension "tar.gz"
  action :configure
  not_if { platform_family?('rhel') && node['platform_version'].to_f < 6.0 }
end

Set the administrator if not already set

The following example shows how to set the administrator for Nagios on multiple nodes, except when the package already exists on a node:

%w{adminpassword adminpassword-repeat}.each do |setting|
  execute "debconf-set-selections::#{node['nagios']['server']['vname']}-cgi::#{node['nagios']['server']['vname']}/#{setting}" do
    command "echo #{node['nagios']['server']['vname']}-cgi #{node['nagios']['server']['vname']}/#{setting} password #{random_initial_password} | debconf-set-selections"
    not_if "dpkg -l #{node['nagios']['server']['vname']}"
  end
end

only_if Examples

Install packages only when necessary

The following example shows how to use only_if with one (or more) cookbook attributes to ensure that packages are only installed when necessary. In this case, three attributes exist in the /attributes/default.rb file: use_openssl, use_pcre, and use_zlib. Each of these attributes are defined as false by default. The only_if attributes are used to test for the presence of these packages on the target node before then asking the chef-client to complete the process of installing these packages. If the packages are already present, the chef-client will do nothing.

package 'libpcre3-dev' do
  only_if { node['haproxy']['source']['use_pcre'] }
end

package 'libssl-dev' do
  only_if { node['haproxy']['source']['use_openssl'] }
end

package 'zlib1g-dev' do
  only_if { node['haproxy']['source']['use_zlib'] }
end

Remove a recipe if it belongs to a specific run-list

The following example shows how to use only_if to only remove a recipe named recipe[ntp::undo], but only when that recipe is part of the recipe[ntp::default] run-list:

ruby_block 'remove ntp::undo from run list' do
  block do
    node.run_list.remove('recipe[ntp::undo]')
  end
  only_if { node.run_list.include?('recipe[ntp::default]') }
end

Re-register ASP.Net if it’s already installed

The following example shows how to use only_if to ensure that the chef-client will attempt to register ASP.NET only if the executable is installed on the system, on both 32- and 64-bit systems:

aspnet_regiis = "#{ENV['WinDir']}\\Microsoft.NET\\Framework\\v4.0.30319\\aspnet_regiis.exe"
execute 'Register ASP.NET v4' do
  command "#{aspnet_regiis} -i"
  only_if { File.exists?(aspnet_regiis) }
  action :nothing
end

aspnet_regiis64 = "#{ENV['WinDir']}\\Microsoft.NET\\Framework64\\v4.0.30319\\aspnet_regiis.exe"
execute 'Register ASP.NET v4 (x64)' do
  command "#{aspnet_regiis64} -i"
  only_if { File.exists?(aspnet_regiis64) }
  action :nothing
end

Lazy Attribute Evaluation

In some cases, the value for an attribute cannot be known until the execution phase of a chef-client run. In this situation, using lazy evaluation of attribute values can be helpful. Instead of an attribute being assigned a value, it may instead be assigned a code block. The syntax for using lazy evaluation is as follows:

attribute_name lazy { code_block }

where lazy is used to tell the chef-client to evaluate the contents of the code block later on in the resource evaluation process (instead of immediately) and { code_block } is arbitrary Ruby code that provides the value.

For example, a resource that is not doing lazy evaluation:

template "template_name" do
  # some attributes
  path "/foo/bar"
end

and a resource that is doing lazy evaluation:

template "template_name" do
  # some attributes
  path lazy { " some Ruby code " }
end

In the previous examples, the first resource uses the value /foo/bar and the second resource uses the value provided by the code block, as long as the contents of that code block are a valid resource attribute.

Notifications

The following notifications can be used with any resource:

Notification Description
notifies Use to notify another resource to take an action if this resource’s state changes for any reason.
subscribes Use to take action on this resource if another resource’s state changes. This is similar to notifies, but reversed.

Notifications Timers

The following timers can be used to define when a notification is triggered:

Timer Description
:delayed Use to specify that a notification should be queued up and then executed at the very end of a chef-client run.
:immediately Use to specify that a notification be run immediately.

Notifies Syntax

The basic syntax of a notifies notification is:

resource "name" do
  notifies :notification, "resource_type[resource_name]", :timer
end

Examples

The following examples show how to use the notifies notification in a recipe.

Delay notifications

template "/etc/nagios3/configures-nagios.conf" do
  # other parameters
  notifies :run, "execute[test-nagios-config]", :delayed
end

Notify immediately

By default, notifications are :delayed, that is they are queued up as they are triggered, and then executed at the very end of a chef-client run. To run an action immediately, use :immediately:

template "/etc/nagios3/configures-nagios.conf" do
  # other parameters
  notifies :run, "execute[test-nagios-config]", :immediately
end

and then the chef-client would immediately run the following:

execute "test-nagios-config" do
  command "nagios3 --verify-config"
  action :nothing
end

Enable a service after a restart or reload

service "apache" do
  supports :restart => true, :reload => true
  action :enable
end

Notify multiple resources

template "/etc/chef/server.rb" do
  source "server.rb.erb"
  owner "root"
  group "root"
  mode "644"
  notifies :restart, "service[chef-solr]", :delayed
  notifies :restart, "service[chef-solr-indexer]", :delayed
  notifies :restart, "service[chef-server]", :delayed
end

Notify in a specific order

To notify multiple resources, and then have these resources run in a certain order, do something like the following:

execute 'foo' do
  command '...'
  notifies :run, 'template[baz]', :immediately
  notifies :install, 'package[bar]', :immediately
  notifies :run, 'execute[final]', :immediately
end

template 'baz' do
  ...
  notifies :run, 'execute[restart_baz]', :immediately
end

package 'bar'

execute 'restart_baz'

execute 'final' do
  command '...'
end

where the sequencing will be in the same order as the resources are listed in the recipe: execute 'foo', template 'baz', execute [restart_baz], package 'bar', and execute 'final'.

Reload a service

template "/tmp/somefile" do
  mode "0644"
  source "somefile.erb"
  notifies :reload, "service[apache]"
end

Restart a service when a template is modified

template "/etc/www/configures-apache.conf" do
  notifies :restart, "service[apache]"
end

Send notifications to multiple resources

To send notifications to multiple resources, just use multiple attributes. Multiple attributes will get sent to the notified resources in the order specified.

template "/etc/netatalk/netatalk.conf" do
  notifies :restart, "service[afpd]", :immediately
  notifies :restart, "service[cnid]", :immediately
end

service "afpd"
service "cnid"

Execute a command using a template

The following example shows how to set up IPv4 packet forwarding using the execute resource to run a command named “forward_ipv4” that uses a template defined by the template resource:

execute "forward_ipv4" do
  command "echo > /proc/.../ipv4/ip_forward"
  action :nothing
end

template "/etc/file_name.conf" do
  source "routing/file_name.conf.erb"
  notifies :run, 'execute[forward_ipv4]', :delayed
end

where the command attribute for the execute resource contains the command that is to be run and the source attribute for the template resource specifies which template to use. The notifies attribute for the template specifies that the execute[forward_ipv4] (which is defined by the execute resource) should be queued up and run at the end of the chef-client run.

Restart a service, and then notify a different service

The following example shows how start a service named “example_service” and immediately notify the Nginx service to restart.

service "example_service" do
  action :start
  provider Chef::Provider::Service::Init
  notifies :restart, "service[nginx]", :immediately
end

where by using the default provider for the service, the recipe is telling the chef-client to determine the specific provider to be used during the chef-client run based on the platform of the node on which the recipe will run.

Notify when a remote source changes

remote_file "/tmp/couch.png" do
  source "http://couchdb.apache.org/img/sketch.png"
  action :nothing
end

http_request "HEAD http://couchdb.apache.org/img/sketch.png" do
  message ""
  url "http://couchdb.apache.org/img/sketch.png"
  action :head
  if File.exists?("/tmp/couch.png")
    headers "If-Modified-Since" => File.mtime("/tmp/couch.png").httpdate
  end
  notifies :create, "remote_file[/tmp/couch.png]", :immediately
end

Subscribes Syntax

The basic syntax of a subscribes notification is:

resource "name" do
  subscribes :notification, "resource_type[resource_name]", :timer
end

Examples

The following examples show how to use the subscribes notification in a recipe.

Prevent restart and reconfigure if configuration is broken

Use the :nothing common action to prevent an application from restarting, and then use the subscribes notification to ask the broken configuration to be reconfigured immediately:

execute "test-nagios-config" do
  command "nagios3 --verify-config"
  action :nothing
  subscribes :run, "template[/etc/nagios3/configures-nagios.conf]", :immediately
end

Reload a service using a template

To reload a service based on a template, use the template and service resources together in the same recipe, similar to the following:

template "/tmp/somefile" do
  mode "0644"
  source "somefile.erb"
end

service "apache" do
  supports :restart => true, :reload => true
  action :enable
  subscribes :reload, "template[/tmp/somefile]", :immediately
end

where the subscribes notification is used to reload the service using the template specified by the template resource.

Stash a file in a data bag

The following example shows how to use the ruby_block resource to stash a BitTorrent file in a data bag so that it can be distributed to nodes in the organization.

#  the following code sample comes from the ``seed`` recipe in the following cookbook: https://github.com/mattray/bittorrent-cookbook

ruby_block "share the torrent file" do
  block do
    f = File.open(node['bittorrent']['torrent'],'rb')
    #read the .torrent file and base64 encode it
    enc = Base64.encode64(f.read)
    data = {
      'id'=>bittorrent_item_id(node['bittorrent']['file']),
      'seed'=>node.ipaddress,
      'torrent'=>enc
    }
    item = Chef::DataBagItem.new
    item.data_bag('bittorrent')
    item.raw_data = data
    item.save
  end
  action :nothing
  subscribes :create, "bittorrent_torrent[#{node['bittorrent']['torrent']}]"
end

Relative Paths

The following relative paths can be used with any resource:

Relative Path Description
#{ENV['HOME']} Use to return the ~ path in Linux and Mac OS X or the %HOMEPATH% in Microsoft Windows.

Examples

template "#{ENV['HOME']}/chef-getting-started.txt" do
  source "chef-getting-started.txt.erb"
  mode 00644
end

Run from Resource Collection

The chef-client processes recipes in two phases:

  1. First, each resource in the node object is identified and a resource collection is built. All recipes are loaded in a specific order, and then the actions specified within each of them are identified.
  2. Next, the chef-client configures the system based on the order of the resources in the resource collection. Each resource is mapped to a provider, which then examines the node and then does the steps necessary to complete the action.

Sometimes, it may be necessary to ensure that a specific resource is run during the phase that builds the resource collection. For example:

  • A resource may need to run first so that it can download a package that will be used by other resources in the resource collection
  • Several resources need to install a package; rather than having the package installer run several times, it can be configured to run only once

To support these types of uses cases, it is possible to tell the chef-client to run a resource at the beginning and/or the end of the resource collection phase. Effectively, run a resource before all other resources are added to the resource collection and/or after all resources have been added, but before the chef-client configures the system.

Before other Resources

To run a resource at the start of the resource collection phase of the chef-client run, set up a Chef::Resource object, and then call the method that runs the action.

Update a package cache

It is important to make sure that an operating system’s package cache is up to date before installing packages, otherwise there may be references to versions that no longer exist. For example, on Debian or Ubuntu systems, the APT cache needs to be updated. Use code similar to the following:

e = execute "apt-get update" do
  action :nothing
end

e.run_action(:run)

where e is created as a Chef::Resource::Execute Ruby object. The action attribute is set to :nothing so that the run_action method can be used to tell the chef-client to run the specified command. The apt (for Debian and Ubuntu) and pacman (for Arch Linux) cookbooks can be used for this purpose. The preceding recipe can be placed at the top of a node’s run list to ensure it is run before the chef-client tries to install any packages.

An anti-pattern

Unfortunately, resources that are executed when the resource collection is being built cannot notify any resource that has yet to be added to the resource collection. For example:

execute "ifconfig"

p = package 'vim-enhanced' do
  action :nothing
  notifies :run, "execute[ifconfig]", :immediately
end
p.run_action(:install)

In some cases, the better approach may be to install the package before the resource collection is built to ensure that it is available to other resources later on. Or, something like the following can be used:

p = package "foo" do
  #parameters
end
p.run_action(:install)

if p.updated_by_last_action?
  #Call the resource that we want to "notify"
end

After Collection is Built

To run a resource at the end of the resource collection phase of the chef-client run, use the :delayed timer on a notification.

Windows File Security

To support Microsoft Windows security, the template, file, remote_file, cookbook_file, directory, and remote_directory resources support the use of inheritance and access control lists (ACLs) within recipes.

Access Control Lists (ACLs)

The rights attribute can be used in a recipe to manage access control lists (ACLs), which allow permissions to be given to multiple users and groups. The syntax for the rights attribute is as follows:

rights permission, principal, option_type => value

where

  • permission is used to specify which rights will be granted to the principal. The possible values are: :read, :write, :full_control, :modify, and :deny. These permissions are cumulative. If :write is specified, then it includes :read. If :full_control is specified, then it includes both :write and :read. If :deny is specified, then the user or group will not have rights to the object. (For those who know the Microsoft Windows API: :read corresponds to GENERIC_READ and GENERIC_EXECUTE; :write corresponds to GENERIC_WRITE, GENERIC_READ, and GENERIC_EXECUTE; :full_control corresponds to GENERIC_ALL, which allows a user to change the owner and other metadata about a file.)

  • principal is used to specify a group or user name. This is identical to what is entered in the login box for Microsoft Windows, such as user_name, domain\user_name, or user_name@fully_qualified_domain_name. The chef-client does not need to know if a principal is a user or a group.

  • option_type is a hash that contains advanced rights options. For example, the rights to a directory that only applies to the first level of children might look something like: rights :write, "domain\group_name", :one_level_deep => true. Possible option types:

    Option Type Description
    :applies_to_children Use to specify how permissions are applied to children. Possible values: true to inherit both child directories and files; false to not inherit any child directories or files; :containers_only to inherit only child directories (and not files); :objects_only to recursively inherit files (and not child directories).
    :applies_to_self Indicates whether a permission is applied to the parent directory. Possible values: true to apply to the parent directory or file and its children; false to not apply only to child directories and files.
    :one_level_deep Indicates the depth to which permissions will be applied. Possible values: true to apply only to the first level of children; false to apply to all children.

The rights attribute can be used as many times as necessary; the chef-client will apply them to the file or directory as required. For example:

resource "x.txt" do
  rights :read, "Everyone"
  rights :write, "domain\group"
  rights :full_control, "group_name_or_user_name"
  rights :full_control, "user_name", :applies_to_children => true
end

or:

rights :read, ["Administrators","Everyone"]
rights :deny, ["Julian", "Lewis"]
rights :full_control, "Users", :applies_to_children => true
rights :write, "Sally", :applies_to_children => :containers_only, :applies_to_self => false, :one_level_deep => true

Some other important things to know when using the rights attribute:

  • Order independence. It doesn’t matter if rights :deny, ["Julian", "Lewis"] is placed before or after rights :read, ["Julian", "Lewis"], both Julian and Lewis will be unable to read the document.
  • Only inherited rights remain. All existing explicit rights on the object are removed and replaced.
  • If rights are not specified, nothing will be changed. The chef-client does not clear out the rights on a file or directory if rights are not specified.
  • Changing inherited rights can be expensive. Microsoft Windows will propagate rights to all children recursively due to inheritance. This is a normal aspect of Microsoft Windows, so consider the frequency with which this type of action is necessary and take steps to control this type of action if performance is the primary consideration.

Inheritance

By default, a file or directory inherits rights from its parent directory. Most of the time this is the preferred behavior, but sometimes it may be necessary to take steps to more specifically control rights. The inherits attribute can be used to specifically tell the chef-client to apply (or not apply) inherited rights from its parent directory.

For example, the following example specifies the rights for a directory:

directory 'C:\mordor' do
  rights :read, 'MORDOR\Minions'
  rights :full_control, 'MORDOR\Sauron'
end

and then the following example specifies how to use inheritance to deny access to the child directory:

directory 'C:\mordor\mount_doom' do
  rights :full_control, 'MORDOR\Sauron'
  inherits false # Sauron is the only person who should have any sort of access
end

If the :deny permission were to be used instead, something could slip through unless all users and groups were denied.

Another example also shows how to specify rights for a directory:

directory 'C:\mordor' do
  rights :read, 'MORDOR\Minions'
  rights :full_control, 'MORDOR\Sauron'
  rights :write, 'SHIRE\Frodo' # Who put that there I didn't put that there
end

but then not use the inherits attribute to deny those rights on a child directory:

directory 'C:\mordor\mount_doom' do
  rights :deny, 'MORDOR\Minions' # Oops, not specific enough
end

Because the inherits attribute is not specified, the chef-client will default it to true, which will ensure that security settings for existing files remain unchanged.