Extending Chef: creating custom resources with the DSL and properties, understanding the difference between LWRP and HWRP, writing Ruby helpers in libraries, and installing exception and report handlers in the chef-client run cycle.

In episode 15 you built clean, tested cookbook writing habits. The deeper your automation goes, the more often you find repeating patterns — and that is when it is time to abstract. In episode 16 we discuss Custom Resources & Libraries: creating your own resources with the custom resource DSL, getting to know LWRP and HWRP, plus writing Ruby helpers and handlers that hook into the chef-client run cycle.
The goals of this episode:
libraries/ directory.A custom resource lives in the resources/ directory of a cookbook, one file per resource. It defines properties as inputs and actions as the behaviors recipes call.
unified_mode true
property :domain, String, required: true
property :document_root, String, default: "/var/www/html"
property :allow_upload, [true, false], default: false
action :create do
directory new_resource.document_root do
recursive true
end
template File.join(new_resource.document_root, "index.html") do
source "index.html.erb"
variables domain: new_resource.domain
end
end
action :delete do
directory new_resource.document_root do
recursive true
action :delete
end
endThe resource above can be used exactly like a built-in resource:
my_site "blog.example.com" do
document_root "/srv/blog"
action :create
endNote
new_resource gives access to the property values currently being processed. Always access properties through new_resource, not node, so default values and per-location values are applied correctly.
Properties are the input contract of a resource. Chef supports types, default values, required, and even regex validation.
property :domain, String, required: true, regex: /^[a-z0-9.-]+$/
property :worker_count, Integer, default: 2
property :http_ports, Array, default: [80, 8080]The modern custom resource replaces two older approaches:
| Approach | Location | Characteristics |
|---|---|---|
| Custom resource | resources/name.rb | Modern DSL, unified_mode |
| LWRP | resources/ + providers/ | Legacy, separate resource and provider |
| HWRP | libraries/ as Ruby classes | Full control, requires knowing the internal API |
Use custom resources for every new case; LWRP and HWRP only need to be understood when reading older cookbooks.
libraries/ is the place for reusable Ruby functions used across recipes:
module MyApp
module Helpers
def site_url(domain)
"https://#{domain}/"
end
end
end
Chef::DSL::Recipe.include MyApp::HelpersThen call it in a recipe:
my_site "blog.example.com" do
document_root "/srv/blog"
end
log "Situs: #{site_url('blog.example.com')}"The chef-client run cycle has phases that can be hooked: start, report (success), and exception (failure). Handlers are Ruby classes derived from Chef::Handler:
class NotifyHandler < Chef::Handler
def report
status = success? ? "BERHASIL" : "GAGAL"
Chef::Log.warn("Chef run #{status} pada #{run_status.node_name}")
end
endAfter the handler is installed, run chef-client and watch the logs to see the handler at work.
Register the handler in a recipe:
chef_handler "NotifyHandler" do
source "#{node["chef_handler"]["handler_path"]}/notify_handler.rb"
supports report: true, exception: true
action :enable
end| Run phase | Handler method | Use |
|---|---|---|
| Before resources run | report with start flag | Initialization |
| Run succeeded | report | Success notifications, metrics |
| Run failed | exception | Alert to Slack or PagerDuty |
Handlers are a good fit for sending notifications, recording metrics, or generating automatic reports.
In this episode 16 you went beyond built-in resources: creating custom resources with properties and actions, understanding the difference with LWRP and HWRP, writing Ruby helpers in libraries/, and installing report and exception handlers that hook into the chef-client run cycle.
Key takeaways:
libraries/ keep cross-recipe logic DRY.In the next episode, episode 17, we shift focus from managing servers to packaging applications: Chef Habitat — building artifacts with hab pkg build, writing plans, running a supervisor, and combining packaged Habitat applications with Chef-managed servers. See you in episode 17!