ruby_block Resource

This page is generated from the Chef source code.To suggest a change, edit the ruby_block.rb file and submit a pull request to the Chef repository.

Resources Reference page


Use the ruby_block resource to execute Ruby code during a Chef Infra 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 a Chef Infra 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
  action                     Symbol # defaults to :run if not specified
end

where:

  • ruby_block is the resource.
  • name is the name given to the resource block.
  • block is the block of Ruby code to be executed.
  • action identifies which steps Chef Infra Client will take to bring the node into the desired state.
  • block and block_name 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


The ruby_block resource has the following actions:

:create
The same as :run.
:nothing
This resource block does not act unless notified by another resource to take action. Once notified, this resource block either runs immediately or is queued up to run at the end of a Chef Infra Client run.
:run
Default. Run a Ruby block.

Properties


The ruby_block resource has the following properties:

block
Ruby Type: Block

A block of Ruby code.

block_name
Ruby Type: String | Default Value: The resource block's name

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

ignore_failure
Ruby Type: true, false | Default Value: false

Continue running a recipe if a resource fails for any reason.

notifies
Ruby Type: Symbol, Chef::Resource\[String\]

A resource may notify another resource to take action when its state changes. Specify a 'resource[name]', the :action that resource should take, and then the :timer for that action. A resource may notify more than one resource; use a notifies statement for each resource to be notified.

If the referenced resource does not exist, an error is raised. In contrast, subscribes will not fail if the source resource is not found.

A timer specifies the point during a Chef Infra Client run at which a notification is run. The following timers are available:

:before

Specifies that the action on a notified resource should be run before processing the resource block in which the notification is located.

:delayed

Default. Specifies that a notification should be queued up, and then executed at the end of a Chef Infra Client run.

:immediate, :immediately

Specifies that a notification should be run immediately, per resource notified.

The syntax for notifies is:

notifies :action, 'resource[name]', :timer
retries
Ruby Type: Integer | Default Value: 0

The number of attempts to catch exceptions and retry the resource.

retry_delay
Ruby Type: Integer | Default Value: 2

The retry delay (in seconds).

subscribes
Ruby Type: Symbol, Chef::Resource\[String\]

A resource may listen to another resource, and then take action if the state of the resource being listened to changes. Specify a 'resource[name]', the :action to be taken, and then the :timer for that action.

Note that subscribes does not apply the specified action to the resource that it listens to - for example:

file '/etc/nginx/ssl/example.crt' do
  mode '0600'
  owner 'root'
end

service 'nginx' do
  subscribes :reload, 'file[/etc/nginx/ssl/example.crt]', :immediately
end

In this case the subscribes property reloads the nginx service whenever its certificate file, located under /etc/nginx/ssl/example.crt, is updated. subscribes does not make any changes to the certificate file itself, it merely listens for a change to the file, and executes the :reload action for its resource (in this example nginx) when a change is detected.

If the other resource does not exist, the subscription will not raise an error. Contrast this with the stricter semantics of notifies, which will raise an error if the other resource does not exist.

A timer specifies the point during a Chef Infra Client run at which a notification is run. The following timers are available:

:before

Specifies that the action on a notified resource should be run before processing the resource block in which the notification is located.

:delayed

Default. Specifies that a notification should be queued up, and then executed at the end of a Chef Infra Client run.

:immediate, :immediately

Specifies that a notification should be run immediately, per resource notified.

The syntax for subscribes is:

subscribes :action, 'resource[name]', :timer

Examples


The following examples demonstrate various approaches for using the ruby_block resource in recipes:

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 Chef Infra 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/chef-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/chef-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.override[:rbenv][:root] = rbenv_root
node.override[: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

Run specific blocks of Ruby code on specific platforms

The following example shows how the platform? method and an if statement can be used in a recipe along with the ruby_block resource to run certain blocks of Ruby code on certain platforms:

if platform_family?('debian', 'rhel', 'fedora', 'amazon')
  ruby_block 'update-java-alternatives' do
    block do
      if platform?('ubuntu', 'debian') and version == 6
        run_context = Chef::RunContext.new(node, {})
        r = Chef::Resource::Execute.new('update-java-alternatives', run_context)
        r.command 'update-java-alternatives -s java-6-openjdk'
        r.returns [0,2]
        r.run_action(:create)
      else

        require 'fileutils'
        arch = node['kernel']['machine'] =~ /x86_64/ ? 'x86_64' : 'i386'
        Chef::Log.debug("glob is #{java_home_parent}/java*#{version}*openjdk*")
        jdk_home = Dir.glob("#{java_home_parent}/java*#{version}*openjdk{,[-\.]#{arch}}")[0]
        Chef::Log.debug("jdk_home is #{jdk_home}")

        if File.exist? java_home
          FileUtils.rm_f java_home
        end
        FileUtils.ln_sf jdk_home, java_home

        cmd = Chef::ShellOut.new(
              %Q[ update-alternatives --install /usr/bin/java java #{java_home}/bin/java 1;
              update-alternatives --set java #{java_home}/bin/java ]
              ).run_command
           unless cmd.exitstatus == 0 or cmd.exitstatus == 2
          Chef::Application.fatal!('Failed to update-alternatives for openjdk!')
        end
      end
    end
    action :nothing
  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

© 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/resources/ruby_block/