for testing...
This commit is contained in:
parent
326b12db6f
commit
218e412e68
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -35,15 +35,15 @@ pkg
|
||||||
#tmtags
|
#tmtags
|
||||||
|
|
||||||
# For emacs:
|
# For emacs:
|
||||||
#*~
|
*~
|
||||||
#\#*
|
#\#*
|
||||||
#.\#*
|
#.\#*
|
||||||
|
|
||||||
# For vim:
|
# For vim:
|
||||||
#*.swp
|
*.swp
|
||||||
|
|
||||||
# For redcar:
|
# For redcar:
|
||||||
#.redcar
|
#.redcar
|
||||||
|
|
||||||
# For rubinius:
|
# For rubinius:
|
||||||
#*.rbc
|
*.rbc
|
||||||
|
|
17
Gemfile
17
Gemfile
|
@ -1,15 +1,14 @@
|
||||||
source "http://rubygems.org"
|
source "http://rubygems.org"
|
||||||
# Add dependencies required to use your gem here.
|
|
||||||
# Example:
|
gem 'enum'
|
||||||
# gem "activesupport", ">= 2.3.5"
|
|
||||||
|
|
||||||
# Add dependencies to develop your gem here.
|
# Add dependencies to develop your gem here.
|
||||||
# Include everything needed to run rake, tests, features, etc.
|
# Include everything needed to run rake, tests, features, etc.
|
||||||
group :development do
|
group :development do
|
||||||
gem "shoulda", ">= 0"
|
gem "shoulda"
|
||||||
gem "yard", "~> 0.7"
|
gem "yard"
|
||||||
gem "rdoc", "~> 3.12"
|
gem "rdoc"
|
||||||
gem "bundler", "~> 1.0.0"
|
gem "bundler"
|
||||||
gem "jeweler", "~> 1.8.4"
|
gem "jeweler"
|
||||||
gem "rcov", ">= 0"
|
gem "simplecov"
|
||||||
end
|
end
|
||||||
|
|
48
Gemfile.lock
Normal file
48
Gemfile.lock
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
GEM
|
||||||
|
remote: http://rubygems.org/
|
||||||
|
specs:
|
||||||
|
activesupport (3.2.12)
|
||||||
|
i18n (~> 0.6)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
bourne (1.1.2)
|
||||||
|
mocha (= 0.10.5)
|
||||||
|
enum (1.0.0)
|
||||||
|
git (1.2.5)
|
||||||
|
i18n (0.6.4)
|
||||||
|
jeweler (1.8.4)
|
||||||
|
bundler (~> 1.0)
|
||||||
|
git (>= 1.2.5)
|
||||||
|
rake
|
||||||
|
rdoc
|
||||||
|
json (1.7.7)
|
||||||
|
metaclass (0.0.1)
|
||||||
|
mocha (0.10.5)
|
||||||
|
metaclass (~> 0.0.1)
|
||||||
|
multi_json (1.6.1)
|
||||||
|
rake (10.0.3)
|
||||||
|
rdoc (4.0.0)
|
||||||
|
json (~> 1.4)
|
||||||
|
shoulda (3.3.2)
|
||||||
|
shoulda-context (~> 1.0.1)
|
||||||
|
shoulda-matchers (~> 1.4.1)
|
||||||
|
shoulda-context (1.0.2)
|
||||||
|
shoulda-matchers (1.4.2)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
bourne (~> 1.1.2)
|
||||||
|
simplecov (0.7.1)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
simplecov-html (~> 0.7.1)
|
||||||
|
simplecov-html (0.7.1)
|
||||||
|
yard (0.8.5.2)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
bundler
|
||||||
|
enum
|
||||||
|
jeweler
|
||||||
|
rdoc
|
||||||
|
shoulda
|
||||||
|
simplecov
|
||||||
|
yard
|
2
Rakefile
2
Rakefile
|
@ -32,6 +32,7 @@ Rake::TestTask.new(:test) do |test|
|
||||||
test.verbose = true
|
test.verbose = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
require 'rcov/rcovtask'
|
require 'rcov/rcovtask'
|
||||||
Rcov::RcovTask.new do |test|
|
Rcov::RcovTask.new do |test|
|
||||||
test.libs << 'test'
|
test.libs << 'test'
|
||||||
|
@ -39,6 +40,7 @@ Rcov::RcovTask.new do |test|
|
||||||
test.verbose = true
|
test.verbose = true
|
||||||
test.rcov_opts << '--exclude "gems/*"'
|
test.rcov_opts << '--exclude "gems/*"'
|
||||||
end
|
end
|
||||||
|
=end
|
||||||
|
|
||||||
task :default => :test
|
task :default => :test
|
||||||
|
|
||||||
|
|
319
lib/nsca.rb
319
lib/nsca.rb
|
@ -0,0 +1,319 @@
|
||||||
|
require 'socket'
|
||||||
|
require 'enum'
|
||||||
|
require 'timeout'
|
||||||
|
require 'benchmark'
|
||||||
|
|
||||||
|
module NSCA
|
||||||
|
class ReturnCode <Enum
|
||||||
|
start_at 0
|
||||||
|
enum %w[OK WARNING CRITICAL UNKNOWN]
|
||||||
|
end
|
||||||
|
|
||||||
|
# This class losly based on send_nsca `SendNsca::NscaConnection`-class.
|
||||||
|
class Connection
|
||||||
|
PACKET_VERSION = 3 # NSCA 2.9
|
||||||
|
# packet-version crc32 timestamp return-code hostname service status(incl perfdata) EOT
|
||||||
|
PACK_STRING = "n N N n a64 a128 a4096 C"
|
||||||
|
EOT = 0x17 # Seperator for more than one entry
|
||||||
|
|
||||||
|
attr_reader :xor_key, :timestamp, :socket
|
||||||
|
|
||||||
|
def initialize socket_or_host, port = nil
|
||||||
|
@socket = case socket_or_host
|
||||||
|
when String then Net::TCPSocket.new socket_or_host, port
|
||||||
|
else socket_or_host
|
||||||
|
end
|
||||||
|
# read xor_key and timestamp
|
||||||
|
xor_key_and_timestamp = @socket.recv 132
|
||||||
|
@xor_key, ts = xor_key_and_timestamp.unpack 'a128L'
|
||||||
|
@xor_key_a = @xor_key.unpack 'C*' # needed for every xor
|
||||||
|
@timestamp = Time.at ts
|
||||||
|
end
|
||||||
|
|
||||||
|
def xor msg
|
||||||
|
key_a = @xor_key_a
|
||||||
|
# Slice the message in parts of length key_a.length.
|
||||||
|
# XOR each char of a part with char at the same index in key_a.
|
||||||
|
msg.unpack( 'C*').each_slice( key_a.length).inject do |res, part|
|
||||||
|
res += part.zip( key_a).map {|a,b| a^b }.pack 'C*'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def crc32 msg
|
||||||
|
(msg.each_byte.inject 0xFFFFFFFF do |r,b|
|
||||||
|
8.times.inject( r^b) {|r,_i| (r>>1) ^ (0xEDB88320 * (r&1)) }
|
||||||
|
end) ^ 0xFFFFFFFF
|
||||||
|
end
|
||||||
|
|
||||||
|
# Builds a check-result-line for NSCA.
|
||||||
|
#
|
||||||
|
# Will be terminated by end-of-terminate.
|
||||||
|
# @param [Time,Integer,nil] timestamp Checked at this time
|
||||||
|
# @param [0..3] return_code `NSCA::ReturnCode`
|
||||||
|
# @param [String(length<64),nil] hostname If nil, local hostname will be used.
|
||||||
|
# Must be known by Nagios.
|
||||||
|
# @param [String(length<128)] service Name of Service. Must be known by Nagios.
|
||||||
|
# @param [String(length<4096)] status Status-line inclusive optional Performance Data.
|
||||||
|
def build_package timestamp, return_code, hostname, service, status
|
||||||
|
entry = [
|
||||||
|
PACKET_VERSION, # packet-version
|
||||||
|
0, # crc32 (unknown yet)
|
||||||
|
(timestamp || @timestamp).to_i,
|
||||||
|
return_code.to_i,
|
||||||
|
hostname || `hostname -f`,
|
||||||
|
service,
|
||||||
|
status # incl perfdata
|
||||||
|
]
|
||||||
|
# generate crc32 and put it at entry[2...6]
|
||||||
|
xor "#{entry[0...2]}#{crc32 entry.pack( PACK_STRING)}#{entry[6..-1]}#{EOT.chr}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Sends a check-result.
|
||||||
|
# @see #build_package
|
||||||
|
def send( *a) @socket.write build_package( *a) end
|
||||||
|
|
||||||
|
# Sends check-results
|
||||||
|
# @param [Array<NSCA::Check::Base>] results
|
||||||
|
def send_results *results
|
||||||
|
results.flatten.each do |r|
|
||||||
|
send r.timestamp, r.retcode, r.hostname, r.service, r.text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Closes connection to NSCA.
|
||||||
|
def close( *a) @socket.close( *a) end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Server
|
||||||
|
attr_reader :socket_or_host, :port, :connect
|
||||||
|
def initialize socket_or_host = nil, port = nil, &connect
|
||||||
|
@socket_or_host, @port = socket_or_host, port
|
||||||
|
@connect = connect || lambda { Connection.new @socket_or_host, @port }
|
||||||
|
end
|
||||||
|
|
||||||
|
def open &e
|
||||||
|
conn = @connect.call
|
||||||
|
if block_given?
|
||||||
|
begin yield conn
|
||||||
|
ensure conn && conn.close
|
||||||
|
end
|
||||||
|
else
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def send *results
|
||||||
|
open do |conn|
|
||||||
|
conn.send_results results
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module PerformanceData
|
||||||
|
class Base
|
||||||
|
extend Timeout
|
||||||
|
extend Benchmark
|
||||||
|
|
||||||
|
def initialize value
|
||||||
|
@value = value
|
||||||
|
end
|
||||||
|
|
||||||
|
class <<self
|
||||||
|
attr_reader :label, :unit, :warn, :crit, :min, :max
|
||||||
|
def init label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
|
||||||
|
@label, @unit, @warn, @crit, @min, @max = label.to_s, unit, warn, crit, min, max
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def measure &block
|
||||||
|
timeout ||= 0
|
||||||
|
exception = Class.new Timeout::Error
|
||||||
|
pd = perfdatas[perfdata_label]
|
||||||
|
timeout = pd.max
|
||||||
|
m = realtime do
|
||||||
|
begin
|
||||||
|
timeout timeout, exception, &block
|
||||||
|
rescue exception
|
||||||
|
end
|
||||||
|
end
|
||||||
|
new m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :value
|
||||||
|
def label() self.label end
|
||||||
|
def unit() self.unit end
|
||||||
|
def warn() self.warn end
|
||||||
|
def crit() self.crit end
|
||||||
|
def min() self.min end
|
||||||
|
def max() self.max end
|
||||||
|
|
||||||
|
def return_code
|
||||||
|
if @value.nil? then 3
|
||||||
|
elsif crit <= @value then 2
|
||||||
|
elsif warn <= @value then 1
|
||||||
|
else 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{label}=#{value}#{unit},#{warn},#{crit},#{min},#{max}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class <<self
|
||||||
|
def create label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
|
||||||
|
cl = Class.new Base
|
||||||
|
cl.init label, unit, warn, crit, min, max
|
||||||
|
end
|
||||||
|
|
||||||
|
def new label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
|
||||||
|
cl = create label, unit, warn, crit, min, max
|
||||||
|
clname = NSCA::Helper.class_name_gen label
|
||||||
|
self.const_set clname, cl if clname
|
||||||
|
cl
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Check
|
||||||
|
class Base
|
||||||
|
attr_reader :perfdatas, :return_code, :status, :timestamp
|
||||||
|
def initialize return_code = nil, status = nil, perfdatas = nil
|
||||||
|
@perfdatas = {}
|
||||||
|
init return_code, status, perfdatas, timestamp || Time.now
|
||||||
|
end
|
||||||
|
|
||||||
|
def init return_code = nil, status = nil, perfdatas = nil, timestamp = nil
|
||||||
|
@return_code = return_code if return_code
|
||||||
|
@status = status if status
|
||||||
|
perfdatas.each &method( :[]) if perfdatas
|
||||||
|
@timestamp = timestamp if timestamp
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def [] perfdata_label
|
||||||
|
pd = @perfdatas[perfdata_label]
|
||||||
|
pd && pd.value
|
||||||
|
end
|
||||||
|
|
||||||
|
def []= perfdata_label, value
|
||||||
|
cl = self.class.perfdatas[perfdata_label]
|
||||||
|
cl ||= PerformanceData::Base.create perfdata_label
|
||||||
|
@perfdatas[perfdata_label] = cl.new value
|
||||||
|
end
|
||||||
|
|
||||||
|
def text
|
||||||
|
r = "#{status || ReturnCode.find(return_code)}"
|
||||||
|
r += " | #{perfdatas.map( &:to_s).join ' '}" unless perfdatas.empty?
|
||||||
|
r
|
||||||
|
end
|
||||||
|
|
||||||
|
def measure perfdata_label, &block
|
||||||
|
@perfdatas[perfdata_label].measure &block
|
||||||
|
end
|
||||||
|
|
||||||
|
def send servers = nil
|
||||||
|
NSCA.send self, servers
|
||||||
|
end
|
||||||
|
|
||||||
|
def ok status = nil, perfdatas = nil
|
||||||
|
init ReturnCode::OK, status, perfdatas
|
||||||
|
send
|
||||||
|
end
|
||||||
|
|
||||||
|
def warning status = nil, perfdatas = nil
|
||||||
|
init ReturnCode::WARNING, status, perfdatas
|
||||||
|
send
|
||||||
|
end
|
||||||
|
alias warn warning
|
||||||
|
|
||||||
|
def critical status = nil, perfdatas = nil
|
||||||
|
init ReturnCode::CRITICAL, status, perfdatas
|
||||||
|
send
|
||||||
|
end
|
||||||
|
alias crit critical
|
||||||
|
|
||||||
|
def unknown status = nil, perfdatas = nil
|
||||||
|
init ReturnCode::UNKNOWN, status, perfdatas
|
||||||
|
send
|
||||||
|
end
|
||||||
|
|
||||||
|
def determine_return_code
|
||||||
|
rc = self.class.perfdatas.map do |label, pdc|
|
||||||
|
pd = @perfdatas[label]
|
||||||
|
if pd
|
||||||
|
pd.return_code
|
||||||
|
else
|
||||||
|
-1
|
||||||
|
end
|
||||||
|
end.max
|
||||||
|
end
|
||||||
|
|
||||||
|
def retcode
|
||||||
|
rc = return_code || determine_return_code
|
||||||
|
(0..3).include?(rc) ? rc : 3
|
||||||
|
end
|
||||||
|
|
||||||
|
class <<self
|
||||||
|
attr_reader :service, :hostname, :perfdatas
|
||||||
|
def init service, hostname = nil, perfdatas = nil
|
||||||
|
@service, @hostname, @perfdatas = service, hostname || `hostname -f`, {}
|
||||||
|
perfdatas.each {|pd| @perfdatas[pd.label] = pd }
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def ok status = nil, perfdatas = nil
|
||||||
|
new.ok status, perfdatas
|
||||||
|
end
|
||||||
|
|
||||||
|
def warning status = nil, perfdatas = nil
|
||||||
|
new.warning status, perfdatas
|
||||||
|
end
|
||||||
|
alias warn warning
|
||||||
|
|
||||||
|
def critical status = nil, perfdatas = nil
|
||||||
|
new.warning status, perfdatas
|
||||||
|
end
|
||||||
|
alias crit critical
|
||||||
|
|
||||||
|
def unknown status = nil, perfdatas = nil
|
||||||
|
new.unknown status, perfdatas
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create service, hostname = nil, perfdatas = nil
|
||||||
|
cl = Class.new Base
|
||||||
|
cl.init service, hostname, perfdatas
|
||||||
|
cl
|
||||||
|
end
|
||||||
|
|
||||||
|
def new service, hostname = nil, perfdatas = nil
|
||||||
|
cl = create service, hostname, perfdatas
|
||||||
|
clname = NSCA::Helper.class_name_gen service
|
||||||
|
self.const_set clname, cl if clname
|
||||||
|
cl
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Helper
|
||||||
|
class <<self
|
||||||
|
def class_name_gen label
|
||||||
|
clname = label.gsub( /\W+/, '_').sub /^[0-9_]+/, ''
|
||||||
|
return nil if clname.empty?
|
||||||
|
clname[0] = clname[0].upcase
|
||||||
|
clname.to_sym
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class <<self
|
||||||
|
def servers() @servers ||= [] end
|
||||||
|
|
||||||
|
def send results, servers = nil
|
||||||
|
Array.wrap( servers || NSCA.servers).each {|server| server.send results }
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,64 @@
|
||||||
require 'helper'
|
require 'helper'
|
||||||
|
|
||||||
class TestNsca < Test::Unit::TestCase
|
class TestNSCA < Test::Unit::TestCase
|
||||||
should "probably rename this file and start testing for real" do
|
end
|
||||||
flunk "hey buddy, you should probably rename this file and start testing for real"
|
|
||||||
|
class TestNSCA::ReturnCode < Test::Unit::TestCase
|
||||||
|
context 'return code' do
|
||||||
|
should( 'be 0 == OK') { assert NSCA::ReturnCode.find(0) == NSCA::ReturnCode::OK }
|
||||||
|
should( 'be 1 == WARNING') { assert NSCA::ReturnCode.find(1) == NSCA::ReturnCode::WARNING }
|
||||||
|
should( 'be 2 == CRITICAL') { assert NSCA::ReturnCode.find(2) == NSCA::ReturnCode::CRITICAL }
|
||||||
|
should( 'be 3 == UNKNOWN') { assert NSCA::ReturnCode.find(3) == NSCA::ReturnCode::UNKNOWN }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestNSCA::Helper < Test::Unit::TestCase
|
||||||
|
context 'class gen name' do
|
||||||
|
should 'generate class names' do
|
||||||
|
assert :Total_run_check_measure == NSCA::Helper.class_name_gen( 'total run check measure')
|
||||||
|
end
|
||||||
|
|
||||||
|
should 'do not generate class names, if no letter' do
|
||||||
|
assert nil == NSCA::Helper.class_name_gen( '123 321, 43 _ ?')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class TestNSCA::PerformanceData < Test::Unit::TestCase
|
||||||
|
should 'set a subclass for new PerfData-types' do
|
||||||
|
NSCA::PerformanceData.new 'subclass test'
|
||||||
|
assert_nothing_raised NameError do
|
||||||
|
assert NSCA::PerformanceData::Subclass_test, "No subclass created."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def perfdata *a
|
||||||
|
NSCA::PerformanceData.create *a
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'Created NSCA::PerformanceData-subclasses' do
|
||||||
|
should 'be the same like returned' do
|
||||||
|
cl = NSCA::PerformanceData.new 'returned and subclass the same test'
|
||||||
|
assert cl == NSCA::PerformanceData::Returned_and_subclass_the_same_test, 'Classes are not the same.'
|
||||||
|
end
|
||||||
|
should 'have a unit if given' do
|
||||||
|
assert :s == perfdata( 'have an unit test', :s).unit, "Not s as unit"
|
||||||
|
end
|
||||||
|
should 'have not a unit if not given' do
|
||||||
|
assert nil == perfdata( 'have not an unit test', nil).unit, "Not nil as unit"
|
||||||
|
end
|
||||||
|
should 'have a warn thresh if given' do
|
||||||
|
assert 3 == perfdata( 'have a warn test', nil, 3).warn, "Not 3 as warn"
|
||||||
|
end
|
||||||
|
should 'have not a warn thresh if not given' do
|
||||||
|
assert nil == perfdata( 'have not a warn test', nil, nil).warn, "Not nil as warn"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
class TestNSCA::Connection < Test::Unit::TestCase
|
||||||
|
should '' do
|
||||||
|
NSCA::Connection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue