summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2016-05-13 14:14:04 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2016-05-13 14:14:04 -0700
commit96f8d9583c7f7e16efeac0c4fe085a83d83f5041 (patch)
tree2a0c80a5ad8b799ce790dc50e0cb1eaa5b7d8849
parent103c34b057bba9061c010b4a9836977e9a8dbb90 (diff)
downloadchef-lcg/better-handler-wiring.tar.gz
wire up chef handlers directly from librarieslcg/better-handler-wiring
smear just a little bit of minimal DSL wiring into the Chef::Report class so that classes can wire themselves up automatically as handlers. this also extends the Chef::Config[*_handler] arrays to take classes as well as instances. in the case of passing a class that is not a singleton, a new instance will be created when the report is run. it will obviously be difficult to pass any state into this instance. if the class that is passed supports calling `#instance` we assume it is a Singleton and get the instance and use that. this is to support other chef code grabbing/creating the singleton instance and poking it with data (probably configuring where the reporter goes and what creds it needs to publish and other stuff).
-rw-r--r--lib/chef/handler.rb33
-rw-r--r--spec/unit/handler_spec.rb87
2 files changed, 120 insertions, 0 deletions
diff --git a/lib/chef/handler.rb b/lib/chef/handler.rb
index b720a11a45..100ed23d9e 100644
--- a/lib/chef/handler.rb
+++ b/lib/chef/handler.rb
@@ -57,16 +57,47 @@ class Chef
#
class Handler
+ 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
+
# The list of currently configured start handlers
def self.start_handlers
Array(Chef::Config[:start_handlers])
end
+ 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 the start handlers. This will usually be called by a notification
# from Chef::Client
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.")
@@ -90,6 +121,7 @@ class Chef
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
@@ -115,6 +147,7 @@ class Chef
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
diff --git a/spec/unit/handler_spec.rb b/spec/unit/handler_spec.rb
index 65c3ddc4cb..a56645fa78 100644
--- a/spec/unit/handler_spec.rb
+++ b/spec/unit/handler_spec.rb
@@ -212,4 +212,91 @@ describe Chef::Handler do
end
end
+ describe "library report handler" do
+ before do
+ # we need to lazily declare this after we have reset Chef::Config in the default rspec before handler
+ class MyTestHandler < Chef::Handler
+ handler_for :report, :exception, :start
+
+ class << self
+ attr_accessor :ran_report
+ end
+
+ def report
+ self.class.ran_report = true
+ end
+ end
+ end
+
+ it "gets added to Chef::Config[:report_handlers]" do
+ expect(Chef::Config[:report_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:exception_handlers]" do
+ expect(Chef::Config[:exception_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:start_handlers]" do
+ expect(Chef::Config[:start_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "runs the report handler" do
+ Chef::Handler.run_report_handlers(@run_status)
+ expect(MyTestHandler.ran_report).to be true
+ end
+
+ it "runs the exception handler" do
+ Chef::Handler.run_exception_handlers(@run_status)
+ expect(MyTestHandler.ran_report).to be true
+ end
+
+ it "runs the start handler" do
+ Chef::Handler.run_start_handlers(@run_status)
+ expect(MyTestHandler.ran_report).to be true
+ end
+ end
+
+ describe "library singleton report handler" do
+ before do
+ # we need to lazily declare this after we have reset Chef::Config in the default rspec before handler
+ class MyTestHandler < Chef::Handler
+ handler_for :report, :exception, :start
+
+ include Singleton
+
+ attr_accessor :ran_report
+
+ def report
+ self.ran_report = true
+ end
+ end
+ end
+
+ it "gets added to Chef::Config[:report_handlers]" do
+ expect(Chef::Config[:report_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:exception_handlers]" do
+ expect(Chef::Config[:exception_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "gets added to Chef::Config[:start_handlers]" do
+ expect(Chef::Config[:start_handlers].include?(MyTestHandler)).to be true
+ end
+
+ it "runs the report handler" do
+ Chef::Handler.run_report_handlers(@run_status)
+ expect(MyTestHandler.instance.ran_report).to be true
+ end
+
+ it "runs the exception handler" do
+ Chef::Handler.run_exception_handlers(@run_status)
+ expect(MyTestHandler.instance.ran_report).to be true
+ end
+
+ it "runs the start handler" do
+ Chef::Handler.run_start_handlers(@run_status)
+ expect(MyTestHandler.instance.ran_report).to be true
+ end
+ end
end