nsca 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []