nsca 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/VERSION +1 -1
  2. data/lib/nsca/check.rb +67 -45
  3. data/nsca.gemspec +2 -2
  4. data/test/test_nsca.rb +159 -24
  5. metadata +3 -3
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.0
@@ -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 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
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
- timeout ||= 0
16
- exception = Class.new Timeout::Error
17
- pd = perfdatas[perfdata_label.to_sym]
18
- timeout = pd.max
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.label.to_sym end
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 label, unit = nil, warn = nil, crit = nil, min = nil, max = nil
51
- cl = Class.new Base
52
- cl.init label, unit, warn, crit, min, max
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
- attr_reader :perfdatas, :return_code, :status, :timestamp
67
- def initialize return_code = nil, status = nil, perfdatas = nil
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.to_sym
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(return_code)}"
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
- @perfdatas[perfdata_label.to_sym].measure &block
135
+ push perfdata_for( perfdata_label).measure( &block)
111
136
  end
112
137
  def send() NSCA::send self end
113
138
 
114
- def ok status = nil, perfdatas = nil
115
- init ReturnCode::OK, status, perfdatas
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 service, hostname = nil, perfdatas = nil
158
- @service, @hostname, @perfdatas = service, hostname || `hostname -f`, {}
159
- perfdatas.each {|pd| @perfdatas[pd.label.to_sym] = pd }
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
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "nsca"
8
- s.version = "0.1.4"
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-09"
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 = [
@@ -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
- class TestChecks
5
- extend NSCA::Checks
6
- PD1 = perfdata :pd1_in_sec, :s, 10, 20, 0, 30
7
- PD2 = perfdata :pd2_in_1, 1, 0.99, 0.98, 0, 1
8
- PD3 = perfdata :pd3_count, :c, 3, 5, 0
9
- T0 = check 'TestNSCA0', 'uxnags01-sbe.net.mobilkom.at'
10
- T1 = check 'TestNSCA1', 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2]
11
- T2 = check :TestNSCA2, 'uxnags01-sbe.net.mobilkom.at', [PD1, PD2, PD3]
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
- 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
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
- checks << TestChecks::T0.new( 1, "0123456789"*51+"AB")
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
- checks << TestChecks::T1.new( nil, "Should be OK", [pd1, pd2, pd3])
43
+ t1 = T1.new( nil, "Should be OK", [pd1, pd2, pd3], timestamp)
44
+ checks << t1
30
45
 
31
- NSCA::destinations << NSCA::Client.new( 'localhost', 5667, password: 'abcdefghijkl')
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
- 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.'
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
- class TestNSCA::Client < Test::Unit::TestCase
92
- should '' do
93
- NSCA::Client
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.1.4
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-09 00:00:00.000000000 Z
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: -1034310641
165
+ hash: -843459889
166
166
  required_rubygems_version: !ruby/object:Gem::Requirement
167
167
  none: false
168
168
  requirements: