#!/usr/bin/env ruby # # Nagios.cfg should be enabled with a command_file: # # command_file=/var/lib/nagios3/rw/nagios.cmd # # The format this script expects looks like: # [$TIMET] PROCESS_SERVICE_CHECK_RESULT;$HOSTNAME$;$SERVICEDESC$;$SERVICESTATE$;$SERVICEOUTPUT$;$SERVICEPERFDATA$ # unless $:.include?(File.dirname(__FILE__) + '/../lib/') $: << File.dirname(__FILE__) + '/../lib' end require 'optparse' require 'ostruct' require 'redis' require 'oj' Oj.default_options = { :indent => 0, :mode => :strict } require 'dante' require 'flapjack/configuration' require 'flapjack/data/event' # Nsca example line for a storage-device check: #[1393410685] PROCESS_SERVICE_CHECK_RESULT;db1.dev;STORAGE;0;Raid Set # 000 (800.0GB) is Normal. def process_input(opts) redis = opts[:redis] fifo = File.new(opts[:fifo]) begin while line = fifo.gets skip unless line split_line = line.split(" ") timestamp, passivecheck = split_line split_passive = passivecheck.split(";") timestamp = timestamp.delete('[]') check_long_output = '' object_type, entity, check, state, check_output = split_passive case when (split_line.length < 2 || split_passive.length < 5) puts "ERROR - rejecting this line; illegal format: [#{line}]" next when (timestamp !~ /^\d+$/) puts "ERROR - rejecting this line; timestamp look like a timestamp: [#{line}]" next when (object_type != 'PROCESS_SERVICE_CHECK_RESULT') puts "ERROR - rejecting this line; identifier 'PROCESS_SERVICE_CHECK_RESULT' is missing: [#{line}]" next end puts "#{object_type}, #{timestamp}, #{entity}, #{check}, #{state}, #{check_output}" state = {'0' => 'ok', '1' => 'warning', '2' => 'critical'}[state.downcase] || 'unknown' event = { 'entity' => entity, 'check' => check, 'type' => 'service', 'state' => state, 'summary' => check_output, 'details' => nil, 'time' => timestamp, } Flapjack::Data::Event.add(event, :redis => redis) end rescue Redis::CannotConnectError puts "Error, unable to to connect to the redis server (#{$!})" end end def main(opts) fifo = opts[:fifo] redis = Redis.new(opts[:redis_options]) while true process_input(:redis => redis, :fifo => fifo) puts "Whoops with the fifo, restarting main loop in 10 seconds" sleep 10 end end options = OpenStruct.new options.config = Flapjack::Configuration::DEFAULT_CONFIG_PATH options.daemonize = nil exe = File.basename(__FILE__) optparse = OptionParser.new do |opts| opts.banner = "Usage: #{exe} COMMAND [OPTIONS]" opts.separator "" opts.separator "Commands" opts.separator " start #{" " * 25} start #{exe}" opts.separator " stop #{" " * 26} stop #{exe}" opts.separator " restart #{" " * 23} (re)start #{exe}" opts.separator " status #{" " * 24} see if #{exe} is running" opts.separator "" opts.separator "Options" opts.on("-c", "--config [PATH]", String, "PATH to the config file to use") do |c| options.config = c end opts.on("-f", "--fifo FIFO", String, "Path to the nagios perfdata named pipe") do |f| options.fifo = f end opts.on("-d", "--[no-]daemonize", "Daemonize?") do |d| options.daemonize = d end opts.on("-p", "--pidfile [PATH]", String, "PATH to the pidfile to write to") do |pid| options.pidfile = pid end opts.on("-l", "--logfile [PATH]", String, "PATH to the logfile to write to") do |l| options.logfile = l end opts.on_tail("-h", "--help", "Show this usage message") do puts opts puts ' Required Nagios Configuration Changes ------------------------------------- flapjack-nsca-receiver reads events from the nagios "command file" read from by Nagios, written to by the Nsca-daemon. The named pipe is automatically created by _nagios_ if it is enabled in the configfile: # modified lines: command_file=/var/lib/nagios3/rw/nagios.cmd The Nsca daemon is optionally writing to a tempfile if the named pipe does not exist. Details on the wiki: https://github.com/flpjck/flapjack/wiki/USING#XXX ' exit end end optparse.parse!(ARGV) FLAPJACK_ENV = ENV['FLAPJACK_ENV'] || 'production' config = Flapjack::Configuration.new config.load(options.config) config_env = config.all redis_options = config.for_redis if config_env.nil? || config_env.empty? puts "No config data for environment '#{FLAPJACK_ENV}' found in '#{options.config}'" puts optparse exit 1 end config_nr = config_env['nsca-receiver'] || {} pidfile = options.pidfile.nil? ? (config_nr['pid_file'] || "/var/run/flapjack/#{exe}.pid") : options.pidfile logfile = options.logfile.nil? ? (config_nr['log_file'] || "/var/log/flapjack/#{exe}.log") : options.logfile fifo = options.fifo.nil? ? (config_nr['fifo'] || '/var/lib/nagios3/rw/nagios.cmd') : options.fifo daemonize = options.daemonize.nil? ? !!config_nr['daemonize'] : options.daemonize runner = Dante::Runner.new(exe, :pid_path => pidfile, :log_path => logfile) case ARGV[0] when "start", "restart" unless File.exist?(fifo) raise "No fifo (named pipe) file found at #{fifo}" end unless File.pipe?(fifo) raise "The file at #{fifo} is not a named pipe, try using mkfifo to make one" end unless File.readable?(fifo) raise "The fifo (named pipe) at #{fifo} is unreadable" end end case ARGV[0] when "start" if runner.daemon_running? puts "#{exe} is already running." exit 1 else print "#{exe} starting..." runner.execute(:daemonize => daemonize) { main(:redis_options => redis_options, :fifo => fifo) } puts " done." end when "stop" if runner.daemon_running? print "#{exe} stopping..." runner.execute(:kill => true) puts " done." else puts "#{exe} is not running." exit 1 end when "restart" print "#{exe} restarting..." runner.execute(:daemonize => true, :restart => true) { main(:redis_options => redis_options, :fifo => fifo) } puts " done." when "status" uptime = (runner.daemon_running?) ? Time.now - File.stat(pidfile).ctime : 0 if runner.daemon_running? puts "#{exe} is running: #{uptime}" else puts "#{exe} is not running" exit 3 end else if ARGV.nil? || ARGV.empty? puts "No command provided" else puts "Unknown command provided: '#{ARGV[0]}'" end puts "\n#{optparse}" exit 1 end