lib/flapjack/cli/notifier.rb in auxesis-flapjack-0.3.8 vs lib/flapjack/cli/notifier.rb in auxesis-flapjack-0.4.1
- old
+ new
@@ -3,10 +3,11 @@
require 'rubygems'
require 'ostruct'
require 'optparse'
require 'log4r'
require 'log4r/outputter/syslogoutputter'
+require File.join(File.dirname(__FILE__), '..', 'database')
module Flapjack
class NotifierOptions
def self.parse(args)
options = OpenStruct.new
@@ -19,10 +20,16 @@
options.port = port.to_i
end
opts.on('-r', '--recipients FILE', 'recipients file') do |recipients|
options.recipients = recipients.to_s
end
+ opts.on('-c', '--config FILE', 'config file') do |config|
+ options.config_filename = config.to_s
+ end
+ opts.on('-d', '--database-uri URI', 'location of the checks database') do |db|
+ options.database_uri = db.to_s
+ end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
end
@@ -41,14 +48,31 @@
options.host ||= 'localhost'
options.port ||= 11300
@errors = []
# check that recipients file exists
- unless File.exists?(options.recipients.to_s)
- @errors << "The specified recipients file doesn't exist!"
+ if options.recipients
+ unless File.exists?(options.recipients.to_s)
+ @errors << "The specified recipients file doesn't exist!"
+ end
+ else
+ @errors << "You need to specify a recipients file with [-r|--recipients]."
end
-
+
+ # check that config file exists
+ if options.config_filename
+ unless File.exists?(options.config_filename.to_s)
+ @errors << "The specified config file doesn't exist!"
+ end
+ else
+ options.config_filename ||= "/etc/flapjack/flapjack-notifier.yaml"
+ unless File.exists?(options.config_filename.to_s)
+ @errors << "The default config file (#{options.config_filename}) doesn't exist!"
+ @errors << "Set one up, or specify one with [-c|--config]."
+ end
+ end
+
# if there are errors, print them out and exit
if @errors.size > 0
puts "Errors:"
@errors.each do |error|
puts " - #{error}"
@@ -61,15 +85,17 @@
options
end
end
class NotifierCLI
- attr_accessor :log, :recipients, :notifier, :results_queue
+ attr_accessor :log, :recipients, :results_queue, :config
+ attr_accessor :notifier, :notifiers
attr_accessor :condition
- def initialize
- @log = Log4r::Logger.new("notifier")
+ def initialize(opts={})
+ @log = opts[:logger]
+ @log ||= Log4r::Logger.new("notifier")
end
def setup_loggers
@log.add(Log4r::StdoutOutputter.new('notifier'))
@log.add(Log4r::SyslogOutputter.new('notifier'))
@@ -81,32 +107,126 @@
yaml = opts[:yaml]
else
opts[:filename] ||= File.join(Dir.pwd, "recipients.yaml")
yaml = YAML::load(File.read(opts[:filename]))
end
-
+
+ # FIXME: add error detection for passing in dumb things
+
@recipients = yaml.map do |r|
OpenStruct.new(r)
end
end
+
+ def setup_config(opts={})
+ if opts[:yaml]
+ yaml = opts[:yaml]
+ else
+ opts[:filename] ||= File.join(Dir.pwd, "flapjack-notifier.yaml")
+ yaml = YAML::load(File.read(opts[:filename]))
+ end
+
+ @config = OpenStruct.new(yaml)
+ end
+
+ def setup_database(opts={})
+ uri = (opts[:database_uri] || @config.database_uri)
+ raise ArgumentError, "database URI wasn't specified!" unless uri
+ DataMapper.setup(:default, uri)
+ validate_database
+ end
+
+ def validate_database
+ begin
+ DataMapper.repository(:default).adapter.execute("SELECT 'id' FROM 'checks';")
+ rescue Sqlite3Error
+ @log.warning("The specified database doesn't appear to have any structure!")
+ @log.warning("You need to investigate this.")
+ end
+ # FIXME: add more rescues in here!
+ end
+
+ def initialize_notifiers(opts={})
+ notifiers_directory = opts[:notifiers_directory]
+ notifiers_directory ||= File.expand_path(File.join(File.dirname(__FILE__), '..', 'notifiers'))
+
+ raise ArgumentError, "notifiers directory doesn't exist!" unless File.exists?(notifiers_directory)
+
+ @notifiers = []
+
+ @config.notifiers.each_pair do |notifier, config|
+ filename = File.join(notifiers_directory, notifier.to_s, 'init')
+ if File.exists?(filename + '.rb')
+ @log.debug("Loading the #{notifier.to_s.capitalize} notifier")
+ require filename
+ @notifiers << Flapjack::Notifiers.const_get("#{notifier.to_s.capitalize}").new(config)
+ else
+ @log.warning("Flapjack::Notifiers::#{notifier.to_s.capitalize} doesn't exist!")
+ end
+ end
+
+ @notifiers
+ end
+
+ # Sets up notifier to do the grunt work of notifying people when checks
+ # return badly.
+ #
+ # Accepts a list of recipients (:recipients) and a logger (:logger) as
+ # arguments. If neither of these are specified, it will default to an
+ # existing list of recipients and the current logger.
+ #
+ # Sets up and returns @notifier, an instance of Flapjack::Notifier
+ def setup_notifier(opts={})
+ recipients = (opts[:recipients] || @recipients)
+ log = (opts[:logger] || @log)
+ initialize_notifiers
+ notifiers = @notifiers # should we accept a list of notifiers?
+ @notifier = Flapjack::Notifier.new(:logger => log,
+ :notifiers => notifiers,
+ :recipients => recipients)
+ end
def process_loop
@log.info("Processing results...")
loop do
process_result
end
end
-
+
+ def save_result(result)
+ if check = Check.get(result.id)
+ check.status = result.retval
+ check.save
+ else
+ @log.error("Got result for check #{result.id}, but it doesn't exist!")
+ end
+ end
+
+ def any_parents_warning_or_critical?(result)
+ if check = Check.get(result.id)
+ check.worst_parent_status > 0 ? true : false
+ else
+ @log.error("Got result for check #{result.id}, but it doesn't exist!")
+ end
+ end
+
def process_result
@log.debug("Waiting for new result...")
- result_job = @results_queue.reserve
+ result_job = @results_queue.reserve # blocks until a job is reserved
result = Result.new(YAML::load(result_job.body))
@log.info("Processing result for check '#{result.id}'")
if result.warning? || result.critical?
- @log.info("Notifying on check '#{result.id}'")
- @notifier.notify!(result)
+ if any_parents_warning_or_critical?(result)
+ @log.info("Not notifying on check '#{result.id}' as parent is failing.")
+ else
+ @log.info("Notifying on check '#{result.id}'")
+ @notifier.notify!(result)
+ end
end
+
+ @log.info("Storing status of check in database")
+ save_result(result)
@log.debug("Deleting result for check '#{result.id}' from queue")
result_job.delete
end