sensu 0.9.11 → 0.9.12.beta

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