sensu 0.9.11 → 0.9.12.beta
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/CHANGELOG.md +20 -0
- data/lib/sensu/api.rb +44 -37
- data/lib/sensu/base.rb +19 -10
- data/lib/sensu/cli.rb +4 -4
- data/lib/sensu/client.rb +103 -68
- data/lib/sensu/constants.rb +5 -7
- data/lib/sensu/extensions.rb +9 -3
- data/lib/sensu/extensions/handlers/debug.rb +1 -1
- data/lib/sensu/logstream.rb +49 -22
- data/lib/sensu/rabbitmq.rb +2 -2
- data/lib/sensu/server.rb +59 -55
- data/lib/sensu/settings.rb +182 -248
- data/lib/sensu/socket.rb +12 -12
- data/sensu.gemspec +3 -5
- metadata +37 -64
data/lib/sensu/constants.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
module Sensu
|
2
2
|
unless defined?(Sensu::VERSION)
|
3
|
-
VERSION = '0.9.
|
3
|
+
VERSION = '0.9.12.beta'
|
4
4
|
|
5
|
-
|
6
|
-
:config_file => '/etc/sensu/config.json',
|
7
|
-
:config_dir => '/etc/sensu/conf.d',
|
8
|
-
:log_level => :info
|
9
|
-
}
|
5
|
+
LOG_LEVELS = [:debug, :info, :warn, :error, :fatal]
|
10
6
|
|
11
7
|
SETTINGS_CATEGORIES = [:checks, :filters, :mutators, :handlers]
|
12
8
|
|
13
|
-
EXTENSION_CATEGORIES = [:mutators, :handlers]
|
9
|
+
EXTENSION_CATEGORIES = [:checks, :mutators, :handlers]
|
14
10
|
|
15
11
|
SEVERITIES = %w[ok warning critical unknown]
|
12
|
+
|
13
|
+
STOP_SIGNALS = %w[INT TERM]
|
16
14
|
end
|
17
15
|
end
|
data/lib/sensu/extensions.rb
CHANGED
@@ -13,8 +13,14 @@ module Sensu
|
|
13
13
|
end
|
14
14
|
|
15
15
|
EXTENSION_CATEGORIES.each do |category|
|
16
|
-
define_method(category
|
17
|
-
@extensions[category].
|
16
|
+
define_method(category) do
|
17
|
+
@extensions[category].map do |name, extension|
|
18
|
+
extension.definition
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method(category.to_s.chop + '_exists?') do |name|
|
23
|
+
@extensions[category].has_key?(name)
|
18
24
|
end
|
19
25
|
end
|
20
26
|
|
@@ -22,7 +28,7 @@ module Sensu
|
|
22
28
|
path = directory.gsub(/\\(?=\S)/, '/')
|
23
29
|
Dir.glob(File.join(path, '**/*.rb')).each do |file|
|
24
30
|
begin
|
25
|
-
require file
|
31
|
+
require File.expand_path(file)
|
26
32
|
rescue ScriptError => error
|
27
33
|
@logger.error('failed to require extension', {
|
28
34
|
:extension_file => file,
|
data/lib/sensu/logstream.rb
CHANGED
@@ -1,20 +1,36 @@
|
|
1
|
-
gem 'cabin', '0.4.4'
|
2
|
-
|
3
|
-
require 'cabin'
|
4
|
-
|
5
1
|
module Sensu
|
6
2
|
class LogStream
|
7
|
-
attr_reader :logger
|
8
|
-
|
9
3
|
def initialize
|
10
|
-
@
|
4
|
+
@log_stream = EM::Queue.new
|
5
|
+
@log_level = :info
|
11
6
|
STDOUT.sync = true
|
12
7
|
STDERR.reopen(STDOUT)
|
13
|
-
|
8
|
+
setup_writer
|
14
9
|
end
|
15
10
|
|
16
|
-
def level=(
|
17
|
-
@
|
11
|
+
def level=(level)
|
12
|
+
@log_level = level
|
13
|
+
end
|
14
|
+
|
15
|
+
def level_filtered?(level)
|
16
|
+
LOG_LEVELS.index(level) < LOG_LEVELS.index(@log_level)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(level, *arguments)
|
20
|
+
unless level_filtered?(level)
|
21
|
+
log_event = create_log_event(level, *arguments)
|
22
|
+
if EM::reactor_running?
|
23
|
+
@log_stream << log_event
|
24
|
+
else
|
25
|
+
puts log_event
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
LOG_LEVELS.each do |level|
|
31
|
+
define_method(level) do |*arguments|
|
32
|
+
add(level, *arguments)
|
33
|
+
end
|
18
34
|
end
|
19
35
|
|
20
36
|
def reopen(file)
|
@@ -24,7 +40,7 @@ module Sensu
|
|
24
40
|
STDOUT.sync = true
|
25
41
|
STDERR.reopen(STDOUT)
|
26
42
|
else
|
27
|
-
|
43
|
+
error('log file is not writable', {
|
28
44
|
:log_file => file
|
29
45
|
})
|
30
46
|
end
|
@@ -33,7 +49,7 @@ module Sensu
|
|
33
49
|
def setup_traps
|
34
50
|
if Signal.list.include?('USR1')
|
35
51
|
Signal.trap('USR1') do
|
36
|
-
@
|
52
|
+
@log_level = @log_level == :info ? :debug : :info
|
37
53
|
end
|
38
54
|
end
|
39
55
|
if Signal.list.include?('USR2')
|
@@ -44,23 +60,34 @@ module Sensu
|
|
44
60
|
end
|
45
61
|
end
|
46
62
|
end
|
47
|
-
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
64
|
+
private
|
65
|
+
|
66
|
+
def create_log_event(level, message, data=nil)
|
67
|
+
log_event = Hash.new
|
68
|
+
log_event[:timestamp] = Time.now.strftime("%Y-%m-%dT%H:%M:%S.%6N%z")
|
69
|
+
log_event[:level] = level
|
70
|
+
log_event[:message] = message
|
71
|
+
if data.is_a?(Hash)
|
72
|
+
log_event.merge!(data)
|
73
|
+
end
|
74
|
+
Oj.dump(log_event)
|
52
75
|
end
|
53
|
-
end
|
54
76
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
77
|
+
def setup_writer
|
78
|
+
writer = Proc.new do |log_event|
|
79
|
+
puts log_event
|
80
|
+
EM::next_tick do
|
81
|
+
@log_stream.pop(&writer)
|
82
|
+
end
|
59
83
|
end
|
84
|
+
@log_stream.pop(&writer)
|
60
85
|
end
|
86
|
+
end
|
61
87
|
|
88
|
+
class Logger
|
62
89
|
def self.get
|
63
|
-
|
90
|
+
@logger ||= LogStream.new
|
64
91
|
end
|
65
92
|
end
|
66
93
|
end
|
data/lib/sensu/rabbitmq.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
gem 'amqp', '0.9.
|
1
|
+
gem 'amqp', '0.9.9'
|
2
2
|
|
3
3
|
require 'amqp'
|
4
4
|
|
@@ -35,7 +35,7 @@ module Sensu
|
|
35
35
|
:on_tcp_connection_failure => on_failure,
|
36
36
|
:on_possible_authentication_failure => on_failure
|
37
37
|
})
|
38
|
-
@connection.logger =
|
38
|
+
@connection.logger = Logger.get
|
39
39
|
@connection.on_tcp_connection_loss do |connection, settings|
|
40
40
|
unless connection.reconnecting?
|
41
41
|
@before_reconnect.call
|
data/lib/sensu/server.rb
CHANGED
@@ -83,11 +83,11 @@ module Sensu
|
|
83
83
|
@keepalive_queue = @amq.queue!('keepalives')
|
84
84
|
@keepalive_queue.bind(@amq.direct('keepalives'))
|
85
85
|
@keepalive_queue.subscribe(:ack => true) do |header, payload|
|
86
|
-
client =
|
86
|
+
client = Oj.load(payload)
|
87
87
|
@logger.debug('received keepalive', {
|
88
88
|
:client => client
|
89
89
|
})
|
90
|
-
@redis.set('client:' + client[:name], client
|
90
|
+
@redis.set('client:' + client[:name], Oj.dump(client)) do
|
91
91
|
@redis.sadd('clients', client[:name]) do
|
92
92
|
header.ack
|
93
93
|
end
|
@@ -100,10 +100,10 @@ module Sensu
|
|
100
100
|
subdue_at = handler ? 'handler' : 'publisher'
|
101
101
|
conditions = Array.new
|
102
102
|
if check[:subdue]
|
103
|
-
conditions
|
103
|
+
conditions << check[:subdue]
|
104
104
|
end
|
105
105
|
if handler && handler[:subdue]
|
106
|
-
conditions
|
106
|
+
conditions << handler[:subdue]
|
107
107
|
end
|
108
108
|
conditions.each do |condition|
|
109
109
|
if condition.has_key?(:begin) && condition.has_key?(:end)
|
@@ -169,37 +169,26 @@ module Sensu
|
|
169
169
|
filter[:negate] ? matched : !matched
|
170
170
|
else
|
171
171
|
@logger.error('unknown filter', {
|
172
|
-
:
|
173
|
-
:name => filter_name
|
174
|
-
}
|
172
|
+
:filter_name => filter_name
|
175
173
|
})
|
176
174
|
false
|
177
175
|
end
|
178
176
|
end
|
179
177
|
|
180
|
-
def derive_handlers(handler_list
|
178
|
+
def derive_handlers(handler_list)
|
181
179
|
handler_list.inject(Array.new) do |handlers, handler_name|
|
182
180
|
if @settings.handler_exists?(handler_name)
|
183
181
|
handler = @settings[:handlers][handler_name].merge(:name => handler_name)
|
184
182
|
if handler[:type] == 'set'
|
185
|
-
|
186
|
-
handlers = handlers + derive_handlers(handler[:handlers], true)
|
187
|
-
else
|
188
|
-
@logger.error('handler sets cannot be nested', {
|
189
|
-
:handler => handler
|
190
|
-
})
|
191
|
-
end
|
183
|
+
handlers = handlers + derive_handlers(handler[:handlers])
|
192
184
|
else
|
193
|
-
handlers
|
185
|
+
handlers << handler
|
194
186
|
end
|
195
187
|
elsif @extensions.handler_exists?(handler_name)
|
196
|
-
|
197
|
-
handlers.push(handler)
|
188
|
+
handlers << @extensions[:handlers][handler_name]
|
198
189
|
else
|
199
190
|
@logger.error('unknown handler', {
|
200
|
-
:
|
201
|
-
:name => handler_name
|
202
|
-
}
|
191
|
+
:handler_name => handler_name
|
203
192
|
})
|
204
193
|
end
|
205
194
|
handlers.uniq
|
@@ -284,7 +273,7 @@ module Sensu
|
|
284
273
|
def mutate_event_data(mutator_name, event, &block)
|
285
274
|
case
|
286
275
|
when mutator_name.nil?
|
287
|
-
block.call(event
|
276
|
+
block.call(Oj.dump(event))
|
288
277
|
when @settings.mutator_exists?(mutator_name)
|
289
278
|
mutator = @settings[:mutators][mutator_name]
|
290
279
|
on_error = Proc.new do |error|
|
@@ -294,7 +283,7 @@ module Sensu
|
|
294
283
|
:error => error.to_s
|
295
284
|
})
|
296
285
|
end
|
297
|
-
execute_command(mutator[:command], event
|
286
|
+
execute_command(mutator[:command], Oj.dump(event), on_error) do |output, status|
|
298
287
|
if status == 0
|
299
288
|
block.call(output)
|
300
289
|
else
|
@@ -316,9 +305,7 @@ module Sensu
|
|
316
305
|
end
|
317
306
|
else
|
318
307
|
@logger.error('unknown mutator', {
|
319
|
-
:
|
320
|
-
:name => mutator_name
|
321
|
-
}
|
308
|
+
:mutator_name => mutator_name
|
322
309
|
})
|
323
310
|
end
|
324
311
|
end
|
@@ -403,10 +390,10 @@ module Sensu
|
|
403
390
|
})
|
404
391
|
check = result[:check]
|
405
392
|
result_set = check[:name] + ':' + check[:issued].to_s
|
406
|
-
@redis.hset('aggregation:' + result_set, result[:client],
|
393
|
+
@redis.hset('aggregation:' + result_set, result[:client], Oj.dump(
|
407
394
|
:output => check[:output],
|
408
395
|
:status => check[:status]
|
409
|
-
|
396
|
+
)) do
|
410
397
|
SEVERITIES.each do |severity|
|
411
398
|
@redis.hsetnx('aggregate:' + result_set, severity, 0)
|
412
399
|
end
|
@@ -427,7 +414,7 @@ module Sensu
|
|
427
414
|
})
|
428
415
|
@redis.get('client:' + result[:client]) do |client_json|
|
429
416
|
unless client_json.nil?
|
430
|
-
client =
|
417
|
+
client = Oj.load(client_json)
|
431
418
|
check = case
|
432
419
|
when @settings.check_exists?(result[:check][:name])
|
433
420
|
@settings[:checks][result[:check][:name]].merge(result[:check])
|
@@ -458,7 +445,7 @@ module Sensu
|
|
458
445
|
@redis.ltrim(history_key, -21, -1)
|
459
446
|
end
|
460
447
|
@redis.hget('events:' + client[:name], check[:name]) do |event_json|
|
461
|
-
previous_occurrence = event_json ?
|
448
|
+
previous_occurrence = event_json ? Oj.load(event_json) : false
|
462
449
|
is_flapping = false
|
463
450
|
if check.has_key?(:low_flap_threshold) && check.has_key?(:high_flap_threshold)
|
464
451
|
was_flapping = previous_occurrence ? previous_occurrence[:flapping] : false
|
@@ -480,14 +467,14 @@ module Sensu
|
|
480
467
|
if previous_occurrence && check[:status] == previous_occurrence[:status]
|
481
468
|
event[:occurrences] = previous_occurrence[:occurrences] += 1
|
482
469
|
end
|
483
|
-
@redis.hset('events:' + client[:name], check[:name],
|
470
|
+
@redis.hset('events:' + client[:name], check[:name], Oj.dump(
|
484
471
|
:output => check[:output],
|
485
472
|
:status => check[:status],
|
486
473
|
:issued => check[:issued],
|
487
474
|
:handlers => Array((check[:handlers] || check[:handler]) || 'default'),
|
488
475
|
:flapping => is_flapping,
|
489
476
|
:occurrences => event[:occurrences]
|
490
|
-
|
477
|
+
)) do
|
491
478
|
unless check[:handle] == false
|
492
479
|
event[:action] = is_flapping ? :flapping : :create
|
493
480
|
handle_event(event)
|
@@ -521,7 +508,7 @@ module Sensu
|
|
521
508
|
@result_queue = @amq.queue!('results')
|
522
509
|
@result_queue.bind(@amq.direct('results'))
|
523
510
|
@result_queue.subscribe(:ack => true) do |header, payload|
|
524
|
-
result =
|
511
|
+
result = Oj.load(payload)
|
525
512
|
@logger.debug('received result', {
|
526
513
|
:result => result
|
527
514
|
})
|
@@ -535,42 +522,52 @@ module Sensu
|
|
535
522
|
def publish_check_request(check)
|
536
523
|
payload = {
|
537
524
|
:name => check[:name],
|
538
|
-
:command => check[:command],
|
539
525
|
:issued => Time.now.to_i
|
540
526
|
}
|
527
|
+
if check.has_key?(:command)
|
528
|
+
payload[:command] = check[:command]
|
529
|
+
end
|
541
530
|
@logger.info('publishing check request', {
|
542
531
|
:payload => payload,
|
543
532
|
:subscribers => check[:subscribers]
|
544
533
|
})
|
545
|
-
check[:subscribers].
|
546
|
-
@amq.fanout(exchange_name).publish(payload
|
534
|
+
check[:subscribers].each do |exchange_name|
|
535
|
+
@amq.fanout(exchange_name).publish(Oj.dump(payload))
|
547
536
|
end
|
548
537
|
end
|
549
538
|
|
550
|
-
def
|
551
|
-
@logger.debug('scheduling check requests')
|
539
|
+
def schedule_checks(checks)
|
552
540
|
check_count = 0
|
553
541
|
stagger = testing? ? 0 : 2
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
})
|
567
|
-
end
|
542
|
+
checks.each do |check|
|
543
|
+
check_count += 1
|
544
|
+
scheduling_delay = stagger * check_count % 30
|
545
|
+
@master_timers << EM::Timer.new(scheduling_delay) do
|
546
|
+
interval = testing? ? 0.5 : check[:interval]
|
547
|
+
@master_timers << EM::PeriodicTimer.new(interval) do
|
548
|
+
unless action_subdued?(check)
|
549
|
+
publish_check_request(check)
|
550
|
+
else
|
551
|
+
@logger.info('check request was subdued', {
|
552
|
+
:check => check
|
553
|
+
})
|
568
554
|
end
|
569
555
|
end
|
570
556
|
end
|
571
557
|
end
|
572
558
|
end
|
573
559
|
|
560
|
+
def setup_publisher
|
561
|
+
@logger.debug('scheduling check requests')
|
562
|
+
standard_checks = @settings.checks.reject do |check|
|
563
|
+
check[:standalone] || check[:publish] == false
|
564
|
+
end
|
565
|
+
extension_checks = @extensions.checks.reject do |check|
|
566
|
+
check[:standalone] || check[:publish] == false || !check[:interval].is_a?(Integer)
|
567
|
+
end
|
568
|
+
schedule_checks(standard_checks + extension_checks)
|
569
|
+
end
|
570
|
+
|
574
571
|
def publish_result(client, check)
|
575
572
|
payload = {
|
576
573
|
:client => client[:name],
|
@@ -579,7 +576,7 @@ module Sensu
|
|
579
576
|
@logger.info('publishing check result', {
|
580
577
|
:payload => payload
|
581
578
|
})
|
582
|
-
@amq.direct('results').publish(payload
|
579
|
+
@amq.direct('results').publish(Oj.dump(payload))
|
583
580
|
end
|
584
581
|
|
585
582
|
def determine_stale_clients
|
@@ -587,7 +584,7 @@ module Sensu
|
|
587
584
|
@redis.smembers('clients') do |clients|
|
588
585
|
clients.each do |client_name|
|
589
586
|
@redis.get('client:' + client_name) do |client_json|
|
590
|
-
client =
|
587
|
+
client = Oj.load(client_json)
|
591
588
|
check = {
|
592
589
|
:name => 'keepalive',
|
593
590
|
:issued => Time.now.to_i
|
@@ -821,8 +818,15 @@ module Sensu
|
|
821
818
|
end
|
822
819
|
|
823
820
|
def trap_signals
|
824
|
-
|
821
|
+
@signals = Array.new
|
822
|
+
STOP_SIGNALS.each do |signal|
|
825
823
|
Signal.trap(signal) do
|
824
|
+
@signals << signal
|
825
|
+
end
|
826
|
+
end
|
827
|
+
EM::PeriodicTimer.new(1) do
|
828
|
+
signal = @signals.shift
|
829
|
+
if STOP_SIGNALS.include?(signal)
|
826
830
|
@logger.warn('received signal', {
|
827
831
|
:signal => signal
|
828
832
|
})
|
data/lib/sensu/settings.rb
CHANGED
@@ -38,9 +38,17 @@ module Sensu
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
type = category.to_s.chop
|
42
|
+
|
43
|
+
define_method((type + '_exists?').to_sym) do |name|
|
42
44
|
@settings[category].has_key?(name.to_sym)
|
43
45
|
end
|
46
|
+
|
47
|
+
define_method(('invalid_' + type).to_sym) do |details, reason|
|
48
|
+
invalid(reason, {
|
49
|
+
type => details
|
50
|
+
})
|
51
|
+
end
|
44
52
|
end
|
45
53
|
|
46
54
|
def load_env
|
@@ -70,10 +78,13 @@ module Sensu
|
|
70
78
|
end
|
71
79
|
|
72
80
|
def load_file(file)
|
81
|
+
@logger.debug('loading config file', {
|
82
|
+
:config_file => file
|
83
|
+
})
|
73
84
|
if File.readable?(file)
|
74
85
|
begin
|
75
86
|
contents = File.open(file, 'r').read
|
76
|
-
config =
|
87
|
+
config = Oj.load(contents)
|
77
88
|
merged = deep_merge(@settings, config)
|
78
89
|
unless @loaded_files.empty?
|
79
90
|
@logger.warn('config file applied changes', {
|
@@ -83,8 +94,8 @@ module Sensu
|
|
83
94
|
end
|
84
95
|
@settings = merged
|
85
96
|
@indifferent_access = false
|
86
|
-
@loaded_files
|
87
|
-
rescue
|
97
|
+
@loaded_files << file
|
98
|
+
rescue Oj::ParseError => error
|
88
99
|
@logger.error('config file must be valid json', {
|
89
100
|
:config_file => file,
|
90
101
|
:error => error.to_s
|
@@ -116,40 +127,47 @@ module Sensu
|
|
116
127
|
|
117
128
|
def validate
|
118
129
|
@logger.debug('validating settings')
|
119
|
-
|
130
|
+
SETTINGS_CATEGORIES.each do |category|
|
131
|
+
unless @settings[category].is_a?(Hash)
|
132
|
+
invalid(category.to_s + ' must be a hash')
|
133
|
+
end
|
134
|
+
send(category).each do |details|
|
135
|
+
send(('validate_' + category.to_s.chop).to_sym, details)
|
136
|
+
end
|
137
|
+
end
|
120
138
|
case File.basename($0)
|
121
|
-
when 'rspec'
|
122
|
-
validate_client
|
123
|
-
validate_api
|
124
|
-
validate_server
|
125
139
|
when 'sensu-client'
|
126
140
|
validate_client
|
127
141
|
when 'sensu-api'
|
128
142
|
validate_api
|
129
|
-
when '
|
130
|
-
|
143
|
+
when 'rspec'
|
144
|
+
validate_client
|
145
|
+
validate_api
|
131
146
|
end
|
132
147
|
@logger.debug('settings are valid')
|
133
148
|
end
|
134
149
|
|
135
150
|
private
|
136
151
|
|
137
|
-
def invalid(reason,
|
152
|
+
def invalid(reason, data={})
|
138
153
|
@logger.fatal('invalid settings', {
|
139
154
|
:reason => reason
|
140
|
-
}.merge(
|
155
|
+
}.merge(data))
|
141
156
|
@logger.fatal('SENSU NOT RUNNING!')
|
142
157
|
exit 2
|
143
158
|
end
|
144
159
|
|
145
|
-
def validate_subdue(
|
146
|
-
|
160
|
+
def validate_subdue(type, details)
|
161
|
+
condition = details[:subdue]
|
162
|
+
data = {
|
163
|
+
type => details
|
164
|
+
}
|
147
165
|
unless condition.is_a?(Hash)
|
148
|
-
invalid(type + ' subdue must be a hash',
|
166
|
+
invalid(type + ' subdue must be a hash', data)
|
149
167
|
end
|
150
168
|
if condition.has_key?(:at)
|
151
169
|
unless %w[handler publisher].include?(condition[:at])
|
152
|
-
invalid(type + ' subdue at must be either handler or publisher',
|
170
|
+
invalid(type + ' subdue at must be either handler or publisher', data)
|
153
171
|
end
|
154
172
|
end
|
155
173
|
if condition.has_key?(:begin) || condition.has_key?(:end)
|
@@ -157,117 +175,196 @@ module Sensu
|
|
157
175
|
Time.parse(condition[:begin])
|
158
176
|
Time.parse(condition[:end])
|
159
177
|
rescue
|
160
|
-
invalid(type + ' subdue begin & end times must be valid',
|
178
|
+
invalid(type + ' subdue begin & end times must be valid', data)
|
161
179
|
end
|
162
180
|
end
|
163
181
|
if condition.has_key?(:days)
|
164
182
|
unless condition[:days].is_a?(Array)
|
165
|
-
invalid(type + ' subdue days must be an array',
|
183
|
+
invalid(type + ' subdue days must be an array', data)
|
166
184
|
end
|
167
185
|
condition[:days].each do |day|
|
168
186
|
days = %w[sunday monday tuesday wednesday thursday friday saturday]
|
169
187
|
unless day.is_a?(String) && days.include?(day.downcase)
|
170
|
-
invalid(type + ' subdue days must be valid days of the week',
|
188
|
+
invalid(type + ' subdue days must be valid days of the week', data)
|
171
189
|
end
|
172
190
|
end
|
173
191
|
end
|
174
192
|
if condition.has_key?(:exceptions)
|
175
193
|
unless condition[:exceptions].is_a?(Array)
|
176
|
-
invalid(type + ' subdue exceptions must be an array',
|
194
|
+
invalid(type + ' subdue exceptions must be an array', data)
|
177
195
|
end
|
178
196
|
condition[:exceptions].each do |exception|
|
179
197
|
unless exception.is_a?(Hash)
|
180
|
-
invalid(type + ' subdue exceptions must each be a hash',
|
198
|
+
invalid(type + ' subdue exceptions must each be a hash', data)
|
181
199
|
end
|
182
200
|
if exception.has_key?(:begin) || exception.has_key?(:end)
|
183
201
|
begin
|
184
202
|
Time.parse(exception[:begin])
|
185
203
|
Time.parse(exception[:end])
|
186
204
|
rescue
|
187
|
-
invalid(type + ' subdue exception begin & end times must be valid',
|
205
|
+
invalid(type + ' subdue exception begin & end times must be valid', data)
|
188
206
|
end
|
189
207
|
end
|
190
208
|
end
|
191
209
|
end
|
192
210
|
end
|
193
211
|
|
194
|
-
def
|
195
|
-
unless
|
196
|
-
|
197
|
-
end
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
unless check[:command].is_a?(String)
|
205
|
-
invalid('check is missing command', {
|
206
|
-
:check => check
|
207
|
-
})
|
212
|
+
def validate_check(check)
|
213
|
+
unless check[:interval].is_a?(Integer) && check[:interval] > 0
|
214
|
+
invalid_check(check, 'check is missing interval')
|
215
|
+
end
|
216
|
+
unless check[:command].is_a?(String)
|
217
|
+
invalid_check(check, 'check is missing command')
|
218
|
+
end
|
219
|
+
unless check[:standalone]
|
220
|
+
unless check[:subscribers].is_a?(Array)
|
221
|
+
invalid_check(check, 'check is missing subscribers')
|
208
222
|
end
|
209
|
-
|
210
|
-
unless
|
211
|
-
|
212
|
-
:check => check
|
213
|
-
})
|
223
|
+
check[:subscribers].each do |subscriber|
|
224
|
+
unless subscriber.is_a?(String) && !subscriber.empty?
|
225
|
+
invalid_check(check, 'check subscribers must each be a string')
|
214
226
|
end
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
227
|
+
end
|
228
|
+
end
|
229
|
+
if check.has_key?(:timeout)
|
230
|
+
unless check[:timeout].is_a?(Numeric)
|
231
|
+
invalid_check(check, 'check timeout must be numeric')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
if check.has_key?(:handler)
|
235
|
+
unless check[:handler].is_a?(String)
|
236
|
+
invalid_check(check, 'check handler must be a string')
|
237
|
+
end
|
238
|
+
end
|
239
|
+
if check.has_key?(:handlers)
|
240
|
+
unless check[:handlers].is_a?(Array)
|
241
|
+
invalid_check(check, 'check handlers must be an array')
|
242
|
+
end
|
243
|
+
check[:handlers].each do |handler_name|
|
244
|
+
unless handler_name.is_a?(String)
|
245
|
+
invalid_check(check, 'check handlers must each be a string')
|
221
246
|
end
|
222
247
|
end
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
248
|
+
end
|
249
|
+
if check.has_key?(:low_flap_threshold) || check.has_key?(:high_flap_threshold)
|
250
|
+
unless check[:low_flap_threshold].is_a?(Integer)
|
251
|
+
invalid_check(check, 'check low flap threshold must be numeric')
|
252
|
+
end
|
253
|
+
unless check[:high_flap_threshold].is_a?(Integer)
|
254
|
+
invalid_check(check, 'check high flap threshold must be numeric')
|
255
|
+
end
|
256
|
+
end
|
257
|
+
if check.has_key?(:subdue)
|
258
|
+
validate_subdue('check', check)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def validate_mutator(mutator)
|
263
|
+
unless mutator[:command].is_a?(String)
|
264
|
+
invalid_mutator(mutator, 'mutator is missing command')
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def validate_filter(filter)
|
269
|
+
unless filter[:attributes].is_a?(Hash)
|
270
|
+
invalid_filter(filter, 'filter attributes must be a hash')
|
271
|
+
end
|
272
|
+
if filter.has_key?(:negate)
|
273
|
+
unless !!filter[:negate] == filter[:negate]
|
274
|
+
invalid_filter(filter, 'filter negate must be boolean')
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def validate_handler(handler)
|
280
|
+
unless handler[:type].is_a?(String)
|
281
|
+
invalid_handler(handler, 'handler is missing type')
|
282
|
+
end
|
283
|
+
case handler[:type]
|
284
|
+
when 'pipe'
|
285
|
+
unless handler[:command].is_a?(String)
|
286
|
+
invalid_handler(handler, 'handler is missing command')
|
287
|
+
end
|
288
|
+
when 'tcp', 'udp'
|
289
|
+
unless handler[:socket].is_a?(Hash)
|
290
|
+
invalid_handler(handler, 'handler is missing socket hash')
|
291
|
+
end
|
292
|
+
unless handler[:socket][:host].is_a?(String)
|
293
|
+
invalid_handler(handler, 'handler is missing socket host')
|
294
|
+
end
|
295
|
+
unless handler[:socket][:port].is_a?(Integer)
|
296
|
+
invalid_handler(handler, 'handler is missing socket port')
|
297
|
+
end
|
298
|
+
if handler[:socket].has_key?(:timeout)
|
299
|
+
unless handler[:socket][:timeout].is_a?(Integer)
|
300
|
+
invalid_handler(handler, 'handler socket timeout must be an integer')
|
228
301
|
end
|
229
302
|
end
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
303
|
+
when 'amqp'
|
304
|
+
unless handler[:exchange].is_a?(Hash)
|
305
|
+
invalid_handler(handler, 'handler is missing exchange hash')
|
306
|
+
end
|
307
|
+
unless handler[:exchange][:name].is_a?(String)
|
308
|
+
invalid_handler(handler, 'handler is missing exchange name')
|
309
|
+
end
|
310
|
+
if handler[:exchange].has_key?(:type)
|
311
|
+
unless %w[direct fanout topic].include?(handler[:exchange][:type])
|
312
|
+
invalid_handler(handler, 'handler exchange type is invalid')
|
235
313
|
end
|
236
314
|
end
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
315
|
+
when 'set'
|
316
|
+
unless handler[:handlers].is_a?(Array)
|
317
|
+
invalid_handler(handler, 'handler set handlers must be an array')
|
318
|
+
end
|
319
|
+
handler[:handlers].each do |handler_name|
|
320
|
+
unless handler_name.is_a?(String)
|
321
|
+
invalid_handler(handler, 'handler set handlers must each be a string')
|
242
322
|
end
|
243
|
-
|
244
|
-
|
245
|
-
invalid('check handlers items must be strings', {
|
246
|
-
:check => check
|
247
|
-
})
|
248
|
-
end
|
323
|
+
if handler_exists?(handler_name) && @settings[:handlers][handler_name.to_sym][:type] == 'set'
|
324
|
+
invalid_handler(handler, 'handler sets cannot be nested')
|
249
325
|
end
|
250
326
|
end
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
327
|
+
else
|
328
|
+
invalid_handler(handler, 'unknown handler type')
|
329
|
+
end
|
330
|
+
if handler.has_key?(:filter)
|
331
|
+
unless handler[:filter].is_a?(String)
|
332
|
+
invalid_handler(handler, 'handler filter must be a string')
|
257
333
|
end
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
334
|
+
end
|
335
|
+
if handler.has_key?(:filters)
|
336
|
+
unless handler[:filters].is_a?(Array)
|
337
|
+
invalid_handler(handler, 'handler filters must be an array')
|
338
|
+
end
|
339
|
+
handler[:filters].each do |filter_name|
|
340
|
+
unless filter_name.is_a?(String)
|
341
|
+
invalid_handler(handler, 'handler filters items must be strings')
|
263
342
|
end
|
264
343
|
end
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
344
|
+
end
|
345
|
+
if handler.has_key?(:mutator)
|
346
|
+
unless handler[:mutator].is_a?(String)
|
347
|
+
invalid_handler(handler, 'handler mutator must be a string')
|
348
|
+
end
|
349
|
+
end
|
350
|
+
if handler.has_key?(:handle_flapping)
|
351
|
+
unless !!handler[:handle_flapping] == handler[:handle_flapping]
|
352
|
+
invalid_handler(handler, 'handler handle_flapping must be boolean')
|
269
353
|
end
|
270
354
|
end
|
355
|
+
if handler.has_key?(:severities)
|
356
|
+
unless handler[:severities].is_a?(Array) && !handler[:severities].empty?
|
357
|
+
invalid_handler(handler, 'handler severities must be an array and not empty')
|
358
|
+
end
|
359
|
+
handler[:severities].each do |severity|
|
360
|
+
unless SEVERITIES.include?(severity)
|
361
|
+
invalid_handler(handler, 'handler severities are invalid')
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
if handler.has_key?(:subdue)
|
366
|
+
validate_subdue('handler', handler)
|
367
|
+
end
|
271
368
|
end
|
272
369
|
|
273
370
|
def validate_client
|
@@ -280,7 +377,7 @@ module Sensu
|
|
280
377
|
unless @settings[:client][:address].is_a?(String)
|
281
378
|
invalid('client must have an address')
|
282
379
|
end
|
283
|
-
unless @settings[:client][:subscriptions].is_a?(Array)
|
380
|
+
unless @settings[:client][:subscriptions].is_a?(Array)
|
284
381
|
invalid('client must have subscriptions')
|
285
382
|
end
|
286
383
|
@settings[:client][:subscriptions].each do |subscription|
|
@@ -306,168 +403,5 @@ module Sensu
|
|
306
403
|
end
|
307
404
|
end
|
308
405
|
end
|
309
|
-
|
310
|
-
def validate_server
|
311
|
-
unless @settings[:filters].is_a?(Hash)
|
312
|
-
invalid('filters must be a hash')
|
313
|
-
end
|
314
|
-
filters.each do |filter|
|
315
|
-
unless filter[:attributes].is_a?(Hash)
|
316
|
-
invalid('filter attributes must be a hash', {
|
317
|
-
:filter => filter
|
318
|
-
})
|
319
|
-
end
|
320
|
-
if filter.has_key?(:negate)
|
321
|
-
unless !!filter[:negate] == filter[:negate]
|
322
|
-
invalid('filter negate must be boolean', {
|
323
|
-
:filter => filter
|
324
|
-
})
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
unless @settings[:mutators].is_a?(Hash)
|
329
|
-
invalid('mutators must be a hash')
|
330
|
-
end
|
331
|
-
mutators.each do |mutator|
|
332
|
-
unless mutator[:command].is_a?(String)
|
333
|
-
invalid('mutator is missing command', {
|
334
|
-
:mutator => mutator
|
335
|
-
})
|
336
|
-
end
|
337
|
-
end
|
338
|
-
unless @settings[:handlers].is_a?(Hash)
|
339
|
-
invalid('handlers must be a hash')
|
340
|
-
end
|
341
|
-
unless @settings[:handlers].include?(:default)
|
342
|
-
invalid('missing default handler')
|
343
|
-
end
|
344
|
-
handlers.each do |handler|
|
345
|
-
unless handler[:type].is_a?(String)
|
346
|
-
invalid('handler is missing type', {
|
347
|
-
:handler => handler
|
348
|
-
})
|
349
|
-
end
|
350
|
-
case handler[:type]
|
351
|
-
when 'pipe'
|
352
|
-
unless handler[:command].is_a?(String)
|
353
|
-
invalid('handler is missing command', {
|
354
|
-
:handler => handler
|
355
|
-
})
|
356
|
-
end
|
357
|
-
when 'tcp', 'udp'
|
358
|
-
unless handler[:socket].is_a?(Hash)
|
359
|
-
invalid('handler is missing socket hash', {
|
360
|
-
:handler => handler
|
361
|
-
})
|
362
|
-
end
|
363
|
-
unless handler[:socket][:host].is_a?(String)
|
364
|
-
invalid('handler is missing socket host', {
|
365
|
-
:handler => handler
|
366
|
-
})
|
367
|
-
end
|
368
|
-
unless handler[:socket][:port].is_a?(Integer)
|
369
|
-
invalid('handler is missing socket port', {
|
370
|
-
:handler => handler
|
371
|
-
})
|
372
|
-
end
|
373
|
-
if handler[:socket].has_key?(:timeout)
|
374
|
-
unless handler[:socket][:timeout].is_a?(Integer)
|
375
|
-
invalid('handler socket timeout must be an integer', {
|
376
|
-
:handler => handler
|
377
|
-
})
|
378
|
-
end
|
379
|
-
end
|
380
|
-
when 'amqp'
|
381
|
-
unless handler[:exchange].is_a?(Hash)
|
382
|
-
invalid('handler is missing exchange hash', {
|
383
|
-
:handler => handler
|
384
|
-
})
|
385
|
-
end
|
386
|
-
unless handler[:exchange][:name].is_a?(String)
|
387
|
-
invalid('handler is missing exchange name', {
|
388
|
-
:handler => handler
|
389
|
-
})
|
390
|
-
end
|
391
|
-
if handler[:exchange].has_key?(:type)
|
392
|
-
unless %w[direct fanout topic].include?(handler[:exchange][:type])
|
393
|
-
invalid('handler exchange type is invalid', {
|
394
|
-
:handler => handler
|
395
|
-
})
|
396
|
-
end
|
397
|
-
end
|
398
|
-
when 'set'
|
399
|
-
unless handler[:handlers].is_a?(Array)
|
400
|
-
invalid('handler set handlers must be an array', {
|
401
|
-
:handler => handler
|
402
|
-
})
|
403
|
-
end
|
404
|
-
handler[:handlers].each do |handler_name|
|
405
|
-
unless handler_name.is_a?(String)
|
406
|
-
invalid('handler set handlers items must be strings', {
|
407
|
-
:handler => handler
|
408
|
-
})
|
409
|
-
end
|
410
|
-
end
|
411
|
-
else
|
412
|
-
invalid('unknown handler type', {
|
413
|
-
:handler => handler
|
414
|
-
})
|
415
|
-
end
|
416
|
-
if handler.has_key?(:filter)
|
417
|
-
unless handler[:filter].is_a?(String)
|
418
|
-
invalid('handler filter must be a string', {
|
419
|
-
:handler => handler
|
420
|
-
})
|
421
|
-
end
|
422
|
-
end
|
423
|
-
if handler.has_key?(:filters)
|
424
|
-
unless handler[:filters].is_a?(Array)
|
425
|
-
invalid('handler filters must be an array', {
|
426
|
-
:handler => handler
|
427
|
-
})
|
428
|
-
end
|
429
|
-
handler[:filters].each do |filter_name|
|
430
|
-
unless filter_name.is_a?(String)
|
431
|
-
invalid('handler filters items must be strings', {
|
432
|
-
:handler => handler
|
433
|
-
})
|
434
|
-
end
|
435
|
-
end
|
436
|
-
end
|
437
|
-
if handler.has_key?(:mutator)
|
438
|
-
unless handler[:mutator].is_a?(String)
|
439
|
-
invalid('handler mutator must be a string', {
|
440
|
-
:handler => handler
|
441
|
-
})
|
442
|
-
end
|
443
|
-
end
|
444
|
-
if handler.has_key?(:handle_flapping)
|
445
|
-
unless !!handler[:handle_flapping] == handler[:handle_flapping]
|
446
|
-
invalid('handler handle_flapping must be boolean', {
|
447
|
-
:handler => handler
|
448
|
-
})
|
449
|
-
end
|
450
|
-
end
|
451
|
-
if handler.has_key?(:severities)
|
452
|
-
unless handler[:severities].is_a?(Array) && !handler[:severities].empty?
|
453
|
-
invalid('handler severities must be an array and not empty', {
|
454
|
-
:handler => handler
|
455
|
-
})
|
456
|
-
end
|
457
|
-
handler[:severities].each do |severity|
|
458
|
-
unless SEVERITIES.include?(severity)
|
459
|
-
invalid('handler severities are invalid', {
|
460
|
-
:handler => handler
|
461
|
-
})
|
462
|
-
end
|
463
|
-
end
|
464
|
-
end
|
465
|
-
if handler.has_key?(:subdue)
|
466
|
-
validate_subdue(handler[:subdue], {
|
467
|
-
:handler => handler
|
468
|
-
})
|
469
|
-
end
|
470
|
-
end
|
471
|
-
end
|
472
406
|
end
|
473
407
|
end
|