bin/check-hardware-fail.rb in sensu-plugins-hardware-1.2.0 vs bin/check-hardware-fail.rb in sensu-plugins-hardware-1.3.0
- old
+ new
@@ -23,41 +23,124 @@
# Shank Feek, Alan Smith
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
+require 'os'
require 'English'
require 'rubygems' if RUBY_VERSION < '1.9.0'
require 'sensu-plugin/check/cli'
class CheckHardwareFail < Sensu::Plugin::Check::CLI
option :lines,
short: '-l NUMBER',
long: '--lines NUMBER',
proc: proc(&:to_i),
- default: 0,
description: 'Maximum number of lines to read from dmesg, 0 (default) means all'
option :query,
short: '-q QUERY',
long: '--query QUERY',
default: 'Hardware Error',
description: 'What pattern to look for in the output of dmesg (regex or literal)'
+ option :seconds,
+ short: '-s SECONDS',
+ long: '--seconds SECONDS',
+ proc: proc(&:to_i),
+ description: 'Amount of seconds to lookbehind from dmesg output. This option is incompatible with --lines'
+
+ option :facility,
+ short: '-f FACILITY[,FACILITY]',
+ long: '--facility FACILITY[,FACILITY]',
+ description: 'Restrict output to defined facilities. Supported log facilities: kern,user,mail,daemon,auth,syslog,lpr,news',
+ required: false,
+ proc: proc { |a| a.split(',') }
+
+ option :level,
+ short: '-L LEVEL[,LEVEL]',
+ long: '--level LEVEL[,LEVEL]',
+ description: 'Restrict output to defined levels, otherwise all levels are included. Supported log levels: emerg,alert,crit,err,warn,notice,info,debug',
+ proc: proc { |a| a.split(',') }
+
+ option :kernel,
+ short: '-k',
+ long: '--kernel',
+ description: 'Include kernel messages',
+ boolean: true
+
option :invert,
long: '--invert',
description: 'Invert order',
- boolean: true,
- default: false
+ boolean: true
def run
- cmd = config[:invert] ? 'head' : 'tail'
- output = if config[:lines].zero?
- `dmesg`.lines.select { |l| l[/#{config[:query]}/] }
- else
- `dmesg | #{cmd} -n #{config[:lines]}`.lines.select { |l| l[/#{config[:query]}/] }
- end
+ # Validate options
+ unknown incompatible_options if incompatible_options
+
+ # Build the command based on the options provided
+ cmd = 'dmesg '
+ cmd += "--facility #{config[:facility].join(',')} " if config[:facility]
+ cmd += "--level #{config[:level].join(',')} " if config[:level]
+ cmd += '--kernel ' if config[:kernel]
+
+ # Run command
+ lines = `#{cmd}`.lines
unknown 'Command execution failed!' unless $CHILD_STATUS.success?
+
+ if config[:seconds]
+ uptime = File.read('/proc/uptime').split(' ').first.to_i
+ seconds_limit = uptime - config[:seconds]
+ end
+
+ # Option --invert
+ # Flipping the array to start the iteration from the last line (newest entry)
+ # unless `--invert` which means that you want to start reading from the first line (oldest entry)
+ lines.reverse! unless config[:invert]
+
+ output = []
+
+ lines.each_with_index do |line, index|
+ break if config[:lines] && index >= config[:lines]
+ if config[:seconds]
+ timestamp = line.split(']').first.delete('[').to_i
+ break if timestamp < seconds_limit
+ end
+ output << line if line[/#{config[:query]}/]
+ end
+
critical "Problem Detected: #{output[0]}" if output.any?
ok 'OK'
+ end
+
+ def incompatible_options
+ if OS.linux?
+ if incompatible_linux.any?
+ "The use of the options --seconds and [--#{incompatible_linux.join(' --')}] is incompatible."
+ elsif invalid_facility.any?
+ "Invalid dmesg facility requested: #{invalid_facility}"
+ elsif invalid_level.any?
+ "Invalid dmesg level requested: #{invalid_level}"
+ end
+ elsif OS.posix?
+ "Incompatible options: [--#{incompatible_posix.join(' --')}] for OS #{OS.host_os}" if incompatible_posix.any?
+ else
+ "OS #{OS.host_os} is not supported"
+ end
+ end
+
+ def incompatible_linux
+ config[:seconds] ? config.keys & %i[lines invert] : []
+ end
+
+ def incompatible_posix
+ config.keys & %i[facility level kernel seconds]
+ end
+
+ def invalid_facility
+ config[:facility].to_a - %w[kern user mail daemon auth syslog lpr news]
+ end
+
+ def invalid_level
+ config[:level].to_a - %w[emerg alert crit err warn notice info debug]
end
end