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:
Generate a new custom resource.
The
resources
directory doesn’t exist by default in a cookbook. Generate theresources
directory and a resource file from thechef-repo/cookbooks
directory with the command:chef generate resource <PATH_TO_COOKBOOK> <RESOURCE_NAME>
For example, this command generates a
site
custom resource in thecustom_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
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.
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. Theprovides
statement makes the custom resource available for use recipes.homepage
sets the default HTML for theindex.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:
- See the LearnChef interactive tutorial: Extending Chef Infra: Custom Resources.
- For a description of available methods, see the custom resources glossary.
- For running resources in Target Mode, see the Target Mode documentation.
- For running resources in Unified Mode, see the Unified Mode documentation.