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 every 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

The syntax for using the ruby_block resource in a recipe is as follows:

ruby_block "name" do
  block do
    # some Ruby code
  end
  action :action # see actions section below
end

where

  • ruby_block tells the chef-client to use the Chef::Provider::RubyBlock provider during the chef-client run
  • name is the name of the resource block; when the block_name attribute is not specified as part of a recipe, name is also the name of the Ruby block
  • block is the attribute that is used to define the Ruby block
  • :action is the step that the resource will ask the provider to take during the chef-client run

Actions

This resource has the following actions:

Action Description
:run Default. Use to run a Ruby block.
:create The same as :run.

Attributes

This resource has the following attributes:

Attribute Description
block A block of Ruby code.
block_name The name of the Ruby block. Default value: the name of the resource block. (See “Syntax” section above for more information.)
provider Optional. Use to explicitly specify a provider. (See “Providers” section below for more information.)

Providers

The chef-client will attempt to determine the correct provider during the chef-client run, and then choose the best/correct provider based on configuration data collected at the start of the chef-client run. In general, a specific provider does not need to be specified. In situations where a specific provider must be specified, there are two approaches:

  • Using a provider’s short name as the name of the resource, e.g. short_name "foo" do
  • Using the provider attribute to specify the long name as an attribute of a resource, e.g. provider Chef::Provider::Long::Name

Whenever possible, try using the short name first, and then use the long name when necessary.

This resource has the following providers:

Long name Short name Notes
Chef::Provider::RubyBlock ruby_block The default provider for all platforms.

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 '0644'
  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 attribute 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