nsca 0.1.4 → 0.2.0
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.
- data/VERSION +1 -1
- data/lib/nsca/check.rb +67 -45
- data/nsca.gemspec +2 -2
- data/test/test_nsca.rb +159 -24
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/nsca/check.rb
CHANGED
@@ -1,29 +1,45 @@
|
|
1
1
|
module NSCA
|
2
2
|
module PerformanceData
|
3
|
+
class TimeUnitExpected < Exception
|
4
|
+
end
|
5
|
+
|
3
6
|
class Base
|
4
7
|
extend Timeout
|
5
8
|
extend Benchmark
|
6
9
|
|
7
10
|
class <<self
|
8
11
|
attr_reader :label, :unit, :warn, :crit, :min, :max
|
9
|
-
def init
|
10
|
-
|
12
|
+
def init *args
|
13
|
+
a, o = args, args.last.is_a?( Hash) ? args.pop : {}
|
14
|
+
@label, @unit = a[0]||o[:label], a[1]||o[:unit]
|
15
|
+
@warn, @crit = a[2]||o[:warn], a[3]||o[:crit]
|
16
|
+
@min, @max = a[4]||o[:min], a[5]||o[:max]
|
17
|
+
raise ArgumentError, "Label expected" unless @label
|
18
|
+
@label = @label.to_s
|
11
19
|
self
|
12
20
|
end
|
13
21
|
|
14
22
|
def measure &block
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
23
|
+
f = case unit.to_s.to_sym
|
24
|
+
when :s then 1
|
25
|
+
when :ms then 1000
|
26
|
+
else raise TimeUnitExpected, "Unit must be seconds (s) or miliseconds (ms) not (#{unit})"
|
27
|
+
end
|
28
|
+
exception = ::Class.new Timeout::Error
|
29
|
+
timeout = max
|
19
30
|
m = realtime do
|
20
31
|
begin
|
21
32
|
timeout timeout, exception, &block
|
22
33
|
rescue exception
|
23
34
|
end
|
24
35
|
end
|
25
|
-
new m
|
36
|
+
new f * m
|
26
37
|
end
|
38
|
+
|
39
|
+
def to_sym() label.to_sym end
|
40
|
+
def to_h() {label: @label, unit: @unit, warn: @warn, crit: @crit, min: @min, max: @max } end
|
41
|
+
def to_a() [label, unit, warn, crit, min, max] end
|
42
|
+
def clone( opts = nil) ::Class.new( self).init opts ? to_h.merge( opts) : to_h end
|
27
43
|
end
|
28
44
|
|
29
45
|
attr_reader :value
|
@@ -34,8 +50,13 @@ module NSCA
|
|
34
50
|
def crit() self.class.crit end
|
35
51
|
def min() self.class.min end
|
36
52
|
def max() self.class.max end
|
53
|
+
def to_a() [label, value, unit, warn, crit, min, max] end
|
37
54
|
def to_s() "#{label}=#{value}#{unit},#{warn},#{crit},#{min},#{max}" end
|
38
|
-
def to_sym() self.class.
|
55
|
+
def to_sym() self.class.to_sym end
|
56
|
+
|
57
|
+
def to_h
|
58
|
+
{label: @label, value: @value, unit: @unit, warn: @warn, crit: @crit, min: @min, max: @max}
|
59
|
+
end
|
39
60
|
|
40
61
|
def return_code
|
41
62
|
if @value.nil? then 3
|
@@ -47,13 +68,9 @@ module NSCA
|
|
47
68
|
end
|
48
69
|
|
49
70
|
class <<self
|
50
|
-
def new
|
51
|
-
|
52
|
-
cl
|
53
|
-
end
|
54
|
-
|
55
|
-
def create label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
|
56
|
-
cl = new label, unit, warn, crit, min, max
|
71
|
+
def new( *args) ::Class.new( Base).init *args end
|
72
|
+
def create label, *args
|
73
|
+
cl = new label, *args
|
57
74
|
clname = NSCA::Helper.class_name_gen label
|
58
75
|
self.const_set clname, cl if clname
|
59
76
|
cl
|
@@ -63,8 +80,10 @@ module NSCA
|
|
63
80
|
|
64
81
|
module Check
|
65
82
|
class Base
|
66
|
-
|
67
|
-
|
83
|
+
attr_accessor :return_code, :status, :timestamp
|
84
|
+
attr_reader :perfdatas
|
85
|
+
|
86
|
+
def initialize return_code = nil, status = nil, perfdatas = nil, timestamp = nil
|
68
87
|
@perfdatas = {}
|
69
88
|
init return_code, status, perfdatas, timestamp || Time.now
|
70
89
|
end
|
@@ -92,46 +111,37 @@ module NSCA
|
|
92
111
|
@perfdatas
|
93
112
|
end
|
94
113
|
|
114
|
+
def perfdata_for label
|
115
|
+
if label.is_a? PerformanceData::Base
|
116
|
+
label
|
117
|
+
else
|
118
|
+
label = label.to_sym
|
119
|
+
self.class.perfdatas[label] || PerformanceData::Base.new( label)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
95
123
|
def []= perfdata_label, value
|
96
124
|
return push value if value.is_a? PerformanceData::Base
|
97
|
-
perfdata_label = perfdata_label.
|
98
|
-
cl = self.class.perfdatas[perfdata_label]
|
99
|
-
cl ||= PerformanceData::Base.new perfdata_label
|
100
|
-
@perfdatas[perfdata_label] = cl.new value
|
125
|
+
@perfdatas[perfdata_label] = perfdata_for( perfdata_label).new value
|
101
126
|
end
|
102
127
|
|
103
128
|
def text
|
104
|
-
r = "#{status || ReturnCode.find(
|
129
|
+
r = "#{status || ReturnCode.find(retcode)}"
|
105
130
|
r += " | #{perfdatas.each_value.map( &:to_s).join ' '}" unless perfdatas.empty?
|
106
131
|
r
|
107
132
|
end
|
108
133
|
|
109
134
|
def measure perfdata_label, &block
|
110
|
-
|
135
|
+
push perfdata_for( perfdata_label).measure( &block)
|
111
136
|
end
|
112
137
|
def send() NSCA::send self end
|
113
138
|
|
114
|
-
def ok
|
115
|
-
|
116
|
-
send
|
117
|
-
end
|
118
|
-
|
119
|
-
def warning status = nil, perfdatas = nil
|
120
|
-
init ReturnCode::WARNING, status, perfdatas
|
121
|
-
send
|
122
|
-
end
|
139
|
+
def ok( *args) init ReturnCode::OK, *args end
|
140
|
+
def warning( *args) init ReturnCode::WARNING, *args end
|
123
141
|
alias warn warning
|
124
|
-
|
125
|
-
def critical status = nil, perfdatas = nil
|
126
|
-
init ReturnCode::CRITICAL, status, perfdatas
|
127
|
-
send
|
128
|
-
end
|
142
|
+
def critical( *args) init ReturnCode::CRITICAL, *args end
|
129
143
|
alias crit critical
|
130
|
-
|
131
|
-
def unknown status = nil, perfdatas = nil
|
132
|
-
init ReturnCode::UNKNOWN, status, perfdatas
|
133
|
-
send
|
134
|
-
end
|
144
|
+
def unknown( *args) init ReturnCode::UNKNOWN, *args end
|
135
145
|
|
136
146
|
def determine_return_code
|
137
147
|
self.class.perfdatas.map do |label, pdc|
|
@@ -151,12 +161,19 @@ module NSCA
|
|
151
161
|
|
152
162
|
def service() self.class.service end
|
153
163
|
def hostname() self.class.hostname end
|
164
|
+
def to_a() [timestamp, retcode, hostname, service, text] end
|
165
|
+
def to_h
|
166
|
+
{timestamp: timestamp, return_code: retcode, hostname: hostname, server: service, status: text}
|
167
|
+
end
|
154
168
|
|
155
169
|
class <<self
|
156
170
|
attr_reader :service, :hostname, :perfdatas
|
157
|
-
def init
|
158
|
-
|
159
|
-
|
171
|
+
def init *args
|
172
|
+
a, o = args, args.last.is_a?( Hash) ? args.pop : {}
|
173
|
+
service, hostname = nil, perfdatas = nil
|
174
|
+
@service, @hostname, @perfdatas = a[0]||o[:service], a[1]||o[:hostname]||`hostname`.chomp, {}
|
175
|
+
perfdatas = a[2]||o[:perfdatas]
|
176
|
+
perfdatas.each {|pd| @perfdatas[pd.to_sym] = pd } if perfdatas
|
160
177
|
self
|
161
178
|
end
|
162
179
|
|
@@ -166,6 +183,11 @@ module NSCA
|
|
166
183
|
def critical( status = nil, perfdatas = nil) new.warning status, perfdatas end
|
167
184
|
alias crit critical
|
168
185
|
def unknown( status = nil, perfdatas = nil) new.unknown status, perfdatas end
|
186
|
+
|
187
|
+
def to_a() [service, hostname, perfdatas.dup] end
|
188
|
+
def to_h() {service: service, hostname: hostname, perfdatas: perfdatas.values} end
|
189
|
+
def to_sym() "#{hostname}|#{service}".to_sym end
|
190
|
+
def clone( opts = nil) ::Class.new( self).init opts ? to_h.merge( opts) : to_h end
|
169
191
|
end
|
170
192
|
end
|
171
193
|
|
data/nsca.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "nsca"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Denis Knauf"]
|
12
|
-
s.date = "2013-04-
|
12
|
+
s.date = "2013-04-11"
|
13
13
|
s.description = "Create your alerts easily and send it to Nagios"
|
14
14
|
s.email = "Denis.Knauf@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
data/test/test_nsca.rb
CHANGED
@@ -1,35 +1,79 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'dummy_server'
|
3
|
+
require 'securerandom'
|
2
4
|
|
3
5
|
class TestNSCA < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
context 'xor' do
|
7
|
+
should 'return a if a (random) will xored double with random key. (1000 rounds)' do
|
8
|
+
1000.times do
|
9
|
+
key_len = SecureRandom.random_number 1000
|
10
|
+
a_len = SecureRandom.random_number 1000
|
11
|
+
key = SecureRandom.random_bytes key_len
|
12
|
+
a = SecureRandom.random_bytes a_len
|
13
|
+
assert_equal a, NSCA.xor( key, NSCA.xor(key, a))
|
14
|
+
end
|
15
|
+
end
|
12
16
|
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TestNSCACommunication < Test::Unit::TestCase
|
20
|
+
Port = 5787
|
21
|
+
|
22
|
+
include NSCA::Checks
|
23
|
+
|
24
|
+
context "our dummy test server on localhost:#{Port} with random password" do
|
25
|
+
should 'receive data' do
|
26
|
+
password = SecureRandom.random_bytes
|
27
|
+
timestamp = Time.now
|
13
28
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
T1 = TestChecks::T1
|
21
|
-
T2 = TestChecks::T2
|
29
|
+
PD1 = perfdata :pd1_in_sec, :s, 10, 20, 0, 30
|
30
|
+
PD2 = perfdata :pd2_in_1, 1, 0.99, 0.98, 0, 1
|
31
|
+
PD3 = perfdata :pd3_count, :c, 3, 5, 0
|
32
|
+
T0 = check 'TestNSCA0', 'uxnags01-sbe.net.mobilkom.at'
|
33
|
+
T1 = check 'TestNSCA1', 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2]
|
34
|
+
T2 = check :TestNSCA2, 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2, PD3]
|
22
35
|
|
23
36
|
checks = []
|
24
|
-
|
37
|
+
t0 = T0.new( 1, "0123456789"*51+"AB", nil, timestamp) # oversized service name
|
38
|
+
checks << t0
|
25
39
|
|
26
40
|
pd1 = PD1.new 3
|
27
41
|
pd2 = PD2.new 0.9996
|
28
42
|
pd3 = PD3.new 2
|
29
|
-
|
43
|
+
t1 = T1.new( nil, "Should be OK", [pd1, pd2, pd3], timestamp)
|
44
|
+
checks << t1
|
30
45
|
|
31
|
-
NSCA::destinations
|
46
|
+
NSCA::destinations.clear
|
47
|
+
NSCA::destinations << NSCA::Client.new( 'localhost', Port, password: password)
|
48
|
+
|
49
|
+
server = Thread.new { NSCA.dummy_server Port, password: password }
|
50
|
+
sleep 1 # server needs time to start...
|
32
51
|
NSCA::send *checks
|
52
|
+
pc0, pc1 = server.value
|
53
|
+
|
54
|
+
[[t0, pc0], [t1, pc1]].each do |(test, packet)|
|
55
|
+
assert_equal test.hostname, packet.hostname
|
56
|
+
assert_equal test.service, packet.service
|
57
|
+
assert_equal timestamp.to_i, packet.timestamp.to_i
|
58
|
+
assert_equal test.retcode, packet.return_code
|
59
|
+
end
|
60
|
+
# original with B, but B is char 512 and will be replaced by \0
|
61
|
+
assert_equal pc0.status, "0123456789"*51+"A"
|
62
|
+
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,"
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'fail crc32 if wrong password' do
|
66
|
+
password = SecureRandom.random_bytes
|
67
|
+
timestamp = Time.now
|
68
|
+
T3 = check 'TestNSCA0', 'uxnags01-sbe.net.mobilkom.at'
|
69
|
+
NSCA::destinations.clear
|
70
|
+
NSCA::destinations << NSCA::Client.new( 'localhost', Port, password: password+'a')
|
71
|
+
server = Thread.new { NSCA.dummy_server Port, password: password }
|
72
|
+
sleep 1 # server needs time to start...
|
73
|
+
NSCA::send T3.new( 1, 'status', nil, timestamp)
|
74
|
+
assert_raise NSCA::Packet::CSC32CheckFailed do
|
75
|
+
server.join
|
76
|
+
end
|
33
77
|
end
|
34
78
|
end
|
35
79
|
end
|
@@ -69,8 +113,14 @@ class TestNSCA::PerformanceData < Test::Unit::TestCase
|
|
69
113
|
|
70
114
|
context 'Created NSCA::PerformanceData-subclasses' do
|
71
115
|
should 'be the same like returned' do
|
72
|
-
|
73
|
-
|
116
|
+
PA = NSCA::PerformanceData.create 'returned and subclass the same test'
|
117
|
+
assert_equal PA, NSCA::PerformanceData::Returned_and_subclass_the_same_test
|
118
|
+
end
|
119
|
+
should 'not exists, if #new used' do
|
120
|
+
pb = NSCA::PerformanceData.new 'no subclass'
|
121
|
+
assert_raise NameError do
|
122
|
+
NSCA::PerformanceData::No_subclass
|
123
|
+
end
|
74
124
|
end
|
75
125
|
should 'have a unit if given' do
|
76
126
|
assert :s == perfdata( 'have an unit test', :s).unit, "Not s as unit"
|
@@ -85,11 +135,96 @@ class TestNSCA::PerformanceData < Test::Unit::TestCase
|
|
85
135
|
assert nil == perfdata( 'have not a warn test', nil, nil).warn, "Not nil as warn"
|
86
136
|
end
|
87
137
|
end
|
138
|
+
|
139
|
+
context 'Measure' do
|
140
|
+
should 'work with s' do
|
141
|
+
PC = perfdata 'something in seconds', :s
|
142
|
+
assert PC.measure { true }.is_a?( PC), 'can not be created?'
|
143
|
+
end
|
144
|
+
|
145
|
+
should 'work with ms' do
|
146
|
+
PD = perfdata 'something in mili seconds', :ms
|
147
|
+
assert PD.measure { true }.is_a?( PD), 'can not be created?'
|
148
|
+
end
|
149
|
+
|
150
|
+
should 'not work with something else' do
|
151
|
+
PE = perfdata 'something else than time', :c
|
152
|
+
assert_raise NSCA::PerformanceData::TimeUnitExpected do
|
153
|
+
PE.measure { true }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
should 'measure something between 1s..3s if i sleep 2 seconds' do
|
158
|
+
PF = perfdata 'wait 2 seconds', :s
|
159
|
+
pf = PF.measure { sleep 2 }
|
160
|
+
assert (1..3).include?( pf.value), "Not in range 1s..3s: #{pf.value}s"
|
161
|
+
end
|
162
|
+
|
163
|
+
should 'measure something between 1000ms..3000ms if i sleep 2 seconds' do
|
164
|
+
PG = perfdata 'wait 2000 mili second', :ms
|
165
|
+
pf = PG.measure { sleep 2 }
|
166
|
+
assert (1000..3000).include?( pf.value), "Not in range 1000ms..3000ms: #{pf.value}ms"
|
167
|
+
end
|
168
|
+
end
|
88
169
|
end
|
89
170
|
|
171
|
+
class TestNSCA::Check < Test::Unit::TestCase
|
172
|
+
context 'Data' do
|
173
|
+
should 'also be empty' do
|
174
|
+
CF = NSCA::Check.new 'empty data'
|
175
|
+
cf = CF.new
|
176
|
+
hostname = `hostname`.chomp
|
177
|
+
assert_equal [cf.timestamp, 3, hostname, 'empty data', 'UNKNOWN'], cf.to_a
|
178
|
+
end
|
179
|
+
|
180
|
+
should 'have default a timestamp. ~ -10s..10s' do
|
181
|
+
CG = NSCA::Check.new 'default timestamp'
|
182
|
+
cg = CG.new
|
183
|
+
now = Time.now
|
184
|
+
range = Time.at(now-10) .. Time.at(now+10)
|
185
|
+
assert range.begin <= cg.timestamp && cg.timestamp <= range.end,
|
186
|
+
"Not a valid timestamp ~now: #{cg.timestamp}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'Subclasses' do
|
191
|
+
should 'be created by NSCA::Check.create' do
|
192
|
+
CA = NSCA::Check.create 'a uniq name'
|
193
|
+
assert_same CA, NSCA::Check::A_uniq_name
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'No Subclasses' do
|
198
|
+
should 'be created by NSCA::Check.new' do
|
199
|
+
CB = NSCA::Check.new 'a uniq name, too'
|
200
|
+
assert_raise NameError, 'A class named NSCA::Check::A_uniq_name_too exists' do
|
201
|
+
CB == NSCA::Check::A_uniq_name_too
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
90
205
|
|
91
|
-
|
92
|
-
|
93
|
-
|
206
|
+
context 'Clones' do
|
207
|
+
should 'have old class as superclass' do
|
208
|
+
CC1 = NSCA::Check.new( 'a check which will be for cloning')
|
209
|
+
CC2 = CC1.clone
|
210
|
+
assert_equal CC2.superclass, CC1
|
211
|
+
end
|
212
|
+
|
213
|
+
should 'have the same data' do
|
214
|
+
CD1 = NSCA::Check.new 'a check for same data after cloning'
|
215
|
+
CD2 = CD1.clone
|
216
|
+
assert_equal CD2.to_a, CD2.to_a
|
217
|
+
end
|
218
|
+
|
219
|
+
should 'have the same data, except specific data' do
|
220
|
+
CE1 = NSCA::Check.new 'a check for same data after cloning again, but...'
|
221
|
+
CE2 = CE1.clone service: '... but the service will be changed.'
|
222
|
+
assert_not_equal CE1.service, CE2.service
|
223
|
+
assert_equal 'a check for same data after cloning again, but...', CE1.service
|
224
|
+
assert_equal '... but the service will be changed.', CE2.service
|
225
|
+
ce1_data, ce2_data = CE1.to_a, CE2.to_a
|
226
|
+
ce1_data[0] = ce2_data[0] = 'dummy'
|
227
|
+
assert_equal ce1_data, ce2_data
|
228
|
+
end
|
94
229
|
end
|
95
230
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nsca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: enum
|
@@ -162,7 +162,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
162
162
|
version: '0'
|
163
163
|
segments:
|
164
164
|
- 0
|
165
|
-
hash: -
|
165
|
+
hash: -843459889
|
166
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
167
|
none: false
|
168
168
|
requirements:
|