nsca 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'enum'
4
+
5
+ # Add dependencies to develop your gem here.
6
+ # Include everything needed to run rake, tests, features, etc.
7
+ group :development do
8
+ gem "shoulda"
9
+ gem "yard"
10
+ gem "rdoc"
11
+ gem "bundler"
12
+ gem "jeweler"
13
+ gem "simplecov"
14
+ end
@@ -0,0 +1,48 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.13)
5
+ i18n (= 0.6.1)
6
+ multi_json (~> 1.0)
7
+ bourne (1.4.0)
8
+ mocha (~> 0.13.2)
9
+ enum (1.0.0)
10
+ git (1.2.5)
11
+ i18n (0.6.1)
12
+ jeweler (1.8.4)
13
+ bundler (~> 1.0)
14
+ git (>= 1.2.5)
15
+ rake
16
+ rdoc
17
+ json (1.7.7)
18
+ metaclass (0.0.1)
19
+ mocha (0.13.3)
20
+ metaclass (~> 0.0.1)
21
+ multi_json (1.7.2)
22
+ rake (10.0.4)
23
+ rdoc (4.0.1)
24
+ json (~> 1.4)
25
+ shoulda (3.4.0)
26
+ shoulda-context (~> 1.0, >= 1.0.1)
27
+ shoulda-matchers (~> 1.0, >= 1.4.1)
28
+ shoulda-context (1.1.0)
29
+ shoulda-matchers (1.5.6)
30
+ activesupport (>= 3.0.0)
31
+ bourne (~> 1.3)
32
+ simplecov (0.7.1)
33
+ multi_json (~> 1.0)
34
+ simplecov-html (~> 0.7.1)
35
+ simplecov-html (0.7.1)
36
+ yard (0.8.5.2)
37
+
38
+ PLATFORMS
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ bundler
43
+ enum
44
+ jeweler
45
+ rdoc
46
+ shoulda
47
+ simplecov
48
+ yard
@@ -0,0 +1,165 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
@@ -0,0 +1,38 @@
1
+ pure ruby NSCA library
2
+ ======================
3
+
4
+ NSCA is a protocol for Nagios passive checks.
5
+ You must run nsca on your server to use it.
6
+
7
+ This is a ruby-pure implementation.
8
+
9
+ First it was planed to provide a client-API, but now there is also a full server-API.
10
+
11
+ Tested against nsca-2.7.
12
+
13
+ TO DO AND DONE
14
+ ==============
15
+
16
+ TODO
17
+ ----
18
+
19
+ * build packet with performance data
20
+ * server side parsing of performance data
21
+ * more documentations
22
+ * mcrypt-support
23
+
24
+ DONE
25
+ ----
26
+
27
+ * packet-API (one check will be packed in one packet)
28
+ * simple-"encryption" (only xor with password and server-side generated iv-key)
29
+ * client-API (send to server)
30
+ * server-API (recv from client)
31
+ * check-API (describe checks and performance data)
32
+ * fast usable API for sending checks
33
+
34
+ Copyright
35
+ =========
36
+
37
+ Copyright (c) 2013 Denis Knauf. See LICENSE.txt for
38
+ further details.
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "nsca"
18
+ gem.homepage = "http://github.com/DenisKnauf/nsca"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Nagios passive alerts with friendly API}
21
+ gem.description = %Q{Create your alerts easily and send it to Nagios}
22
+ gem.email = "Denis.Knauf@gmail.com"
23
+ gem.authors = ["Denis Knauf"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ =begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ test.rcov_opts << '--exclude "gems/*"'
42
+ end
43
+ =end
44
+
45
+ task :default => :test
46
+
47
+ require 'yard'
48
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,10 @@
1
+ require 'socket'
2
+
3
+ module NSCA
4
+ class ServerDummy
5
+ attr_reader :server
6
+ def initialize *host_and_port
7
+ @server = TCPServer.new *host_and_port
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ require 'socket'
2
+ require 'enum'
3
+ require 'timeout'
4
+ require 'benchmark'
5
+ require 'securerandom'
6
+
7
+ module NSCA
8
+ class ReturnCode <Enum
9
+ start_at 0
10
+ enum %w[OK WARNING CRITICAL UNKNOWN]
11
+ end
12
+
13
+ module Helper
14
+ class <<self
15
+ def class_name_gen label
16
+ clname = label.gsub( /\W+/, '_').sub /^[0-9_]+/, ''
17
+ return nil if clname.empty?
18
+ clname[0] = clname[0].upcase
19
+ clname.to_sym
20
+ end
21
+ end
22
+ end
23
+
24
+ class <<self
25
+ def destinations() @destinations ||= [] end
26
+
27
+ def send *results
28
+ NSCA.destinations.each {|server| server.send *results }
29
+ self
30
+ end
31
+ end
32
+ end
33
+
34
+ require 'nsca/packet'
35
+ require 'nsca/server'
36
+ require 'nsca/client'
37
+ require 'nsca/check'
@@ -0,0 +1,182 @@
1
+ module NSCA
2
+ module PerformanceData
3
+ class Base
4
+ extend Timeout
5
+ extend Benchmark
6
+
7
+ class <<self
8
+ attr_reader :label, :unit, :warn, :crit, :min, :max
9
+ def init label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
10
+ @label, @unit, @warn, @crit, @min, @max = label.to_s, unit, warn, crit, min, max
11
+ self
12
+ end
13
+
14
+ def measure &block
15
+ timeout ||= 0
16
+ exception = Class.new Timeout::Error
17
+ pd = perfdatas[perfdata_label]
18
+ timeout = pd.max
19
+ m = realtime do
20
+ begin
21
+ timeout timeout, exception, &block
22
+ rescue exception
23
+ end
24
+ end
25
+ new m
26
+ end
27
+ end
28
+
29
+ attr_reader :value
30
+ def initialize( value) @value = value end
31
+ def label() self.class.label end
32
+ def unit() self.class.unit end
33
+ def warn() self.class.warn end
34
+ def crit() self.class.crit end
35
+ def min() self.class.min end
36
+ def max() self.class.max end
37
+ def to_s() "#{label}=#{value}#{unit},#{warn},#{crit},#{min},#{max}" end
38
+
39
+ def return_code
40
+ if @value.nil? then 3
41
+ elsif crit <= @value then 2
42
+ elsif warn <= @value then 1
43
+ else 0
44
+ end
45
+ end
46
+ end
47
+
48
+ class <<self
49
+ def new label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
50
+ cl = Class.new Base
51
+ cl.init label, unit, warn, crit, min, max
52
+ end
53
+
54
+ def create label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
55
+ cl = new label, unit, warn, crit, min, max
56
+ clname = NSCA::Helper.class_name_gen label
57
+ self.const_set clname, cl if clname
58
+ cl
59
+ end
60
+ end
61
+ end
62
+
63
+ module Check
64
+ class Base
65
+ attr_reader :perfdatas, :return_code, :status, :timestamp
66
+ def initialize return_code = nil, status = nil, perfdatas = nil
67
+ @perfdatas = {}
68
+ init return_code, status, perfdatas, timestamp || Time.now
69
+ end
70
+
71
+ def init return_code = nil, status = nil, perfdatas = nil, timestamp = nil
72
+ @return_code = return_code if return_code
73
+ @status = status if status
74
+ perfdatas.each &method( :[]) if perfdatas
75
+ @timestamp = timestamp if timestamp
76
+ self
77
+ end
78
+
79
+ def [] perfdata_label
80
+ pd = @perfdatas[perfdata_label]
81
+ pd && pd.value
82
+ end
83
+
84
+ def []= perfdata_label, value
85
+ cl = self.class.perfdatas[perfdata_label]
86
+ cl ||= PerformanceData::Base.new perfdata_label
87
+ @perfdatas[perfdata_label] = cl.new value
88
+ end
89
+
90
+ def text
91
+ r = "#{status || ReturnCode.find(return_code)}"
92
+ r += " | #{perfdatas.map( &:to_s).join ' '}" unless perfdatas.empty?
93
+ r
94
+ end
95
+
96
+ def measure( perfdata_label, &block) @perfdatas[perfdata_label].measure &block end
97
+ def send() NSCA::send self end
98
+
99
+ def ok status = nil, perfdatas = nil
100
+ init ReturnCode::OK, status, perfdatas
101
+ send
102
+ end
103
+
104
+ def warning status = nil, perfdatas = nil
105
+ init ReturnCode::WARNING, status, perfdatas
106
+ send
107
+ end
108
+ alias warn warning
109
+
110
+ def critical status = nil, perfdatas = nil
111
+ init ReturnCode::CRITICAL, status, perfdatas
112
+ send
113
+ end
114
+ alias crit critical
115
+
116
+ def unknown status = nil, perfdatas = nil
117
+ init ReturnCode::UNKNOWN, status, perfdatas
118
+ send
119
+ end
120
+
121
+ def determine_return_code
122
+ self.class.perfdatas.map do |label, pdc|
123
+ pd = @perfdatas[label]
124
+ if pd
125
+ pd.return_code
126
+ else
127
+ -1
128
+ end
129
+ end.max
130
+ end
131
+
132
+ def retcode
133
+ rc = return_code || determine_return_code
134
+ (0..3).include?(rc) ? rc : 3
135
+ end
136
+
137
+ def service() self.class.service end
138
+ def hostname() self.class.hostname end
139
+
140
+ class <<self
141
+ attr_reader :service, :hostname, :perfdatas
142
+ def init service, hostname = nil, perfdatas = nil
143
+ @service, @hostname, @perfdatas = service, hostname || `hostname -f`, {}
144
+ perfdatas.each {|pd| @perfdatas[pd.label] = pd }
145
+ self
146
+ end
147
+
148
+ def ok( status = nil, perfdatas = nil) new.ok status, perfdatas end
149
+ def warning( status = nil, perfdatas = nil) new.warning status, perfdatas end
150
+ alias warn warning
151
+ def critical( status = nil, perfdatas = nil) new.warning status, perfdatas end
152
+ alias crit critical
153
+ def unknown( status = nil, perfdatas = nil) new.unknown status, perfdatas end
154
+ end
155
+ end
156
+
157
+ class <<self
158
+ def create service, hostname = nil, perfdatas = nil
159
+ cl = Class.new Base
160
+ cl.init service, hostname, perfdatas
161
+ cl
162
+ end
163
+
164
+ def new service, hostname = nil, perfdatas = nil
165
+ cl = create service, hostname, perfdatas
166
+ clname = NSCA::Helper.class_name_gen service.to_s
167
+ self.const_set clname, cl if clname
168
+ cl
169
+ end
170
+ end
171
+ end
172
+
173
+ module Checks
174
+ def perfdata( cl, *params) const_set cl, NSCA::PerformanceData.new( *params) end
175
+
176
+ def check cl, service, hostname, perfdatas = nil
177
+ perfdatas ||= []
178
+ perfdatas.map! {|cl| cl.is_a?( Symbol) ? const_get( cl) : cl }
179
+ const_set cl, NSCA::Check.new( service, hostname, perfdatas)
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,97 @@
1
+ require 'socket'
2
+ require 'enum'
3
+ require 'timeout'
4
+ require 'benchmark'
5
+ require 'securerandom'
6
+
7
+ module NSCA
8
+ class Client
9
+ class Connection
10
+ attr_reader :iv_key, :timestamp, :socket, :packet_version, :password
11
+
12
+ def self.open *args
13
+ conn = new *args
14
+ if block_given?
15
+ begin yield conn
16
+ ensure conn && conn.close
17
+ end
18
+ else conn
19
+ end
20
+ end
21
+
22
+ # opts must be a hash
23
+ # Connection.new host, port [, opts]
24
+ # Connection.new socket [, opts]
25
+ # Connection.new host, opts # need `opts = {port: Port}`!
26
+ # Connection.new opts # need `opts = {port: Port, hostname: Hostname}`!
27
+ # Connection.new opts # need `opts = {port: Port, socket: Socket}`!
28
+ def initialize *args
29
+ opts = {}
30
+ opts = args.pop.dup if args.last.is_a? Hash
31
+ opts[:host] ||= opts[:hostname]
32
+ opts[:sock] ||= opts[:socket]
33
+ opts[:pass] ||= opts[:password]
34
+
35
+ case args[0]
36
+ when String
37
+ opts[:host] = args[0]
38
+ opts[:port] ||= args[1]
39
+ when IO
40
+ opts[:sock] = args[0]
41
+ end
42
+
43
+ @socket = if opts[:sock].is_a? IO
44
+ opts[:sock]
45
+ elsif opts[:host].is_a? String
46
+ TCPSocket.new opts[:host], opts[:port]
47
+ else
48
+ raise ArgumentError, "Socket or hostname+port expected."
49
+ end
50
+ @packet_version = opts[:packet_version] || PacketV3
51
+
52
+ # read iv_key and timestamp
53
+ iv_key_and_timestamp = @socket.recv 132
54
+ @iv_key, ts = iv_key_and_timestamp.unpack 'a128N'
55
+ @timestamp = Time.at ts
56
+ @password = opts[:pass]
57
+ end
58
+
59
+ # Builds a check-result-line for NSCA.
60
+ #
61
+ # Will be terminated by end-of-terminate.
62
+ # @param [Time,Integer,nil] timestamp Checked at this time
63
+ # @param [0..3] return_code `NSCA::ReturnCode`
64
+ # @param [String(length<64),nil] hostname If nil, local hostname will be used.
65
+ # Must be known by Nagios.
66
+ # @param [String(length<128)] service Name of Service. Must be known by Nagios.
67
+ # @param [String(length<512)] status Status-line inclusive optional Performance Data.
68
+ def build_packet timestamp, return_code, hostname, service, status
69
+ packet = @packet_version.new timestamp || @timestamp, return_code, hostname, service, status
70
+ packet.build @iv_key, @password
71
+ end
72
+
73
+ # Sends a check-result.
74
+ # @see #build_packet
75
+ def send_packet( *a) @socket.write build_packet( *a) end
76
+
77
+ # Sends check-results
78
+ # @param [Array<NSCA::Check::Base>] results
79
+ def send *results
80
+ results.flatten.each do |r|
81
+ send_packet r.timestamp, r.retcode, r.hostname, r.service, r.text
82
+ end
83
+ end
84
+
85
+ # Closes connection to NSCA.
86
+ def close( *a) @socket.close( *a) end
87
+ end
88
+
89
+ attr_reader :hostname, :port, :password
90
+ def initialize hostname = nil, port = nil, password = nil
91
+ @hostname, @port, @password = hostname, port, password
92
+ end
93
+
94
+ def open( &e) Connection.open @hostname, @port, @password, &e end
95
+ def send( *results) open {|conn| conn.send results } end
96
+ end
97
+ end
@@ -0,0 +1,121 @@
1
+ require 'socket'
2
+ require 'enum'
3
+ require 'timeout'
4
+ require 'benchmark'
5
+ require 'securerandom'
6
+
7
+ module NSCA
8
+ class <<self
9
+ def xor key, msg, key_a = nil
10
+ key_a ||= key.unpack 'C*'
11
+ l = key_a.length
12
+ return msg if l < 1
13
+ # Slice the message in parts of length key_a.length.
14
+ # XOR each char of a part with char at the same index in key_a.
15
+ msg.unpack( 'C*').each_with_index.map {|c,i| c^key_a[i%l] }.pack 'C*'
16
+ end
17
+
18
+ def crc32 msg
19
+ (msg.each_byte.inject 0xFFFFFFFF do |r,b|
20
+ 8.times.inject( r^b) {|r,_i| (r>>1) ^ (0xEDB88320 * (r&1)) }
21
+ end) ^ 0xFFFFFFFF
22
+ end
23
+
24
+ # Builds a null terminated, null padded string of length maxlen
25
+ def str2cstr( str, maxlen = nil)
26
+ str = str.to_s
27
+ str = str.to_s[0..(maxlen-2)] if maxlen
28
+ "#{str}\x00"
29
+ end
30
+ def cstr2str( str, maxlen = nil) str[ 0, x.index( ?\0) || ((maxlen||0)-1)] end
31
+ end
32
+
33
+ class Packet
34
+ class CSC32CheckFailed <Exception
35
+ end
36
+ class VersionCheckFailed <Exception
37
+ end
38
+
39
+ def self.versions version = nil
40
+ @@versions ||= {}
41
+ version ? @@versions[version] : @@versions
42
+ end
43
+
44
+ def self.register_version( version, klass) versions[version] = klass end
45
+
46
+ # @param [Time,Integer,nil] timestamp Checked at this time
47
+ # @param [0..3] return_code `NSCA::ReturnCode`
48
+ # @param [String(length<64),nil] hostname If nil, local hostname will be used.
49
+ # Must be known by Nagios.
50
+ # @param [String(length<128)] service Name of Service. Must be known by Nagios.
51
+ # @param [String(length<512)] status Status-line inclusive optional Performance Data.
52
+ def initialize timestamp, return_code, hostname, service, status
53
+ @timestamp, @return_code, @hostname, @service, @status =
54
+ Time.at( timestamp.to_f), return_code, hostname, service, status
55
+ end
56
+
57
+ attr_accessor :timestamp, :return_code, :hostname, :service, :status
58
+ end
59
+
60
+ class PacketV3 < Packet
61
+ NAGIOS_VERSION = 2.7
62
+ PACKET_VERSION = 3
63
+ END_OF_TRANSMISSION = ?\x0a
64
+ HOSTNAME_LENGTH = 64
65
+ SERVICE_LENGTH = 128
66
+ STATUS_LENGTH = 512
67
+
68
+ # these line describes the data package:
69
+ # typedef struct data_packet_struct{
70
+ # int16_t packet_version;
71
+ # /* xx means, 2 bytes without any data.
72
+ # * i do not know, why but there are 2 extra bytes without any need and
73
+ # * no where i can find information how these will be send,
74
+ # * because these struct does not know it.
75
+ # */
76
+ # u_int32_t crc32_value;
77
+ # u_int32_t timestamp;
78
+ # int16_t return_code;
79
+ # char host_name[MAX_HOSTNAME_LENGTH];
80
+ # char svc_description[MAX_DESCRIPTION_LENGTH];
81
+ # char plugin_output[MAX_PLUGINOUTPUT_LENGTH];
82
+ # /* 2 extre xx, too. */
83
+ # }data_packet;
84
+ PACK_STRING = "s> xx L> L> s> Z#{HOSTNAME_LENGTH} Z#{SERVICE_LENGTH} Z#{STATUS_LENGTH} xx"
85
+ PACK_LENGTH = 2+2+4+4+2+HOSTNAME_LENGTH+SERVICE_LENGTH+STATUS_LENGTH+2
86
+ register_version PACKET_VERSION, self
87
+
88
+ # Builds a check-result-line for NSCA.
89
+ #
90
+ # Will be terminated by end-of-terminate.
91
+ def build key = nil, password = nil
92
+ entry = [
93
+ PACKET_VERSION,
94
+ 0, # crc32 (unknown yet)
95
+ (timestamp || Time.now).to_i,
96
+ return_code.to_i,
97
+ NSCA::str2cstr( hostname || `hostname -f`, HOSTNAME_LENGTH),
98
+ NSCA::str2cstr( service, SERVICE_LENGTH),
99
+ NSCA::str2cstr( status, STATUS_LENGTH) # incl perfdata
100
+ ]
101
+ # generate crc32 and put it at entry[2...6]
102
+ entry[1] = NSCA::crc32 entry.pack( PACK_STRING)
103
+ entry = entry.pack PACK_STRING
104
+ entry = NSCA::xor key, entry if key
105
+ entry = NSCA::xor password, entry if password
106
+ entry
107
+ end
108
+
109
+ def self.parse entry, key = nil, password = nil, no_verification_checks = nil
110
+ entry = NSCA::xor key, entry if key
111
+ entry = NSCA::xor password, entry if password
112
+ ver, crc32sum, *x = entry.unpack( PACK_STRING)
113
+ raise VersionCheckFailed, "Packet version 3 expected. (recv: #{ver})" \
114
+ unless no_verification_checks or 3 == ver
115
+ entry[4..7] = ?\x00*4
116
+ raise CSC32CheckFailed, "crc32-check failed. packet seems to be broken." \
117
+ unless no_verification_checks or crc32sum == NSCA::crc32( entry)
118
+ new *x
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,78 @@
1
+ require 'socket'
2
+ require 'enum'
3
+ require 'timeout'
4
+ require 'benchmark'
5
+ require 'securerandom'
6
+
7
+ module NSCA
8
+ class Server
9
+ include Enumerable
10
+
11
+ attr_reader :iv_key, :server, :packet_version, :password
12
+ def initialize *args
13
+ opts = {}
14
+ opts = args.pop.dup if args.last.is_a? Hash
15
+ opts[:host] ||= opts[:hostname]
16
+ opts[:sock] ||= opts[:socket]
17
+ opts[:pass] ||= opts[:password]
18
+
19
+ case args[0]
20
+ when Integer
21
+ opts[:port] = args[0]
22
+ opts[:host] ||= args[1]
23
+ when IO
24
+ opts[:sock] = args[0]
25
+ end
26
+
27
+ @packet_version = opts[:packet_version] || PacketV3
28
+ @iv_key = (opts[:iv_key] || SecureRandom.random_bytes( 128)).to_s
29
+ raise ArgumentError, "Key must be 128 bytes long" unless 128 == @iv_key.length
30
+ @password = opts[:pass].to_s
31
+ @server = if opts[:serv].is_a?( TCPServer) or opts[:serv].is_a?( UNIXServer)
32
+ opts[:serv]
33
+ elsif opts[:port].is_a? Integer
34
+ TCPServer.new *[opts[:port], opts[:host]].compact
35
+ else
36
+ raise ArgumentError, "Server or port-number expected"
37
+ end
38
+ end
39
+
40
+ def accept() Connection.new @server.accept, self end
41
+ def close() @server.close end
42
+
43
+ def each &block
44
+ return Enumerator.new( self) unless block_given?
45
+ while conn = accept
46
+ yield conn
47
+ end
48
+ end
49
+
50
+ class Connection
51
+ include Enumerable
52
+
53
+ def initialize socket, server
54
+ @socket, @server = socket, server
55
+ @iv_key, @password = server.iv_key, server.password
56
+ @packet_version = server.packet_version
57
+ @packet_length = @packet_version::PACK_LENGTH
58
+ @socket.write [@iv_key, Time.now.to_i].pack( 'a* L>')
59
+ end
60
+
61
+ def fetch
62
+ data = read
63
+ @packet_version.parse data, @iv_key, @password if data
64
+ end
65
+
66
+ def each &block
67
+ return Enumerator.new( self) unless block_given?
68
+ while data = fetch
69
+ yield data
70
+ end
71
+ end
72
+
73
+ def eof?() @socket.eof? end
74
+ def read() @socket.read @packet_length end
75
+ def close() @socket.close end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,74 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "nsca"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Denis Knauf"]
12
+ s.date = "2013-04-08"
13
+ s.description = "Create your alerts easily and send it to Nagios"
14
+ s.email = "Denis.Knauf@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "dummy_server.rb",
28
+ "lib/nsca.rb",
29
+ "lib/nsca/check.rb",
30
+ "lib/nsca/client.rb",
31
+ "lib/nsca/packet.rb",
32
+ "lib/nsca/server.rb",
33
+ "nsca.gemspec",
34
+ "test/dummy_server.rb",
35
+ "test/helper.rb",
36
+ "test/test_nsca.rb"
37
+ ]
38
+ s.homepage = "http://github.com/DenisKnauf/nsca"
39
+ s.licenses = ["MIT"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = "1.8.23"
42
+ s.summary = "Nagios passive alerts with friendly API"
43
+
44
+ if s.respond_to? :specification_version then
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_runtime_dependency(%q<enum>, [">= 0"])
49
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
50
+ s.add_development_dependency(%q<yard>, [">= 0"])
51
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
52
+ s.add_development_dependency(%q<bundler>, [">= 0"])
53
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
54
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
55
+ else
56
+ s.add_dependency(%q<enum>, [">= 0"])
57
+ s.add_dependency(%q<shoulda>, [">= 0"])
58
+ s.add_dependency(%q<yard>, [">= 0"])
59
+ s.add_dependency(%q<rdoc>, [">= 0"])
60
+ s.add_dependency(%q<bundler>, [">= 0"])
61
+ s.add_dependency(%q<jeweler>, [">= 0"])
62
+ s.add_dependency(%q<simplecov>, [">= 0"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<enum>, [">= 0"])
66
+ s.add_dependency(%q<shoulda>, [">= 0"])
67
+ s.add_dependency(%q<yard>, [">= 0"])
68
+ s.add_dependency(%q<rdoc>, [">= 0"])
69
+ s.add_dependency(%q<bundler>, [">= 0"])
70
+ s.add_dependency(%q<jeweler>, [">= 0"])
71
+ s.add_dependency(%q<simplecov>, [">= 0"])
72
+ end
73
+ end
74
+
@@ -0,0 +1,16 @@
1
+ require 'pathname'
2
+ $: << Pathname.new( __FILE__).dirname.join( '..', 'lib').to_s
3
+
4
+ module NSCA
5
+ def self.dummy_server *args
6
+ Dir[ Pathname.new( __FILE__).dirname.join( '..', 'lib', '**').to_s].each_entry do |l|
7
+ load l if /\.rb$/ =~ l
8
+ end
9
+ serv = NSCA::Server.new *args
10
+ sock = serv.accept
11
+ sock.to_a
12
+ ensure
13
+ sock.close if sock
14
+ serv.close if serv
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'nsca'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,95 @@
1
+ require 'helper'
2
+
3
+ class TestNSCA < Test::Unit::TestCase
4
+ class TestChecks
5
+ extend NSCA::Checks
6
+ perfdata :PD1, :pd1_in_sec, :s, 10, 20, 0, 30
7
+ perfdata :PD2, :pd2_in_1, 1, 0.99, 0.98, 0, 1
8
+ perfdata :PD3, :pd3_count, :c, 3, 5, 0
9
+ check :T0, 'TestNSCA0', 'uxnags01-sbe.net.mobilkom.at'
10
+ check :T1, 'TestNSCA1', 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2]
11
+ check :T2, :TestNSCA2, 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2, PD3]
12
+ end
13
+
14
+ context 'our test server' do
15
+ should 'receive data. NSCA-server should run on localhost 5777. if not, ignore this test. password=abcdefghijkl' do
16
+ PD1 = TestChecks::PD1
17
+ PD2 = TestChecks::PD2
18
+ PD3 = TestChecks::PD3
19
+ T0 = TestChecks::T0
20
+ T1 = TestChecks::T1
21
+ T2 = TestChecks::T2
22
+
23
+ checks = []
24
+ checks << TestChecks::T0.new( 1, "0123456789"*51+"AB")
25
+
26
+ pd1 = PD1.new 3
27
+ pd2 = PD2.new 0.9996
28
+ pd3 = PD3.new 2
29
+ checks << TestChecks::T1.new( nil, "Should be OK", [pd1, pd2, pd3])
30
+
31
+ NSCA::destinations << NSCA::Client.new( 'localhost', 5667, password: 'abcdefghijkl')
32
+ NSCA::send *checks
33
+ end
34
+ end
35
+ end
36
+
37
+ class TestNSCA::ReturnCode < Test::Unit::TestCase
38
+ context 'return code' do
39
+ should( 'be 0 == OK') { assert NSCA::ReturnCode.find(0) == NSCA::ReturnCode::OK }
40
+ should( 'be 1 == WARNING') { assert NSCA::ReturnCode.find(1) == NSCA::ReturnCode::WARNING }
41
+ should( 'be 2 == CRITICAL') { assert NSCA::ReturnCode.find(2) == NSCA::ReturnCode::CRITICAL }
42
+ should( 'be 3 == UNKNOWN') { assert NSCA::ReturnCode.find(3) == NSCA::ReturnCode::UNKNOWN }
43
+ end
44
+ end
45
+
46
+ class TestNSCA::Helper < Test::Unit::TestCase
47
+ context 'class gen name' do
48
+ should 'generate class names' do
49
+ assert :Total_run_check_measure == NSCA::Helper.class_name_gen( 'total run check measure')
50
+ end
51
+
52
+ should 'do not generate class names, if no letter' do
53
+ assert nil == NSCA::Helper.class_name_gen( '123 321, 43 _ ?')
54
+ end
55
+ end
56
+ end
57
+
58
+ class TestNSCA::PerformanceData < Test::Unit::TestCase
59
+ should 'set a subclass for new PerfData-types' do
60
+ NSCA::PerformanceData.create 'subclass test'
61
+ assert_nothing_raised NameError do
62
+ assert NSCA::PerformanceData::Subclass_test, "No subclass created."
63
+ end
64
+ end
65
+
66
+ def perfdata *a
67
+ NSCA::PerformanceData.new *a
68
+ end
69
+
70
+ context 'Created NSCA::PerformanceData-subclasses' do
71
+ should 'be the same like returned' do
72
+ cl = NSCA::PerformanceData.create 'returned and subclass the same test'
73
+ assert cl == NSCA::PerformanceData::Returned_and_subclass_the_same_test, 'Classes are not the same.'
74
+ end
75
+ should 'have a unit if given' do
76
+ assert :s == perfdata( 'have an unit test', :s).unit, "Not s as unit"
77
+ end
78
+ should 'have not a unit if not given' do
79
+ assert nil == perfdata( 'have not an unit test', nil).unit, "Not nil as unit"
80
+ end
81
+ should 'have a warn thresh if given' do
82
+ assert 3 == perfdata( 'have a warn test', nil, 3).warn, "Not 3 as warn"
83
+ end
84
+ should 'have not a warn thresh if not given' do
85
+ assert nil == perfdata( 'have not a warn test', nil, nil).warn, "Not nil as warn"
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ class TestNSCA::Client < Test::Unit::TestCase
92
+ should '' do
93
+ NSCA::Client
94
+ end
95
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nsca
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Denis Knauf
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: enum
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: shoulda
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: yard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rdoc
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: bundler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: jeweler
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: simplecov
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Create your alerts easily and send it to Nagios
127
+ email: Denis.Knauf@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files:
131
+ - LICENSE.txt
132
+ - README.md
133
+ files:
134
+ - .document
135
+ - Gemfile
136
+ - Gemfile.lock
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - VERSION
141
+ - dummy_server.rb
142
+ - lib/nsca.rb
143
+ - lib/nsca/check.rb
144
+ - lib/nsca/client.rb
145
+ - lib/nsca/packet.rb
146
+ - lib/nsca/server.rb
147
+ - nsca.gemspec
148
+ - test/dummy_server.rb
149
+ - test/helper.rb
150
+ - test/test_nsca.rb
151
+ homepage: http://github.com/DenisKnauf/nsca
152
+ licenses:
153
+ - MIT
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ none: false
160
+ requirements:
161
+ - - ! '>='
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ segments:
165
+ - 0
166
+ hash: -852364013
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ none: false
169
+ requirements:
170
+ - - ! '>='
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ requirements: []
174
+ rubyforge_project:
175
+ rubygems_version: 1.8.23
176
+ signing_key:
177
+ specification_version: 3
178
+ summary: Nagios passive alerts with friendly API
179
+ test_files: []