About the Handler DSL
Use the Handler DSL to attach a callback to an event. If the event occurs during a Chef Infra Client run, the associated callback is executed. For example:
- Sending email if a Chef Infra Client run fails
- Aggregating statistics about resources updated during a Chef Infra Client runs to StatsD
on Method
Use the on
method to associate an event type with a callback. The
callback defines what steps are taken if the event occurs during a Chef
Infra Client run and is defined using arbitrary Ruby code. The syntax is
as follows:
Chef.event_handler do
on :event_type do
# some Ruby
end
end
where
Chef.event_handler
declares a block of code within a recipe that is processed when the named event occurs during a Chef Infra Client runon
defines the block of code that will tell Chef Infra Client how to handle the event:event_type
is a valid exception event type, such as:run_start
,:run_failed
,:converge_failed
,:resource_failed
, or:recipe_not_found
For example:
Chef.event_handler do
on :converge_start do
puts "Ohai! I have started a converge."
end
end
Event Types
The following table describes the events that may occur during a Chef
Infra Client run. Each of these events may be referenced in an on
method block by declaring it as the event type.
:run_start
The start of a Chef Infra Client run.
:run_started
The Chef Infra Client run has started.
:run_completed
The Chef Infra Client run has completed.
:run_failed
The Chef Infra Client run has failed.
:ohai_completed
The Ohai run has completed.
:skipping_registration
The Chef Infra Client isn’t registering with the Chef Infra Server because it already has a private key or because it doesn’t need one.
:registration_start
The Chef Infra Client is attempting to create a private key with which to register to the Chef Infra Server.
:registration_completed
The Chef Infra Client created its private key successfully.
:registration_failed
The Chef Infra Client encountered an error and was unable to register with the Chef Infra Server.
:node_load_start
The Chef Infra Client is attempting to load node data from the Chef Infra Server.
:node_load_success
The Chef Infra Client successfully loaded node data from the policy builder.
:node_load_failed
The Chef Infra Client encountered an error and was unable to load node data from the Chef Infra Server.
:run_list_expand_failed
The Chef Infra Client failed to expand the run-list.
:node_load_completed
The Chef Infra Client successfully loaded node data from the Chef Infra Server. Default and override attributes for roles have been computed, but aren’t yet applied.
:policyfile_loaded
The Policyfile was loaded.
:cookbook_resolution_start
The Chef Infra Client is attempting to pull down the cookbook collection from the Chef Infra Server.
:cookbook_resolution_failed
The Chef Infra Client failed to pull down the cookbook collection from the Chef Infra Server.
:cookbook_resolution_complete
The Chef Infra Client successfully pulled down the cookbook collection from the Chef Infra Server.
:cookbook_clean_start
The Chef Infra Client is attempting to remove unneeded cookbooks.
:removed_cookbook_file
The Chef Infra Client removed a file from a cookbook.
:cookbook_clean_complete
The Chef Infra Client is done removing cookbooks and/or cookbook files.
:cookbook_sync_start
The Chef Infra Client is attempting to synchronize cookbooks.
:synchronized_cookbook
The Chef Infra Client is attempting to synchronize the named cookbook.
:updated_cookbook_file
The Chef Infra Client updated the named file in the named cookbook.
:cookbook_sync_failed
The Chef Infra Client was unable to synchronize cookbooks.
:cookbook_sync_complete
The Chef Infra Client is finished synchronizing cookbooks.
:cookbook_gem_start
The Chef Infra Client is collecting gems from the cookbooks.
:cookbook_gem_installing
The Chef Infra Client is installing a cookbook gem.
:cookbook_gem_using
The Chef Infra Client is using a cookbook gem.
:cookbook_gem_finished
The Chef Infra Client finished installing cookbook gems.
:cookbook_gem_failed
The Chef Infra Client failed to install cookbook gems.
:cookbook_compilation_start
The Chef Infra Client created the run_context and is starting cookbook compilation.
:library_load_start
The Chef Infra Client is loading library files.
:library_file_loaded
The Chef Infra Client successfully loaded the named library file.
:library_file_load_failed
The Chef Infra Client was unable to load the named library file.
:library_load_complete
The Chef Infra Client is finished loading library files.
:lwrp_load_start
The Chef Infra Client is loading custom resources.
:lwrp_file_loaded
The Chef Infra Client successfully loaded the named custom resource.
:lwrp_file_load_failed
The Chef Infra Client was unable to load the named custom resource.
:lwrp_load_complete
The Chef Infra Client is finished loading custom resources.
:ohai_plugin_load_start
Ohai has started loading plugins.
:ohai_plugin_file_loaded
Ohai has loaded a plugin.
:ohai_plugin_file_load_failed
Ohai failed to load a plugin.
:ohai_plugin_load_complete
Ohai has completed loading plugins.
:attribute_load_start
The Chef Infra Client is loading attribute files.
:attribute_file_loaded
The Chef Infra Client successfully loaded the named attribute file.
:attribute_file_load_failed
The Chef Infra Client was unable to load the named attribute file.
:attribute_load_complete
The Chef Infra Client is finished loading attribute files.
:definition_load_start
The Chef Infra Client is loading definitions.
:definition_file_loaded
The Chef Infra Client successfully loaded the named definition.
:definition_file_load_failed
The Chef Infra Client was unable to load the named definition.
:definition_load_complete
The Chef Infra Client is finished loading definitions.
:recipe_load_start
The Chef Infra Client is loading recipes.
:recipe_file_loaded
The Chef Infra Client successfully loaded the named recipe.
:recipe_file_load_failed
The Chef Infra Client was unable to load the named recipe.
:recipe_not_found
The Chef Infra Client was unable to find the named recipe.
:recipe_load_complete
The Chef Infra Client is finished loading recipes.
:cookbook_compilation_complete
The Chef Infra Client completed all cookbook compilation phases.
:converge_start
The Chef Infra Client run converge phase has started.
:action_collection_registration
Provides a reference to the action_collection before cookbooks are compiled.
:converge_complete
The Chef Infra Client run converge phase is complete.
:converge_failed
The Chef Infra Client run converge phase has failed.
:control_group_started
The named control group is being processed.
:control_example_success
The named control group has been processed.
:control_example_failure
The named control group’s processing has failed.
:resource_action_start
A resource action is starting.
:resource_skipped
A resource action was skipped.
:resource_current_state_loaded
A resource’s current state was loaded.
:resource_after_state_loaded
A resource’s after state was loaded.
:resource_current_state_load_bypassed
A resource’s current state wasn’t loaded because the resource doesn’t support why-run mode.
:resource_bypassed
A resource action was skipped because the resource doesn’t support why-run mode.
:resource_update_applied
A change has been made to a resource. (This event occurs for each change made to a resource.)
:resource_update_progress
A resource sent a progress notification to the user to indicate overall progress of a long running operation.
:resource_failed_retriable
A resource action has failed and will be retried.
:resource_failed
A resource action has failed and won’t be retried.
:resource_updated
A resource requires modification.
:resource_up_to_date
A resource is already correct.
:resource_completed
All actions for the resource are complete.
:stream_opened
A stream has opened.
:stream_closed
A stream has closed.
:stream_output
A chunk of data from a single named stream.
:handlers_start
The handler processing phase of a Chef Infra Client run has started.
:handler_executed
The named handler was processed.
:handlers_completed
The handler processing phase of a Chef Infra Client run is complete.
:provider_requirement_failed
An assertion declared by a provider has failed.
:whyrun_assumption
An assertion declared by a provider has failed, but execution is allowed to continue because the Chef Infra Client is running in why-run mode.
:deprecation
A deprecation message has been emitted.
:attribute_changed
Prints out all the attribute changes in cookbooks or sets a policy that override attributes should never be used.
Examples
The following examples show ways to use the Handler DSL.
Send Email
Use the on
method to create an event handler that sends email when a
Chef Infra Client run fails. This will require:
- A way to tell Chef Infra Client how to send email
- An event handler that describes what to do when the
:run_failed
event is triggered - A way to trigger the exception and test the behavior of the event handler
Define How Email is Sent
Use a library to define the code that sends email when a Chef Infra
Client run fails. Name the file helper.rb
and add it to a cookbook’s
/libraries
directory:
require 'net/smtp'
module HandlerSendEmail
class Helper
def send_email_on_run_failure(node_name)
message = "From: Chef <chef@chef.io>\n"
message << "To: Grant <grantmc@chef.io>\n"
message << "Subject: Chef run failed\n"
message << "Date: #{Time.now.rfc2822}\n\n"
message << "Chef run failed on #{node_name}\n"
Net::SMTP.start('localhost', 25) do |smtp|
smtp.send_message message, 'chef@chef.io', 'grantmc@chef.io'
end
end
end
end
Add the Handler
Invoke the library helper in a recipe:
Chef.event_handler do
on :run_failed do
HandlerSendEmail::Helper.new.send_email_on_run_failure(
Chef.run_context.node.name
)
end
end
- Use
Chef.event_handler
to define the event handler - Use the
on
method to specify the event type
Within the on
block, tell Chef Infra Client how to handle the event
when it’s triggered.
Test the Handler
Use the following code block to trigger the exception and have the Chef Infra Client send email to the specified email address:
ruby_block 'fail the run' do
block do
raise 'deliberately fail the run'
end
end
etcd Locks
The following example shows how to prevent concurrent Chef Infra Client runs from both holding a lock on etcd:
lock_key = "#{node.chef_environment}/#{node.name}"
Chef.event_handler do
on :converge_start do |run_context|
Etcd.lock_acquire(lock_key)
end
end
Chef.event_handler do
on :converge_complete do
Etcd.lock_release(lock_key)
end
end
HipChat Notifications
Event messages can be sent to a team communication tool like HipChat. For example, if a Chef Infra Client run fails:
Chef.event_handler do
on :run_failed do |exception|
hipchat_notify exception.message
end
end
or send an alert on a configuration change:
Chef.event_handler do
on :resource_updated do |resource, action|
if resource.to_s == 'template[/etc/nginx/nginx.conf]'
Helper.hipchat_message("#{resource} was updated by chef")
end
end
end
attribute_changed
event hook
In a cookbook library file, you can add this to print out all attribute changes in cookbooks:
Chef.event_handler do
on :attribute_changed do |precedence, key, value|
puts "setting attribute #{precedence}#{key.map { |n| "[\"#{n}\"]" }.join} = #{value}"
end
end
If you want to setup a policy that override attributes should never be used:
Chef.event_handler do
on :attribute_changed do |precedence, key, value|
raise 'override policy violation' if precedence == :override
end
end