Class: Chef::Handler

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/chef/handler.rb,
lib/chef/handler/json_file.rb,
lib/chef/handler/slow_report.rb,
lib/chef/handler/error_report.rb

Overview

The base class for an Exception or Notification Handler. Create your own handler by subclassing Chef::Handler. When a Chef run fails with an uncaught Exception, Chef will set the +run_status+ on your handler and call +report+

Examples:

require 'net/smtp'

module MyOrg
  class OhNoes < Chef::Handler

    def report
      # Create the email message
      message  = "From: Your Name <[email protected]>\n"
      message << "To: Destination Address <[email protected]>\n"
      message << "Subject: Chef Run Failure\n"
      message << "Date: #{Time.now.rfc2822}\n\n"

      # The Node is available as +node+
      message << "Chef run failed on #{node.name}\n"
      # +run_status+ is a value object with all of the run status data
      message << "#{run_status.formatted_exception}\n"
      # Join the backtrace lines. Coerce to an array just in case.
      message << Array(backtrace).join("\n")

      # Send the email
      Net::SMTP.start('your.smtp.server', 25) do |smtp|
        smtp.send_message message, 'from@address', 'to@address'
      end
    end

  end
end

Direct Known Subclasses

ErrorReport, JsonFile, SlowReport

Defined Under Namespace

Classes: ErrorReport, JsonFile, SlowReport

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#run_statusObject (readonly)

The Chef::RunStatus object containing data about the Chef run.



170
171
172
# File 'lib/chef/handler.rb', line 170

def run_status
  @run_status
end

Class Method Details

.exception_handlersObject

The list of currently configured exception handlers



143
144
145
# File 'lib/chef/handler.rb', line 143

def self.exception_handlers
  Array(Chef::Config[:exception_handlers])
end

.handler_for(*args) ⇒ Object

FIXME: Chef::Handler should probably inherit from EventDispatch::Base and should wire up to those events rather than the "notifications" system which is hanging off of Chef::Client. Those "notifications" could then be deprecated in favor of events, and this class could become decoupled from the Chef::Client object.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/chef/handler.rb', line 64

def self.handler_for(*args)
  if args.include?(:start)
    Chef::Config[:start_handlers] ||= []
    Chef::Config[:start_handlers] |= [self]
  end
  if args.include?(:report)
    Chef::Config[:report_handlers] ||= []
    Chef::Config[:report_handlers] |= [self]
  end
  if args.include?(:exception)
    Chef::Config[:exception_handlers] ||= []
    Chef::Config[:exception_handlers] |= [self]
  end
end

.report_handlersObject

The list of currently configured report handlers



117
118
119
# File 'lib/chef/handler.rb', line 117

def self.report_handlers
  Array(Chef::Config[:report_handlers])
end

.resolve_handler_instance(handler) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/chef/handler.rb', line 84

def self.resolve_handler_instance(handler)
  if handler.is_a?(Class)
    if handler.respond_to?(:instance)
      # support retrieving a Singleton reporting object
      handler.instance
    else
      # just a class with no way to insert data
      handler.new
    end
  else
    # the Chef::Config array contains an instance, not a class
    handler
  end
end

.run_exception_handlers(run_status) ⇒ Object

Run the exception handlers. Usually will be called by a notification from Chef::Client when the run fails.



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/chef/handler.rb', line 149

def self.run_exception_handlers(run_status)
  events = run_status.events
  events.handlers_start(exception_handlers.size)
  Chef::Log.error("Running exception handlers")
  exception_handlers.each do |handler|
    handler = resolve_handler_instance(handler)
    handler.run_report_safely(run_status)
    events.handler_executed(handler)
  end
  events.handlers_completed
  Chef::Log.error("Exception handlers complete")
end

.run_report_handlers(run_status) ⇒ Object

Run the report handlers. This will usually be called by a notification from Chef::Client



123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/chef/handler.rb', line 123

