From ee60209b3ccf1f7a52058f18709d73db4d002369 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Wed, 24 Apr 2013 16:26:02 +0200 Subject: [PATCH 01/12] checks: @perfdatas should user symbols as keys. +test --- lib/nsca/check.rb | 9 +++------ test/test_nsca.rb | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/nsca/check.rb b/lib/nsca/check.rb index 569d950..ef35c94 100644 --- a/lib/nsca/check.rb +++ b/lib/nsca/check.rb @@ -107,7 +107,7 @@ module NSCA end def push *perfdatas - perfdatas.each {|perfdata| @perfdatas[perfdata.label] = perfdata } + perfdatas.each {|perfdata| @perfdatas[perfdata.label.to_sym] = perfdata } @perfdatas end @@ -122,6 +122,7 @@ module NSCA def []= perfdata_label, value return push value if value.is_a? PerformanceData::Base + perfdata_label = perfdata_label.to_sym @perfdatas[perfdata_label] = perfdata_for( perfdata_label).new value end @@ -146,11 +147,7 @@ module NSCA def determine_return_code self.class.perfdatas.map do |label, pdc| pd = @perfdatas[label] - if pd - pd.return_code - else - -1 - end + pd ? pd.return_code : -1 end.max end diff --git a/test/test_nsca.rb b/test/test_nsca.rb index 18f987f..bc6c24a 100644 --- a/test/test_nsca.rb +++ b/test/test_nsca.rb @@ -227,4 +227,18 @@ class TestNSCA::Check < Test::Unit::TestCase assert_equal ce1_data, ce2_data end end + + context 'Perfdatas in Checks' do + should 'be saved as symbol-key' do + PH = NSCA::PerformanceData.new 'simplename', :ms + CH = NSCA::Check.new 'a check with perfdata', 'hostname', [PH] + assert_equal PH, CH.perfdatas[:'simplename'] + ch = CH.new + assert_equal nil, ch['simplename'] + assert_equal nil, ch[:simplename] + a = 0 + ch.measure( 'simplename') { 0.upto( 10000) { a += 1 } } + assert_equal ch['simplename'], ch[:simplename] + end + end end From 161e6739e5ccd6fe0b36d69fb17a5defe8ca1561 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Wed, 24 Apr 2013 16:26:14 +0200 Subject: [PATCH 02/12] Version bump to 0.2.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 341cf11..7dff5b8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 \ No newline at end of file +0.2.1 \ No newline at end of file From 9ac69477a018d91b0ff65689c678154a83a5bde8 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Wed, 24 Apr 2013 16:26:18 +0200 Subject: [PATCH 03/12] Regenerate gemspec for version 0.2.1 --- nsca.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nsca.gemspec b/nsca.gemspec index d6957c2..d763177 100644 --- a/nsca.gemspec +++ b/nsca.gemspec @@ -5,11 +5,11 @@ Gem::Specification.new do |s| s.name = "nsca" - s.version = "0.2.0" + s.version = "0.2.1" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Denis Knauf"] - s.date = "2013-04-11" + s.date = "2013-04-24" s.description = "Create your alerts easily and send it to Nagios" s.email = "Denis.Knauf@gmail.com" s.extra_rdoc_files = [ From 8249577e7afa26a91a2a473056f484eab1499c99 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Wed, 24 Apr 2013 16:55:46 +0200 Subject: [PATCH 04/12] perfdata-labels: quote. --- lib/nsca/check.rb | 2 +- test/test_nsca.rb | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/nsca/check.rb b/lib/nsca/check.rb index ef35c94..23250de 100644 --- a/lib/nsca/check.rb +++ b/lib/nsca/check.rb @@ -51,7 +51,7 @@ module NSCA def min() self.class.min end def max() self.class.max end def to_a() [label, value, unit, warn, crit, min, max] end - def to_s() "#{label}=#{value}#{unit},#{warn},#{crit},#{min},#{max}" end + def to_s() "'#{label.gsub /[\n'\|]/, ''}'=#{value}#{unit},#{warn},#{crit},#{min},#{max}" end def to_sym() self.class.to_sym end def to_h diff --git a/test/test_nsca.rb b/test/test_nsca.rb index bc6c24a..46d5f38 100644 --- a/test/test_nsca.rb +++ b/test/test_nsca.rb @@ -58,8 +58,8 @@ class TestNSCACommunication < Test::Unit::TestCase assert_equal test.retcode, packet.return_code end # original with B, but B is char 512 and will be replaced by \0 - assert_equal pc0.status, "0123456789"*51+"A" - assert_equal pc1.status, "Should be OK | pd1_in_sec=3s,10,20,0,30 pd2_in_1=0.99961,0.99,0.98,0,1 pd3_count=2c,3,5,0," + assert_equal "0123456789"*51+"A", pc0.status + assert_equal "Should be OK | 'pd1_in_sec'=3s,10,20,0,30 'pd2_in_1'=0.99961,0.99,0.98,0,1 'pd3_count'=2c,3,5,0,", pc1.status end should 'fail crc32 if wrong password' do @@ -71,9 +71,7 @@ class TestNSCACommunication < Test::Unit::TestCase server = Thread.new { NSCA.dummy_server Port, password: password } sleep 1 # server needs time to start... NSCA::send T3.new( 1, 'status', nil, timestamp) - assert_raise NSCA::Packet::CSC32CheckFailed do - server.join - end + assert_raise( NSCA::Packet::CSC32CheckFailed) { server.join } end end end From a2b6bde0571cbde0fa06997132d873dd7547dbf3 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:26:42 +0200 Subject: [PATCH 05/12] compatibility to nsca-2.9 (NSCA::Packet3__2_9) --- lib/nsca.rb | 50 ++++++++++++++++++++++++++++++++ lib/nsca/check.rb | 5 ++++ lib/nsca/client.rb | 19 ++++++++---- lib/nsca/packet.rb | 72 +++++++++++++++++++--------------------------- lib/nsca/server.rb | 34 +++++++++++++++------- test/test_nsca.rb | 40 +++++++++++++++++--------- 6 files changed, 148 insertions(+), 72 deletions(-) diff --git a/lib/nsca.rb b/lib/nsca.rb index 766c1a0..a60ffc6 100644 --- a/lib/nsca.rb +++ b/lib/nsca.rb @@ -18,6 +18,35 @@ module NSCA clname[0] = clname[0].upcase clname.to_sym end + + def xor_stream key + key = case key + when Array then key + when String then key.bytes.to_a + when Enumerable then key.to_a + end + return lambda{|x|x} if [nil, '', []].include? key + length = key.length + i = 0 + lambda do |str| + r = '' + str.bytes.each_with_index do |c, j| + r[j] = (c ^ key[i]).chr + i = (i + 1) % length + end + r + end + end + + def crc32_stream + sum = 0xFFFFFFFF + lambda do |str| + sum = str.bytes.inject sum do |r, b| + 8.times.inject( r^b) {|r,_i| (r>>1) ^ (0xEDB88320 * (r&1)) } + end if str + sum ^ 0xFFFFFFFF + end + end end end @@ -28,6 +57,27 @@ module NSCA NSCA.destinations.each {|server| server.send *results } self end + + def xor key, msg = nil, key_a = nil + NSCA::Helper.xor_stream( key_a || key)[ msg] + end + + def crc32 msg + NSCA::Helper.crc32_stream[ msg] + end + + # Builds a null terminated, null padded string of length maxlen + def str2cstr( str, maxlen = nil) + str = str.to_s + str = str.to_s[0..(maxlen-2)] if maxlen + "#{str}\x00" + end + def str2nstr( str, maxlen = nil) + str = str.to_s.gsub( ' ', "\x00") + "#{str} " + end + def cstr2str( str, maxlen = nil) str[ 0, str.index( ?\0) || ((maxlen||str.length+1)-1)] end + def nstr2str( str, maxlen = nil) str[ 0, str.index( ' ') || ((maxlen||str.length+1)-1)].gsub( "\x00", ' ') end end end diff --git a/lib/nsca/check.rb b/lib/nsca/check.rb index 23250de..f305785 100644 --- a/lib/nsca/check.rb +++ b/lib/nsca/check.rb @@ -163,6 +163,11 @@ module NSCA {timestamp: timestamp, return_code: retcode, hostname: hostname, server: service, status: text} end + def to_packet version = nil + version ||= PacketV3 + version.new timestamp, retcode, hostname, service, text + end + class <] results def send *results - results.flatten.each do |r| - send_packet r.timestamp, r.retcode, r.hostname, r.service, r.text - end + results.flatten.each &method(:send_packet) end # Closes connection to NSCA. @@ -85,7 +92,7 @@ module NSCA @hostname, @port, @password = hostname, port, password end - def open( &e) Connection.open @hostname, @port, @password, &e end + def open( &e) Connection.open hostname: @hostname, port: @port, password: @password, &e end def send( *results) open {|conn| conn.send results } end end end diff --git a/lib/nsca/packet.rb b/lib/nsca/packet.rb index 9dca72b..204863f 100644 --- a/lib/nsca/packet.rb +++ b/lib/nsca/packet.rb @@ -1,29 +1,4 @@ module NSCA - class <>1) ^ (0xEDB88320 * (r&1)) } - end) ^ 0xFFFFFFFF - end - - # Builds a null terminated, null padded string of length maxlen - def str2cstr( str, maxlen = nil) - str = str.to_s - str = str.to_s[0..(maxlen-2)] if maxlen - "#{str}\x00" - end - def cstr2str( str, maxlen = nil) str[ 0, x.index( ?\0) || ((maxlen||0)-1)] end - end - class Packet class CSC32CheckFailed ') + @xor_password = NSCA::Helper.xor_stream @password + @xor_iv_key = NSCA::Helper.xor_stream @iv_key end def fetch - data = read - @packet_version.parse data, @iv_key, @password if data + iv_key = NSCA::Helper.xor_stream @iv_key + password = NSCA::Helper.xor_stream @password + packet_version = iv_key[ password[ read PacketV3::PACKET_VERSION]] + v = packet_version.unpack( 's>').first + case v + when 3 + data = packet_version + iv_key[ password[ read( PacketV3::PACK_LENGTH - PacketV3::PACKET_VERSION)]] + begin + return PacketV3.parse( data) + rescue NSCA::Packet::CSC32CheckFailed + x = read( PacketV3__2_9::PACK_LENGTH - data.length) + raise if x.nil? + return PacketV3__2_9.parse( data + iv_key[ password[ x]]) + end + else raise "Unknown Version #{v.inspect}" + end end def each &block return Enumerator.new( self) unless block_given? - while data = fetch - yield data - end + yield fetch until eof? end def eof?() @socket.eof? end - def read() @socket.read @packet_length end + def read( len = nil) @socket.read( len || @packet_length) end def close() @socket.close end end end diff --git a/test/test_nsca.rb b/test/test_nsca.rb index 46d5f38..54690e4 100644 --- a/test/test_nsca.rb +++ b/test/test_nsca.rb @@ -18,20 +18,34 @@ end class TestNSCACommunication < Test::Unit::TestCase Port = 5787 + def dummy_server *args + server = Thread.new do + begin + NSCA.dummy_server *args + rescue Object + #STDERR.puts "#{$!.class}: #{$!}", $!.backtrace.map{|bt|" #{bt}"} + raise + ensure + #STDERR.puts "Dummy Server Shutdown" + end + end + sleep 1 # server needs time to start... + server + end include NSCA::Checks context "our dummy test server on localhost:#{Port} with random password" do should 'receive data' do - password = SecureRandom.random_bytes + password = 'password' || SecureRandom.random_bytes timestamp = Time.now PD1 = perfdata :pd1_in_sec, :s, 10, 20, 0, 30 PD2 = perfdata :pd2_in_1, 1, 0.99, 0.98, 0, 1 PD3 = perfdata :pd3_count, :c, 3, 5, 0 - T0 = check 'TestNSCA0', 'uxnags01-sbe.net.mobilkom.at' - T1 = check 'TestNSCA1', 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2] - T2 = check :TestNSCA2, 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2, PD3] + T0 = check 'TestNSCA0', 'localhost' + T1 = check 'TestNSCA1', 'localhost', [PD1, PD2] + T2 = check :TestNSCA2, 'localhost', [PD1, PD2, PD3] checks = [] t0 = T0.new( 1, "0123456789"*51+"AB", nil, timestamp) # oversized service name @@ -44,10 +58,9 @@ class TestNSCACommunication < Test::Unit::TestCase checks << t1 NSCA::destinations.clear - NSCA::destinations << NSCA::Client.new( 'localhost', Port, password: password) + NSCA::destinations << NSCA::Client.new( 'localhost', Port, password) - server = Thread.new { NSCA.dummy_server Port, password: password } - sleep 1 # server needs time to start... + server = dummy_server port: Port, password: password NSCA::send *checks pc0, pc1 = server.value @@ -57,20 +70,19 @@ class TestNSCACommunication < Test::Unit::TestCase assert_equal timestamp.to_i, packet.timestamp.to_i assert_equal test.retcode, packet.return_code end - # original with B, but B is char 512 and will be replaced by \0 + # original with AB, but B is char 512 and will be replaced by \0 assert_equal "0123456789"*51+"A", pc0.status assert_equal "Should be OK | 'pd1_in_sec'=3s,10,20,0,30 'pd2_in_1'=0.99961,0.99,0.98,0,1 'pd3_count'=2c,3,5,0,", pc1.status end should 'fail crc32 if wrong password' do - password = SecureRandom.random_bytes + password = 'password' || SecureRandom.random_bytes timestamp = Time.now - T3 = check 'TestNSCA0', 'uxnags01-sbe.net.mobilkom.at' + T3 = check 'TestNSCA0', 'localhost' NSCA::destinations.clear - NSCA::destinations << NSCA::Client.new( 'localhost', Port, password: password+'a') - server = Thread.new { NSCA.dummy_server Port, password: password } - sleep 1 # server needs time to start... - NSCA::send T3.new( 1, 'status', nil, timestamp) + NSCA::destinations << NSCA::Client.new( 'localhost', Port, password+'a') + server = dummy_server hostname: 'localhost', port: Port, password: password + NSCA::send [T3.new( 1, 'status', nil, timestamp)] assert_raise( NSCA::Packet::CSC32CheckFailed) { server.join } end end From 11d0f09c6d018df21ba9174c0601281d7f84a09e Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:35:20 +0200 Subject: [PATCH 06/12] random padding bytes for strings --- lib/nsca.rb | 9 ++++++--- lib/nsca/packet.rb | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/nsca.rb b/lib/nsca.rb index a60ffc6..d3cb622 100644 --- a/lib/nsca.rb +++ b/lib/nsca.rb @@ -67,15 +67,18 @@ module NSCA end # Builds a null terminated, null padded string of length maxlen - def str2cstr( str, maxlen = nil) + def str2cstr str, maxlen = nil str = str.to_s str = str.to_s[0..(maxlen-2)] if maxlen "#{str}\x00" end - def str2nstr( str, maxlen = nil) - str = str.to_s.gsub( ' ', "\x00") + def rand_padding( str, maxlen) str + SecureRandom.random_bytes( maxlen - str.length) end + def str2cstr_rand_padding( str, maxlen = nil) rand_padding str2cstr( str, maxlen), maxlen end + def str2nstr str, maxlen = nil + str = str.to_s.gsub ' ', "\x00" "#{str} " end + def str2nstr_rand_padding( str, maxlen = nil) rand_padding str2nstr( str, maxlen), maxlen end def cstr2str( str, maxlen = nil) str[ 0, str.index( ?\0) || ((maxlen||str.length+1)-1)] end def nstr2str( str, maxlen = nil) str[ 0, str.index( ' ') || ((maxlen||str.length+1)-1)].gsub( "\x00", ' ') end end diff --git a/lib/nsca/packet.rb b/lib/nsca/packet.rb index 204863f..ccbbc87 100644 --- a/lib/nsca/packet.rb +++ b/lib/nsca/packet.rb @@ -60,9 +60,9 @@ module NSCA 0, # crc32 (unknown yet) (timestamp || Time.now).to_i, return_code.to_i, - NSCA::str2cstr( hostname || `hostname -f`, cl::HOSTNAME_LENGTH), - NSCA::str2cstr( service, cl::SERVICE_LENGTH), - NSCA::str2cstr( status, cl::PLUGIN_OUTPUT_LENGTH) # incl perfdata + NSCA::str2cstr_rand_padding( hostname || `hostname -f`, cl::HOSTNAME_LENGTH), + NSCA::str2cstr_rand_padding( service, cl::SERVICE_LENGTH), + NSCA::str2cstr_rand_padding( status, cl::PLUGIN_OUTPUT_LENGTH) # incl perfdata ] # generate crc32 and put it at entry[2...6] entry[1] = NSCA::crc32 entry.pack( cl::PACK_STRING) From e230f74bcdd164ae085201491c23de92a02f8902 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:36:20 +0200 Subject: [PATCH 07/12] copyright & homepage --- README.md | 2 +- Rakefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7969a51..9a77f28 100644 --- a/README.md +++ b/README.md @@ -34,5 +34,5 @@ DONE Copyright ========= -Copyright (c) 2013 Denis Knauf. See LICENSE.txt for +Copyright (c) 2013-2015 Denis Knauf. See LICENSE.txt for further details. diff --git a/Rakefile b/Rakefile index 852c6e2..0a2131f 100644 --- a/Rakefile +++ b/Rakefile @@ -15,7 +15,7 @@ require 'jeweler' Jeweler::Tasks.new do |gem| # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options gem.name = "nsca" - gem.homepage = "http://github.com/DenisKnauf/nsca" + gem.homepage = "http://github.com/DenisKnauf/ruby-nsca" gem.license = "LGPL-3" gem.summary = %Q{Nagios passive alerts with friendly API} gem.description = %Q{Create your alerts easily and send it to Nagios} From 270df6c90fdad262953fc3bc8f45459d0f311f91 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:40:24 +0200 Subject: [PATCH 08/12] file-linking-test --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9a77f28..162171f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ This is a ruby-pure implementation. First it was planed to provide a client-API, but now there is also a full server-API. -Tested against nsca-2.7. +Tested against nsca-2.7, -2.9. TO DO AND DONE ============== @@ -34,5 +34,4 @@ DONE Copyright ========= -Copyright (c) 2013-2015 Denis Knauf. See LICENSE.txt for -further details. +Copyright (c) 2013-2015 Denis Knauf. See [[LICENSE.txt]] for further details. From a13080c8feb5f8f87b6f2f60fe2cc8bcf53d5894 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:40:46 +0200 Subject: [PATCH 09/12] file-linking-test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 162171f..a72bf90 100644 --- a/README.md +++ b/README.md @@ -34,4 +34,4 @@ DONE Copyright ========= -Copyright (c) 2013-2015 Denis Knauf. See [[LICENSE.txt]] for further details. +Copyright (c) 2013-2015 Denis Knauf. See [LICENSE.txt] for further details. From 511ae1e9ebe9d7c0e7e4ff139d5b19992a502850 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:42:26 +0200 Subject: [PATCH 10/12] file-linking-test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a72bf90..83744c5 100644 --- a/README.md +++ b/README.md @@ -34,4 +34,4 @@ DONE Copyright ========= -Copyright (c) 2013-2015 Denis Knauf. See [LICENSE.txt] for further details. +Copyright (c) 2013-2015 Denis Knauf. See [LICENSE.txt]() for further details. From cf6610318c689b54c5df126d72f76d1ffea3e93f Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:43:08 +0200 Subject: [PATCH 11/12] file-linking-test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83744c5..7a96325 100644 --- a/README.md +++ b/README.md @@ -34,4 +34,4 @@ DONE Copyright ========= -Copyright (c) 2013-2015 Denis Knauf. See [LICENSE.txt]() for further details. +Copyright (c) 2013-2015 Denis Knauf. See [LICENSE.txt](LICENSE.txt) for further details. From 56045ae80dbc0a4db6590b02e5865a2ad384dd2e Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Fri, 3 Jul 2015 15:45:45 +0200 Subject: [PATCH 12/12] usage --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 7a96325..e82d254 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,16 @@ First it was planed to provide a client-API, but now there is also a full server Tested against nsca-2.7, -2.9. +Usage +===== + +Simple sending + +```ruby +NSCA.destinations << NSCA::Client.new('localhost') +NSCA.send 'serverA', 'serviceA', 1, 'Ok' +``` + TO DO AND DONE ==============