Skip to main content

Custom resource guide

Chef Infra Client ships with over 150 built-in resources for managing system configuration such as directory, remote_file, and windows_firewall. With custom resources you can extend the built-in capabilities of Chef Infra Client to create reusable resources for use anywhere in your infrastructure.

Custom resources:

  • Ship directly in cookbooks.
  • Leverage Chef Infra Client built-in resources and any additional custom Ruby code (if needed).
  • Behave the same as existing built-in resources in your recipes.

Write a custom resource

Custom resources are written in Ruby and defined in a cookbook’s /resources directory.

The custom resource code:

  • Declares the properties of the custom resource.
  • Loads the current state of properties for existing resources.
  • Defines each action that the custom resource may take.

Follow these steps to create a new custom resource:

  1. Generate a new custom resource.

    The resources directory doesn’t exist by default in a cookbook. Generate the resources directory and a resource file from the chef-repo/cookbooks directory with the command:

    chef generate resource <PATH_TO_COOKBOOK> <RESOURCE_NAME>
    

    For example, this command generates a site custom resource in the custom_web cookbook:

    chef generate resource cookbooks/custom_web site
    

    The custom_web cookbook directory with a custom resource has the following structure:

    . cookbooks
    └── custom_web
        ├── CHANGELOG.md
        ├── LICENSE
        ├── Policyfile.rb
        ├── README.md
        ├── chefignore
        ├── kitchen.yml
        ├── metadata.rb
        ├── recipes
        │   └── default.rb
        ├── resources
        │   └── site.rb
        └── test
            └── integration
                └── default
                    └── default_test.rb
    
  2. Define the custom resources.

    The layout for a custom resource is:

    provides :resource_name
    
    property :property_name, RubyType, default: 'value'
    
    action :an_action_name do
    # a mix of built-in Chef Infra resources and Ruby
    end
    
    action :another_action_name do
    # a mix of built-in Chef Infra resources and Ruby
    end
    

    The first action listed is the default action.

    For more details on the contents of a custom resource, see the custom resource glossary.

  3. Add the custom resource to a recipe.

    Call a resource in a recipe by its resource name. For example:

    resource_name 'foo'
    

Example custom resource

This example creates a custom resource called site, which uses Chef Infra’s built-in file, service and package resources, and includes :create and :delete actions. It also assumes the existence of a custom httpd template. The code in this custom resource is similar to a typical recipe because it uses built-in Chef Infra Client resources, with the addition of the property and actions definitions for this custom resource.

provides :site

property :homepage, String, default: '<h1>Hello world!</h1>'

action :create do
  package 'httpd'

  service 'httpd' do
    action [:enable, :start]
  end

  file '/var/www/html/index.html' do
    content new_resource.homepage
  end
end

action :delete do
  package 'httpd' do
    action :remove
  end

  file '/var/www/html/index.html' do
    action :delete
  end
end

where:

  • site is the name of the custom resource. The provides statement makes the custom resource available for use recipes.
  • homepage sets the default HTML for the index.html file with a default value of '<h1>Hello world!</h1>'
  • the action block uses the built-in collection of resources to tell Chef Infra Client how to install Apache, start the service, and then create the contents of the file located at /var/www/html/index.html
  • action :create is the default resource (because it’s listed first); action :delete must be called specifically (because it’s not the default action)

Once written, you can use a custom resource in a recipe with the same syntax as Chef Infra Client built-in resources.

Syntax

To add a custom resource to a recipe, call it by its resource name. For example, this adds a the site resource:

site 'foo'

Target Mode

Target Mode executes Chef Infra Client runs on nodes that don’t have Chef Infra Client installed on them. For more information on Target Mode, see the Target Mode documentation.

To enable a custom resource to run in Target Mode, add target_mode: true to the resource definition. For example:

provides :resource_name, target_mode: true
...

Example

The following custom resource example checks for and creates a new directory and runs in Target Mode:

provides :example_directory, target_mode: true
unified_mode true

property: directory, String

load_current_value do |new_resource|
  dir = new_resource.directory
  parsed = dir.match(%r{([^/]+$)})
  path = ''
  if parsed
    path = dir[0..(dir.length - parsed[1].length - 1)]
    dir = parsed[1]
  end

  tmp = __transport_connection.run_command( sprintf('ls -l %s | grep %s || echo -n', path, dir) )

  if tmp.match(Regexp.new(dir))
    directory new_resource.directory
  end
end

action :create do
  converge_if_changed do
    __transport_connection.run_command( sprintf('mkdir %s', new_resource.directory) )
  end
end

Unified Mode

Unified mode is a setting that will compile and converge a custom resource’s action block in one pass and in the order that the code inside that block is composed, from beginning to end. This replaces Chef Infra’s two-pass parsing with single-pass parsing so that resources are executed as soon as they’re declared. This results in clearer code and requires less Ruby knowledge to understand the order of operations.

For more information on Unified Mode, see the Unified Mode documentation.

Enable Unified Mode

Unified Mode is enabled by default starting in Chef Infra Client 18.

In Chef Infra Client 17 (April 2021) and some earlier versions, you can enable Unified Mode in custom resources by adding unified_mode true. You can upgrade most custom resources to use Unified Mode without additional work other than testing and validation. See the following example:

# enable unified mode
unified_mode true

provides :myresource

actions :run do
  [...]
end

Learn more

See these resources to learn more about custom resources:

Edit this page on GitHub

Thank you for your feedback!

×