def self.run_report_handlers(run_status)
  events = run_status.events
  events.handlers_start(report_handlers.size)
  Chef::Log.info("Running report handlers")
  report_handlers.each do |handler|
    handler = resolve_handler_instance(handler)
    handler.run_report_safely(run_status)
    events.handler_executed(handler)
  end
  events.handlers_completed
  Chef::Log.info("Report handlers complete")
end

.run_start_handlers(run_status) ⇒ Object

Run the start handlers. This will usually be called by a notification from Chef::Client



101
102
103
104
105
106
107
108
# File 'lib/chef/handler.rb', line 101

def self.run_start_handlers(run_status)
  Chef::Log.info("Running start handlers")
  start_handlers.each do |handler|
    handler = resolve_handler_instance(handler)
    handler.run_report_safely(run_status)
  end
  Chef::Log.info("Start handlers complete.")
end

.start_handlersObject

The list of currently configured start handlers



80
81
82
# File 'lib/chef/handler.rb', line 80

def self.start_handlers
  Array(Chef::Config[:start_handlers])
end

Instance Method Details

#action_collectionObject



269
270
271
# File 'lib/chef/handler.rb', line 269

def action_collection
  @run_status.run_context.action_collection
end

#all_resourcesObject



218
219
220
# File 'lib/chef/handler.rb', line 218

def all_resources
  @all_resources ||= action_collection&.filtered_collection(unprocessed: false)&.resources || []
end

#dataObject

Return the Hash representation of the run_status



300
301
302
# File 'lib/chef/handler.rb', line 300

def data
  @run_status.to_h
end

#failed_resourcesObject



236
237
238
# File 'lib/chef/handler.rb', line 236

def failed_resources
  @failed_resources ||= action_collection&.filtered_collection(updated: false, up_to_date: false, skipped: false, unprocessed: false)&.resources || []
end

#reportObject

The main entry point for report handling. Subclasses should override this method with their own report handling logic.



275
# File 'lib/chef/handler.rb', line 275

def report; end

#run_report_safely(run_status) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Runs the report handler, rescuing and logging any errors it may cause. This ensures that all handlers get a chance to run even if one fails. This method should not be overridden by subclasses unless you know what you're doing.



283
284
285
286
287
288
289
290
# File 'lib/chef/handler.rb', line 283

def run_report_safely(run_status)
  run_report_unsafe(run_status)
rescue Exception => e
  Chef::Log.error("Report handler #{self.class.name} raised #{e.inspect}")
  Array(e.backtrace).each { |line| Chef::Log.error(line) }
ensure
  @run_status = nil
end

#run_report_unsafe(run_status) ⇒ Object

Runs the report handler without any error handling. This method should not be used directly except in testing.



294
295
296
297
# File 'lib/chef/handler.rb', line 294

def run_report_unsafe(run_status)
  @run_status = run_status
  report
end

#skipped_resourcesObject



242
243
244
# File 'lib/chef/handler.rb', line 242

def skipped_resources
  @skipped_resources ||= action_collection&.filtered_collection(updated: false, up_to_date: false, failed: false, unprocessed: false)&.resources || []
end

#unprocessed_resourcesObject

Unprocessed resources are those which are left over in the outer recipe context when a run fails. Sub-resources of unprocessed resourced are impossible to capture because they would require processing the outer resource.



252
253
254
# File 'lib/chef/handler.rb', line 252

def unprocessed_resources
  @unprocessed_resources ||= action_collection&.filtered_collection(updated: false, up_to_date: false, failed: false, skipped: false)&.resources || []
end

#up_to_date_resourcesObject



230
231
232
# File 'lib/chef/handler.rb', line 230

def up_to_date_resources
  @up_to_date_resources ||= action_collection&.filtered_collection(updated: false, skipped: false, failed: false, unprocessed: false)&.resources || []
end

#updated_resourcesObject



224
225
226
# File 'lib/chef/handler.rb', line 224

def updated_resources
  @updated_resources ||= action_collection&.filtered_collection(up_to_date: false, skipped: false, failed: false, unprocessed: false)&.resources || []
end