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.
@@ -1,17 +1,15 @@
1
1
  module Sensu
2
2
  unless defined?(Sensu::VERSION)
3
- VERSION = '0.9.11'
3
+ VERSION = '0.9.12.beta'
4
4
 
5
- DEFAULT_OPTIONS = {
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
@@ -13,8 +13,14 @@ module Sensu
13
13
  end
14
14
 
15
15
  EXTENSION_CATEGORIES.each do |category|
16
- define_method(category.to_s.chop + '_exists?') do |extension_name|
17
- @extensions[category].has_key?(extension_name)
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,
@@ -10,7 +10,7 @@ module Sensu
10
10
  end
11
11
 
12
12
  def run(event, settings, &block)
13
- block.call(event.to_json, 0)
13
+ block.call(Oj.dump(event), 0)
14
14
  end
15
15
  end
16
16
  end
@@ -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
- @logger = Cabin::Channel.get
4
+ @log_stream = EM::Queue.new
5
+ @log_level = :info
11
6
  STDOUT.sync = true
12
7
  STDERR.reopen(STDOUT)
13
- @logger.subscribe(STDOUT)
8
+ setup_writer
14
9
  end
15
10
 
16
- def level=(log_level)
17
- @logger.level = log_level
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
- @logger.error('log file is not writable', {
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
- @logger.level = @logger.level == :info ? :debug : :info
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
- class Logger
50
- def self.get
51
- Cabin::Channel.get
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
- class NullLogger
56
- [:debug, :info, :warn, :error, :fatal].each do |method|
57
- define_method(method) do |*arguments|
58
- true
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
- self.new
90
+ @logger ||= LogStream.new
64
91
  end
65
92
  end
66
93
  end
@@ -1,4 +1,4 @@
1
- gem 'amqp', '0.9.8'
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 = NullLogger.get
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 = JSON.parse(payload, :symbolize_names => true)
86
+ client = Oj.load(payload)
87
87
  @logger.debug('received keepalive', {
88
88
  :client => client
89
89
  })
90
- @redis.set('client:' + client[:name], client.to_json) do
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.push(check[:subdue])
103
+ conditions << check[:subdue]
104
104
  end
105
105
  if handler && handler[:subdue]
106
- conditions.push(handler[:subdue])
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
- :filter => {
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, nested=false)
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
- unless nested
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.push(handler)
185
+ handlers << handler
194
186
  end
195
187
  elsif @extensions.handler_exists?(handler_name)
196
- handler = @extensions[:handlers][handler_name]
197
- handlers.push(handler)
188
+ handlers << @extensions[:handlers][handler_name]
198
189
  else
199
190
  @logger.error('unknown handler', {
200
- :handler => {
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.to_json)
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.to_json, on_error) do |output, status|
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
- :mutator => {
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
- }.to_json) do
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 = JSON.parse(client_json, :symbolize_names => true)
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 ? JSON.parse(event_json, :symbolize_names => true) : false
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
- }.to_json) do
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 = JSON.parse(payload, :symbolize_names => true)
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].uniq.each do |exchange_name|
546
- @amq.fanout(exchange_name).publish(payload.to_json)
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 setup_publisher
551
- @logger.debug('scheduling check requests')
539
+ def schedule_checks(checks)
552
540
  check_count = 0
553
541
  stagger = testing? ? 0 : 2
554
- @settings.checks.each do |check|
555
- unless check[:publish] == false || check[:standalone]
556
- check_count += 1
557
- scheduling_delay = stagger * check_count % 30
558
- @master_timers << EM::Timer.new(scheduling_delay) do
559
- interval = testing? ? 0.5 : check[:interval]
560
- @master_timers << EM::PeriodicTimer.new(interval) do
561
- unless action_subdued?(check)
562
- publish_check_request(check)
563
- else
564
- @logger.info('action is subdued', {
565
- :check => check
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.to_json)
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 = JSON.parse(client_json, :symbolize_names => true)
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
- %w[INT TERM].each do |signal|
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
  })
@@ -38,9 +38,17 @@ module Sensu
38
38
  end
39
39
  end
40
40
 
41
- define_method((category.to_s.chop + '_exists?').to_sym) do |name|
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 = JSON.parse(contents, :symbolize_names => true)
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.push(file)
87
- rescue JSON::ParserError => error
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
- validate_checks
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 'sensu-server'
130
- validate_server
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, details={})
152
+ def invalid(reason, data={})
138
153
  @logger.fatal('invalid settings', {
139
154
  :reason => reason
140
- }.merge(details))
155
+ }.merge(data))
141
156
  @logger.fatal('SENSU NOT RUNNING!')
142
157
  exit 2
143
158
  end
144
159
 
145
- def validate_subdue(condition, details={})
146
- type = details.has_key?(:check) ? 'check' : 'handler'
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', details)
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', details)
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', details)
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', details)
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', details)
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', details)
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', details)
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', details)
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 validate_checks
195
- unless @settings[:checks].is_a?(Hash)
196
- invalid('checks must be a hash')
197
- end
198
- checks.each do |check|
199
- unless check[:interval].is_a?(Integer) && check[:interval] > 0
200
- invalid('check is missing interval', {
201
- :check => check
202
- })
203
- end
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
- unless check[:standalone]
210
- unless check[:subscribers].is_a?(Array) && check[:subscribers].size > 0
211
- invalid('check is missing subscribers', {
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
- check[:subscribers].each do |subscriber|
216
- unless subscriber.is_a?(String) && !subscriber.empty?
217
- invalid('check subscribers must each be a string', {
218
- :check => check
219
- })
220
- end
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
- if check.has_key?(:timeout)
224
- unless check[:timeout].is_a?(Numeric)
225
- invalid('check timeout must be numeric', {
226
- :check => check
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
- if check.has_key?(:handler)
231
- unless check[:handler].is_a?(String)
232
- invalid('check handler must be a string', {
233
- :check => check
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
- if check.has_key?(:handlers)
238
- unless check[:handlers].is_a?(Array)
239
- invalid('check handlers must be an array', {
240
- :check => check
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
- check[:handlers].each do |handler_name|
244
- unless handler_name.is_a?(String)
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
- if check.has_key?(:low_flap_threshold)
252
- unless check[:low_flap_threshold].is_a?(Integer)
253
- invalid('flap thresholds must be integers', {
254
- :check => check
255
- })
256
- end
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
- if check.has_key?(:high_flap_threshold)
259
- unless check[:high_flap_threshold].is_a?(Integer)
260
- invalid('flap thresholds must be integers', {
261
- :check => check
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
- if check.has_key?(:subdue)
266
- validate_subdue(check[:subdue], {
267
- :check => check
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) && !@settings[:client][:subscriptions].empty?
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