Chef

Table Of Contents

ruby_block

A resource defines the desired state for a single configuration item present on a node that is under management by Chef. A resource collection—one (or more) individual resources—defines the desired state for the entire node. During a chef-client run, the current state of each resource is tested, after which the chef-client will take any steps that are necessary to repair the node and bring it back into the desired state.

Use the ruby_block resource to execute Ruby code during a chef-client run. Ruby code in the ruby_block resource is evaluated with other resources during convergence, whereas Ruby code outside of a ruby_block resource is evaluated before other resources, as the recipe is compiled.

Syntax

A ruby_block resource block executes a block of arbitrary Ruby code. For example, to reload the client.rb file during the chef-client run:

ruby_block 'reload_client_config' do
  block do
    Chef::Config.from_file("/etc/chef/client.rb")
  end
  action :run
end

The full syntax for all of the properties that are available to the ruby_block resource is:

ruby_block 'name' do
  block                      Block
  block_name                 String # defaults to 'name' if not specified
  notifies                   # see description
  provider                   Chef::Provider::RubyBlock
  subscribes                 # see description
  action                     Symbol # defaults to :run if not specified
end

where

  • ruby_block is the resource
  • name is the name of the resource block
  • block is the block of Ruby code to be executed
  • :action identifies the steps the chef-client will take to bring the node into the desired state
  • block, block_name, and provider are properties of this resource, with the Ruby type shown. See “Properties” section below for more information about all of the properties that may be used with this resource.

Actions

This resource has the following actions:

Action Description
:create The same as :run.
:nothing Define a resource block that does nothing until it is notified by another resource to take action. When notified, this resource block is either run immediately or it is queued up to be run at the end of the chef-client run.
:run Default. Run a Ruby block.

Properties

This resource has the following properties:

Property Description
block

Ruby Type: Block

A block of Ruby code.

block_name

Ruby Type: String

The name of the Ruby block. Default value: the name of the resource block. See “Syntax” section above for more information.

ignore_failure

Ruby Types: TrueClass, FalseClass

Continue running a recipe if a resource fails for any reason. Default value: false.

notifies

Ruby Type: Symbol, ‘Chef::Resource[String]’, Symbol

Which resource takes action when this resource’s state changes. A resource may notify more than one resource; use a notifies statement for each resource to be notified.

Specify the :action, 'resource[name]', and timer (:delayed or :immediately). Use multiple notifies statements to notify more than one resource.

resource 'name' do
  ...
  notifies :action, 'resource[name]', :timer
end

Use the following timers to specify 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 should be run immediately, per resource notified.
provider

Ruby Type: Chef Class

Optional. Explicitly specify a provider.

retries

Ruby Type: Integer

The number of times to catch exceptions and retry the resource. Default value: 0.

retry_delay

Ruby Type: Integer

The retry delay (in seconds). Default value: 2.

subscribes

Ruby Type: Symbol, ‘Chef::Resource[String]’, Symbol

Specify that this resource is to listen to another resource, and then take action when that resource’s state changes.

Specify the :action, 'resource[name]', and timer (:delayed or :immediately). Use multiple subscribes statements to listen to more than one resource.

resource 'name' do
  ...
  subscribes :action, 'resource[name]', :timer
end

The subscribes property uses the same timers as the notifies property.

Examples

The following examples demonstrate various approaches for using resources in recipes. If you want to see examples of how Chef uses resources in recipes, take a closer look at the cookbooks that Chef authors and maintains: https://github.com/opscode-cookbooks.

Re-read configuration data

ruby_block 'reload_client_config' do
  block do
    Chef::Config.from_file('/etc/chef/client.rb')
  end
  action :run
end

Install repositories from a file, trigger a command, and force the internal cache to reload

The following example shows how to install new Yum repositories from a file, where the installation of the repository triggers a creation of the Yum cache that forces the internal cache for the chef-client to reload:

execute 'create-yum-cache' do
 command 'yum -q makecache'
 action :nothing
end

ruby_block 'reload-internal-yum-cache' do
  block do
    Chef::Provider::Package::Yum::YumCache.instance.reload
  end
  action :nothing
end

cookbook_file '/etc/yum.repos.d/custom.repo' do
  source 'custom'
  mode '0755'
  notifies :run, 'execute[create-yum-cache]', :immediately
  notifies :create, 'ruby_block[reload-internal-yum-cache]', :immediately
end

Use an if statement with the platform recipe DSL method

The following example shows how an if statement can be used with the platform? method in the Recipe DSL to run code specific to Microsoft Windows. The code is defined using the ruby_block resource:

# the following code sample comes from the ``client`` recipe
# in the following cookbook: https://github.com/opscode-cookbooks/mysql

if platform?('windows')
  ruby_block 'copy libmysql.dll into ruby path' do
    block do
      require 'fileutils'
      FileUtils.cp "#{node['mysql']['client']['lib_dir']}\\libmysql.dll",
        node['mysql']['client']['ruby_dir']
    end
    not_if { File.exist?("#{node['mysql']['client']['ruby_dir']}\\libmysql.dll") }
  end
end

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']}]", :immediately
end

Update the /etc/hosts file

The following example shows how the ruby_block resource can be used to update the /etc/hosts file:

# the following code sample comes from the ``ec2`` recipe
# in the following cookbook: https://github.com/opscode-cookbooks/dynect

ruby_block 'edit etc hosts' do
  block do
    rc = Chef::Util::FileEdit.new('/etc/hosts')
    rc.search_file_replace_line(/^127\.0\.0\.1 localhost$/,
       '127.0.0.1 #{new_fqdn} #{new_hostname} localhost')
    rc.write_file
  end
end

Set environment variables

The following example shows how to use variables within a Ruby block to set environment variables using rbenv.

node.set[:rbenv][:root] = rbenv_root
node.set[:ruby_build][:bin_path] = rbenv_binary_path

ruby_block 'initialize' do
  block do
    ENV['RBENV_ROOT'] = node[:rbenv][:root]
    ENV['PATH'] = "#{node[:rbenv][:root]}/bin:#{node[:ruby_build][:bin_path]}:#{ENV['PATH']}"
  end
end

Set JAVA_HOME

The following example shows how to use a variable within a Ruby block to set the java_home environment variable:

ruby_block 'set-env-java-home' do
  block do
    ENV['JAVA_HOME'] = java_home
  end
end

Reload the configuration

The following example shows how to reload the configuration of a chef-client using the remote_file resource to:

  • using an if statement to check whether the plugins on a node are the latest versions
  • identify the location from which Ohai plugins are stored
  • using the notifies property and a ruby_block resource to trigger an update (if required) and to then reload the client.rb file.
directory 'node[:ohai][:plugin_path]' do
  owner 'chef'
  recursive true
end

ruby_block 'reload_config' do
  block do
    Chef::Config.from_file('/etc/chef/client.rb')
  end
  action :nothing
end

if node[:ohai].key?(:plugins)
  node[:ohai][:plugins].each do |plugin|
    remote_file node[:ohai][:plugin_path] +"/#{plugin}" do
      source plugin
      owner 'chef'
              notifies :run, 'ruby_block[reload_config]', :immediately
    end
  end
end