sensu 0.9.9 → 0.9.10

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 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