sensu 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## 0.9.10 - 2013-01-30
2
+
3
+ ### Features
4
+
5
+ Handlers can be subdued like checks, suppression windows.
6
+
7
+ ### Non-backwards compatible changes
8
+
9
+ Extensions have access to settings.
10
+
11
+ ### Other
12
+
13
+ Client queue names are now determined by the broker (RabbitMQ).
14
+
15
+ Improved zombie reaping.
16
+
1
17
  ## 0.9.9 - 2013-01-14
2
18
 
3
19
  ### Features
data/lib/sensu/client.rb CHANGED
@@ -134,42 +134,44 @@ module Sensu
134
134
 
135
135
  def setup_subscriptions
136
136
  @logger.debug('subscribing to client subscriptions')
137
- @uniq_queue_name ||= rand(36 ** 32).to_s(36)
138
- @check_request_queue = @amq.queue(@uniq_queue_name, :auto_delete => true)
139
- @settings[:client][:subscriptions].uniq.each do |exchange_name|
140
- @logger.debug('binding queue to exchange', {
141
- :queue => @uniq_queue_name,
142
- :exchange => {
143
- :name => exchange_name
144
- }
145
- })
146
- @check_request_queue.bind(@amq.fanout(exchange_name))
147
- end
148
- @check_request_queue.subscribe do |payload|
149
- begin
150
- check = JSON.parse(payload, :symbolize_names => true)
151
- @logger.info('received check request', {
152
- :check => check
137
+ @check_request_queue = @amq.queue('', :auto_delete => true) do |queue|
138
+ @settings[:client][:subscriptions].uniq.each do |exchange_name|
139
+ @logger.debug('binding queue to exchange', {
140
+ :queue => {
141
+ :name => queue.name
142
+ },
143
+ :exchange => {
144
+ :name => exchange_name
145
+ }
153
146
  })
154
- if @settings.check_exists?(check[:name])
155
- check.merge!(@settings[:checks][check[:name]])
156
- execute_check(check)
157
- elsif @safe_mode
158
- @logger.warn('check is not defined', {
147
+ queue.bind(@amq.fanout(exchange_name))
148
+ end
149
+ queue.subscribe do |payload|
150
+ begin
151
+ check = JSON.parse(payload, :symbolize_names => true)
152
+ @logger.info('received check request', {
159
153
  :check => check
160
154
  })
161
- check[:output] = 'Check is not defined (safe mode)'
162
- check[:status] = 3
163
- check[:handle] = false
164
- publish_result(check)
165
- else
166
- execute_check(check)
155
+ if @settings.check_exists?(check[:name])
156
+ check.merge!(@settings[:checks][check[:name]])
157
+ execute_check(check)
158
+ elsif @safe_mode
159
+ @logger.warn('check is not defined', {
160
+ :check => check
161
+ })
162
+ check[:output] = 'Check is not defined (safe mode)'
163
+ check[:status] = 3
164
+ check[:handle] = false
165
+ publish_result(check)
166
+ else
167
+ execute_check(check)
168
+ end
169
+ rescue JSON::ParserError => error
170
+ @logger.warn('check request payload must be valid json', {
171
+ :payload => payload,
172
+ :error => error.to_s
173
+ })
167
174
  end
168
- rescue JSON::ParserError => error
169
- @logger.warn('check request payload must be valid json', {
170
- :payload => payload,
171
- :error => error.to_s
172
- })
173
175
  end
174
176
  end
175
177
  end
@@ -1,6 +1,6 @@
1
1
  module Sensu
2
2
  unless defined?(Sensu::VERSION)
3
- VERSION = '0.9.9'
3
+ VERSION = '0.9.10'
4
4
 
5
5
  DEFAULT_OPTIONS = {
6
6
  :config_file => '/etc/sensu/config.json',
@@ -82,7 +82,7 @@ module Sensu
82
82
  definition.has_key?(key.to_sym)
83
83
  end
84
84
 
85
- def run(event=nil, &block)
85
+ def run(event=nil, settings={}, &block)
86
86
  block.call('noop', 0)
87
87
  end
88
88
 
@@ -9,7 +9,7 @@ module Sensu
9
9
  'outputs json event data'
10
10
  end
11
11
 
12
- def run(event, &block)
12
+ def run(event, settings, &block)
13
13
  block.call(event.to_json, 0)
14
14
  end
15
15
  end
@@ -9,7 +9,7 @@ module Sensu
9
9
  'returns check output'
10
10
  end
11
11
 
12
- def run(event, &block)
12
+ def run(event, settings, &block)
13
13
  block.call(event[:check][:output], 0)
14
14
  end
15
15
  end
data/lib/sensu/io.rb CHANGED
@@ -37,6 +37,10 @@ module Sensu
37
37
  kill_process_group(child.pid)
38
38
  wait_on_process_group(child.pid)
39
39
  ['Execution timed out', 2]
40
+ rescue => error
41
+ kill_process_group(child.pid)
42
+ wait_on_process_group(child.pid)
43
+ raise error
40
44
  end
41
45
  end
42
46
 
@@ -27,9 +27,6 @@ module Sensu
27
27
  end
28
28
 
29
29
  def connect(options={})
30
- options.reject! do |key, value|
31
- key == :heartbeat
32
- end
33
30
  on_failure = Proc.new do
34
31
  error = RabbitMQError.new('cannot connect to rabbitmq')
35
32
  @on_error.call(error)
data/lib/sensu/server.rb CHANGED
@@ -94,12 +94,20 @@ module Sensu
94
94
  end
95
95
  end
96
96
 
97
- def check_subdued?(check, subdue_at)
97
+ def action_subdued?(check, handler=nil)
98
98
  subdue = false
99
- if check[:subdue].is_a?(Hash)
100
- if check[:subdue].has_key?(:begin) && check[:subdue].has_key?(:end)
101
- begin_time = Time.parse(check[:subdue][:begin])
102
- end_time = Time.parse(check[:subdue][:end])
99
+ subdue_at = handler ? 'handler' : 'publisher'
100
+ conditions = Array.new
101
+ if check[:subdue]
102
+ conditions.push(check[:subdue])
103
+ end
104
+ if handler && handler[:subdue]
105
+ conditions.push(handler[:subdue])
106
+ end
107
+ conditions.each do |condition|
108
+ if condition.has_key?(:begin) && condition.has_key?(:end)
109
+ begin_time = Time.parse(condition[:begin])
110
+ end_time = Time.parse(condition[:end])
103
111
  if end_time < begin_time
104
112
  if Time.now < end_time
105
113
  begin_time = Time.parse('12:00:00 AM')
@@ -111,19 +119,26 @@ module Sensu
111
119
  subdue = true
112
120
  end
113
121
  end
114
- if check[:subdue].has_key?(:days)
115
- days = check[:subdue][:days].map(&:downcase)
122
+ if condition.has_key?(:days)
123
+ days = condition[:days].map(&:downcase)
116
124
  if days.include?(Time.now.strftime('%A').downcase)
117
125
  subdue = true
118
126
  end
119
127
  end
120
- if subdue && check[:subdue].has_key?(:exceptions)
121
- subdue = check[:subdue][:exceptions].none? do |exception|
128
+ if subdue && condition.has_key?(:exceptions)
129
+ subdue = condition[:exceptions].none? do |exception|
122
130
  Time.now >= Time.parse(exception[:begin]) && Time.now <= Time.parse(exception[:end])
123
131
  end
124
132
  end
133
+ if subdue
134
+ if subdue_at == (condition[:at] || 'handler')
135
+ break
136
+ else
137
+ subdue = false
138
+ end
139
+ end
125
140
  end
126
- subdue && subdue_at == (check[:subdue][:at] || 'handler').to_sym
141
+ subdue
127
142
  end
128
143
 
129
144
  def filter_attributes_match?(hash_one, hash_two)
@@ -202,8 +217,8 @@ module Sensu
202
217
  })
203
218
  next
204
219
  end
205
- if check_subdued?(event[:check], :handler)
206
- @logger.info('check is subdued at handler', {
220
+ if action_subdued?(event[:check], handler)
221
+ @logger.info('action is subdued', {
207
222
  :event => event,
208
223
  :handler => handler
209
224
  })
@@ -266,31 +281,36 @@ module Sensu
266
281
  end
267
282
 
268
283
  def mutate_event_data(mutator_name, event, &block)
269
- on_error = Proc.new do |error|
270
- @logger.error('mutator error', {
271
- :event => event,
272
- :mutator => mutator,
273
- :error => error.to_s
274
- })
275
- end
276
284
  case
277
285
  when mutator_name.nil?
278
286
  block.call(event.to_json)
279
287
  when @settings.mutator_exists?(mutator_name)
280
288
  mutator = @settings[:mutators][mutator_name]
289
+ on_error = Proc.new do |error|
290
+ @logger.error('mutator error', {
291
+ :event => event,
292
+ :mutator => mutator,
293
+ :error => error.to_s
294
+ })
295
+ end
281
296
  execute_command(mutator[:command], event.to_json, on_error) do |output, status|
282
297
  if status == 0
283
298
  block.call(output)
284
299
  else
285
- on_error.call('non-zero exit status (' + status + '): ' + output)
300
+ on_error.call('non-zero exit status (' + status.to_s + '): ' + output)
286
301
  end
287
302
  end
288
303
  when @extensions.mutator_exists?(mutator_name)
289
- @extensions[:mutators][mutator_name].run(event) do |output, status|
304
+ extension = @extensions[:mutators][mutator_name]
305
+ extension.run(event, @settings.to_hash) do |output, status|
290
306
  if status == 0
291
307
  block.call(output)
292
308
  else
293
- on_error.call('non-zero exit status (' + status + '): ' + output)
309
+ @logger.error('mutator error', {
310
+ :event => event,
311
+ :extension => extension,
312
+ :error => 'non-zero exit status (' + status.to_s + '): ' + output
313
+ })
294
314
  end
295
315
  end
296
316
  else
@@ -365,7 +385,7 @@ module Sensu
365
385
  end
366
386
  @handlers_in_progress_count -= 1
367
387
  when 'extension'
368
- handler.run(event_data) do |output, status|
388
+ handler.run(event_data, @settings.to_hash) do |output, status|
369
389
  output.split(/\n+/).each do |line|
370
390
  @logger.info(line)
371
391
  end
@@ -536,8 +556,12 @@ module Sensu
536
556
  @master_timers << EM::Timer.new(scheduling_delay) do
537
557
  interval = testing? ? 0.5 : check[:interval]
538
558
  @master_timers << EM::PeriodicTimer.new(interval) do
539
- unless check_subdued?(check, :publisher)
559
+ unless action_subdued?(check)
540
560
  publish_check_request(check)
561
+ else
562
+ @logger.info('action is subdued', {
563
+ :check => check
564
+ })
541
565
  end
542
566
  end
543
567
  end
@@ -20,11 +20,15 @@ module Sensu
20
20
  @indifferent_access = true
21
21
  end
22
22
 
23
- def [](key)
23
+ def to_hash
24
24
  unless @indifferent_access
25
25
  indifferent_access!
26
26
  end
27
- @settings[key.to_sym]
27
+ @settings
28
+ end
29
+
30
+ def [](key)
31
+ to_hash[key]
28
32
  end
29
33
 
30
34
  SETTINGS_CATEGORIES.each do |category|
@@ -137,6 +141,55 @@ module Sensu
137
141
  exit 2
138
142
  end
139
143
 
144
+ def validate_subdue(condition, details={})
145
+ type = details.has_key?(:check) ? 'check' : 'handler'
146
+ unless condition.is_a?(Hash)
147
+ invalid(type + ' subdue must be a hash', details)
148
+ end
149
+ if condition.has_key?(:at)
150
+ unless %w[handler publisher].include?(condition[:at])
151
+ invalid(type + ' subdue at must be either handler or publisher', details)
152
+ end
153
+ end
154
+ if condition.has_key?(:begin) || condition.has_key?(:end)
155
+ begin
156
+ Time.parse(condition[:begin])
157
+ Time.parse(condition[:end])
158
+ rescue
159
+ invalid(type + ' subdue begin & end times must be valid', details)
160
+ end
161
+ end
162
+ if condition.has_key?(:days)
163
+ unless condition[:days].is_a?(Array)
164
+ invalid(type + ' subdue days must be an array', details)
165
+ end
166
+ condition[:days].each do |day|
167
+ days = %w[sunday monday tuesday wednesday thursday friday saturday]
168
+ unless day.is_a?(String) && days.include?(day.downcase)
169
+ invalid(type + ' subdue days must be valid days of the week', details)
170
+ end
171
+ end
172
+ end
173
+ if condition.has_key?(:exceptions)
174
+ unless condition[:exceptions].is_a?(Array)
175
+ invalid(type + ' subdue exceptions must be an array', details)
176
+ end
177
+ condition[:exceptions].each do |exception|
178
+ unless exception.is_a?(Hash)
179
+ invalid(type + ' subdue exceptions must each be a hash', details)
180
+ end
181
+ if exception.has_key?(:begin) || exception.has_key?(:end)
182
+ begin
183
+ Time.parse(exception[:begin])
184
+ Time.parse(exception[:end])
185
+ rescue
186
+ invalid(type + ' subdue exception begin & end times must be valid', details)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+
140
193
  def validate_checks
141
194
  unless @settings[:checks].is_a?(Hash)
142
195
  invalid('checks must be a hash')
@@ -209,60 +262,9 @@ module Sensu
209
262
  end
210
263
  end
211
264
  if check.has_key?(:subdue)
212
- unless check[:subdue].is_a?(Hash)
213
- invalid('check subdue must be a hash', {
214
- :check => check
215
- })
216
- end
217
- if check[:subdue].has_key?(:begin) || check[:subdue].has_key?(:end)
218
- begin
219
- Time.parse(check[:subdue][:begin])
220
- Time.parse(check[:subdue][:end])
221
- rescue
222
- invalid('check subdue begin & end times must be valid', {
223
- :check => check
224
- })
225
- end
226
- end
227
- if check[:subdue].has_key?(:days)
228
- unless check[:subdue][:days].is_a?(Array)
229
- invalid('check subdue days must be an array', {
230
- :check => check
231
- })
232
- end
233
- check[:subdue][:days].each do |day|
234
- days = %w[sunday monday tuesday wednesday thursday friday saturday]
235
- unless day.is_a?(String) && days.include?(day.downcase)
236
- invalid('check subdue days must be valid days of the week', {
237
- :check => check
238
- })
239
- end
240
- end
241
- end
242
- if check[:subdue].has_key?(:exceptions)
243
- unless check[:subdue][:exceptions].is_a?(Array)
244
- invalid('check subdue exceptions must be an array', {
245
- :check => check
246
- })
247
- end
248
- check[:subdue][:exceptions].each do |exception|
249
- unless exception.is_a?(Hash)
250
- invalid('check subdue exceptions must each be a hash', {
251
- :check => check
252
- })
253
- end
254
- if exception.has_key?(:begin) || exception.has_key?(:end)
255
- begin
256
- Time.parse(exception[:begin])
257
- Time.parse(exception[:end])
258
- rescue
259
- invalid('check subdue exception begin & end times must be valid', {
260
- :check => check
261
- })
262
- end
263
- end
264
- end
265
- end
265
+ validate_subdue(check[:subdue], {
266
+ :check => check
267
+ })
266
268
  end
267
269
  end
268
270
  end
@@ -459,6 +461,11 @@ module Sensu
459
461
  end
460
462
  end
461
463
  end
464
+ if handler.has_key?(:subdue)
465
+ validate_subdue(handler[:subdue], {
466
+ :handler => handler
467
+ })
468
+ end
462
469
  end
463
470
  end
464
471
  end
data/sensu.gemspec CHANGED
@@ -1,3 +1,4 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  require File.join(File.dirname(__FILE__), 'lib', 'sensu', 'constants')
2
3
 
3
4
  Gem::Specification.new do |s|
@@ -13,6 +14,7 @@ Gem::Specification.new do |s|
13
14
  s.has_rdoc = false
14
15
 
15
16
  s.add_dependency('eventmachine', '1.0.0')
17
+ s.add_dependency('amq-client', '0.9.11')
16
18
  s.add_dependency('amqp', '0.9.8')
17
19
  s.add_dependency('json')
18
20
  s.add_dependency('cabin', '0.4.4')
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu
3
3
  version: !ruby/object:Gem::Version
4
- hash: 41
4
+ hash: 47
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
- - 9
10
- version: 0.9.9
9
+ - 10
10
+ version: 0.9.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sean Porter
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2013-01-14 00:00:00 -08:00
19
+ date: 2013-01-30 00:00:00 -08:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -36,9 +36,25 @@ dependencies:
36
36
  type: :runtime
37
37
  version_requirements: *id001
38
38
  - !ruby/object:Gem::Dependency
39
- name: amqp
39
+ name: amq-client
40
40
  prerelease: false
41
41
  requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - "="
45
+ - !ruby/object:Gem::Version
46
+ hash: 45
47
+ segments:
48
+ - 0
49
+ - 9
50
+ - 11
51
+ version: 0.9.11
52
+ type: :runtime
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: amqp
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
42
58
  none: false
43
59
  requirements:
44
60
  - - "="
@@ -50,11 +66,11 @@ dependencies:
50
66
  - 8
51
67
  version: 0.9.8
52
68
  type: :runtime
53
- version_requirements: *id002
69
+ version_requirements: *id003
54
70
  - !ruby/object:Gem::Dependency
55
71
  name: json
56
72
  prerelease: false
57
- requirement: &id003 !ruby/object:Gem::Requirement
73
+ requirement: &id004 !ruby/object:Gem::Requirement
58
74
  none: false
59
75
  requirements:
60
76
  - - ">="
@@ -64,11 +80,11 @@ dependencies:
64
80
  - 0
65
81
  version: "0"
66
82
  type: :runtime
67
- version_requirements: *id003
83
+ version_requirements: *id004
68
84
  - !ruby/object:Gem::Dependency
69
85
  name: cabin
70
86
  prerelease: false
71
- requirement: &id004 !ruby/object:Gem::Requirement
87
+ requirement: &id005 !ruby/object:Gem::Requirement
72
88
  none: false
73
89
  requirements:
74
90
  - - "="
@@ -80,11 +96,11 @@ dependencies:
80
96
  - 4
81
97
  version: 0.4.4
82
98
  type: :runtime
83
- version_requirements: *id004
99
+ version_requirements: *id005
84
100
  - !ruby/object:Gem::Dependency
85
101
  name: em-redis-unified
86
102
  prerelease: false
87
- requirement: &id005 !ruby/object:Gem::Requirement
103
+ requirement: &id006 !ruby/object:Gem::Requirement
88
104
  none: false
89
105
  requirements:
90
106
  - - "="
@@ -96,11 +112,11 @@ dependencies:
96
112
  - 1
97
113
  version: 0.4.1
98
114
  type: :runtime
99
- version_requirements: *id005
115
+ version_requirements: *id006
100
116
  - !ruby/object:Gem::Dependency
101
117
  name: thin
102
118
  prerelease: false
103
- requirement: &id006 !ruby/object:Gem::Requirement
119
+ requirement: &id007 !ruby/object:Gem::Requirement
104
120
  none: false
105
121
  requirements:
106
122
  - - "="
@@ -112,11 +128,11 @@ dependencies:
112
128
  - 0
113
129
  version: 1.5.0
114
130
  type: :runtime
115
- version_requirements: *id006
131
+ version_requirements: *id007
116
132
  - !ruby/object:Gem::Dependency
117
133
  name: async_sinatra
118
134
  prerelease: false
119
- requirement: &id007 !ruby/object:Gem::Requirement
135
+ requirement: &id008 !ruby/object:Gem::Requirement
120
136
  none: false
121
137
  requirements:
122
138
  - - "="
@@ -128,11 +144,11 @@ dependencies:
128
144
  - 0
129
145
  version: 1.0.0
130
146
  type: :runtime
131
- version_requirements: *id007
147
+ version_requirements: *id008
132
148
  - !ruby/object:Gem::Dependency
133
149
  name: rake
134
150
  prerelease: false
135
- requirement: &id008 !ruby/object:Gem::Requirement
151
+ requirement: &id009 !ruby/object:Gem::Requirement
136
152
  none: false
137
153
  requirements:
138
154
  - - ">="
@@ -142,11 +158,11 @@ dependencies:
142
158
  - 0
143
159
  version: "0"
144
160
  type: :development
145
- version_requirements: *id008
161
+ version_requirements: *id009
146
162
  - !ruby/object:Gem::Dependency
147
163
  name: rspec
148
164
  prerelease: false
149
- requirement: &id009 !ruby/object:Gem::Requirement
165
+ requirement: &id010 !ruby/object:Gem::Requirement
150
166
  none: false
151
167
  requirements:
152
168
  - - ">="
@@ -156,11 +172,11 @@ dependencies:
156
172
  - 0
157
173
  version: "0"
158
174
  type: :development
159
- version_requirements: *id009
175
+ version_requirements: *id010
160
176
  - !ruby/object:Gem::Dependency
161
177
  name: em-http-request
162
178
  prerelease: false
163
- requirement: &id010 !ruby/object:Gem::Requirement
179
+ requirement: &id011 !ruby/object:Gem::Requirement
164
180
  none: false
165
181
  requirements:
166
182
  - - ">="
@@ -170,7 +186,7 @@ dependencies:
170
186
  - 0
171
187
  version: "0"
172
188
  type: :development
173
- version_requirements: *id010
189
+ version_requirements: *id011
174
190
  description: A monitoring framework that aims to be simple, malleable, and scalable. Uses the publish/subscribe model.
175
191
  email:
176
192
  - portertech@gmail.com