sensu 0.9.6.beta.4 → 0.9.6.beta.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sensu/api.rb +22 -18
- data/lib/sensu/base.rb +2 -12
- data/lib/sensu/client.rb +44 -28
- data/lib/sensu/constants.rb +1 -1
- data/lib/sensu/redis.rb +81 -0
- data/lib/sensu/server.rb +79 -59
- data/lib/sensu/settings.rb +80 -32
- metadata +5 -6
- data/lib/sensu/patches/amqp.rb +0 -7
- data/lib/sensu/patches/redis.rb +0 -71
data/lib/sensu/api.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'base')
|
2
|
+
require File.join(File.dirname(__FILE__), 'redis')
|
2
3
|
|
3
4
|
require 'thin'
|
4
5
|
require 'sinatra/async'
|
5
|
-
require 'redis'
|
6
|
-
|
7
|
-
require File.join(File.dirname(__FILE__), 'patches', 'redis')
|
8
6
|
|
9
7
|
module Sensu
|
10
8
|
class API < Sinatra::Base
|
@@ -26,13 +24,17 @@ module Sensu
|
|
26
24
|
end
|
27
25
|
|
28
26
|
def self.setup(options={})
|
27
|
+
$logger = Cabin::Channel.get
|
29
28
|
base = Sensu::Base.new(options)
|
30
|
-
$logger = base.logger
|
31
29
|
$settings = base.settings
|
32
30
|
$logger.debug('connecting to redis', {
|
33
31
|
:settings => $settings[:redis]
|
34
32
|
})
|
35
|
-
$redis = Redis.connect($settings[:redis])
|
33
|
+
$redis = Sensu::Redis.connect($settings[:redis])
|
34
|
+
$redis.on_disconnect = Proc.new do
|
35
|
+
$logger.warn('reconnecting to redis')
|
36
|
+
$redis.reconnect!
|
37
|
+
end
|
36
38
|
$logger.debug('connecting to rabbitmq', {
|
37
39
|
:settings => $settings[:rabbitmq]
|
38
40
|
})
|
@@ -45,7 +47,15 @@ module Sensu
|
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
|
-
def
|
50
|
+
def healthy?
|
51
|
+
unless $redis.connected?
|
52
|
+
unless env['REQUEST_PATH'] == '/info'
|
53
|
+
halt 500
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def request_log
|
49
59
|
$logger.info([env['REQUEST_METHOD'], env['REQUEST_PATH']].join(' '), {
|
50
60
|
:remote_address => env['REMOTE_ADDR'],
|
51
61
|
:user_agent => env['HTTP_USER_AGENT'],
|
@@ -71,7 +81,8 @@ module Sensu
|
|
71
81
|
|
72
82
|
before do
|
73
83
|
content_type 'application/json'
|
74
|
-
request_log
|
84
|
+
request_log
|
85
|
+
healthy?
|
75
86
|
end
|
76
87
|
|
77
88
|
aget '/info' do
|
@@ -80,16 +91,10 @@ module Sensu
|
|
80
91
|
:version => Sensu::VERSION
|
81
92
|
},
|
82
93
|
:health => {
|
83
|
-
:redis => 'ok',
|
84
|
-
:rabbitmq => 'ok'
|
94
|
+
:redis => $redis.connected? ? 'ok' : 'down',
|
95
|
+
:rabbitmq => $rabbitmq.connected? ? 'ok' : 'down'
|
85
96
|
}
|
86
97
|
}
|
87
|
-
if $redis.reconnecting?
|
88
|
-
response[:health][:redis] = 'down'
|
89
|
-
end
|
90
|
-
if $rabbitmq.reconnecting?
|
91
|
-
response[:health][:rabbitmq] = 'down'
|
92
|
-
end
|
93
98
|
body response.to_json
|
94
99
|
end
|
95
100
|
|
@@ -378,10 +383,9 @@ module Sensu
|
|
378
383
|
:signal => signal
|
379
384
|
})
|
380
385
|
$logger.warn('stopping')
|
386
|
+
$redis.close
|
381
387
|
$logger.warn('stopping reactor')
|
382
|
-
EM::
|
383
|
-
EM::stop_event_loop
|
384
|
-
end
|
388
|
+
EM::stop_event_loop
|
385
389
|
end
|
386
390
|
end
|
387
391
|
end
|
data/lib/sensu/base.rb
CHANGED
@@ -10,7 +10,6 @@ require 'cabin'
|
|
10
10
|
require 'amqp'
|
11
11
|
|
12
12
|
require File.join(File.dirname(__FILE__), 'patches', 'ruby')
|
13
|
-
require File.join(File.dirname(__FILE__), 'patches', 'amqp')
|
14
13
|
|
15
14
|
require File.join(File.dirname(__FILE__), 'constants')
|
16
15
|
require File.join(File.dirname(__FILE__), 'cli')
|
@@ -20,11 +19,10 @@ require File.join(File.dirname(__FILE__), 'process')
|
|
20
19
|
|
21
20
|
module Sensu
|
22
21
|
class Base
|
23
|
-
attr_reader :options, :
|
22
|
+
attr_reader :options, :settings
|
24
23
|
|
25
24
|
def initialize(options={})
|
26
25
|
@options = Sensu::DEFAULT_OPTIONS.merge(options)
|
27
|
-
@logger = Cabin::Channel.get
|
28
26
|
setup_logging
|
29
27
|
setup_settings
|
30
28
|
setup_process
|
@@ -43,15 +41,7 @@ module Sensu
|
|
43
41
|
Dir[@options[:config_dir] + '/**/*.json'].each do |file|
|
44
42
|
@settings.load_file(file)
|
45
43
|
end
|
46
|
-
|
47
|
-
@settings.validate
|
48
|
-
rescue => error
|
49
|
-
@logger.fatal('config invalid', {
|
50
|
-
:error => error.to_s
|
51
|
-
})
|
52
|
-
@logger.fatal('SENSU NOT RUNNING!')
|
53
|
-
exit 2
|
54
|
-
end
|
44
|
+
@settings.validate
|
55
45
|
@settings.set_env
|
56
46
|
end
|
57
47
|
|
data/lib/sensu/client.rb
CHANGED
@@ -22,8 +22,8 @@ module Sensu
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def initialize(options={})
|
25
|
+
@logger = Cabin::Channel.get
|
25
26
|
base = Sensu::Base.new(options)
|
26
|
-
@logger = base.logger
|
27
27
|
@settings = base.settings
|
28
28
|
@timers = Array.new
|
29
29
|
@checks_in_progress = Array.new
|
@@ -48,8 +48,8 @@ module Sensu
|
|
48
48
|
def setup_keepalives
|
49
49
|
@logger.debug('scheduling keepalives')
|
50
50
|
publish_keepalive
|
51
|
-
@timers << EM::PeriodicTimer.new(
|
52
|
-
|
51
|
+
@timers << EM::PeriodicTimer.new(20) do
|
52
|
+
if @rabbitmq.connected?
|
53
53
|
publish_keepalive
|
54
54
|
end
|
55
55
|
end
|
@@ -90,7 +90,8 @@ module Sensu
|
|
90
90
|
substitute
|
91
91
|
end
|
92
92
|
if unmatched_tokens.empty?
|
93
|
-
execute =
|
93
|
+
execute = Proc.new do
|
94
|
+
check = check.dup
|
94
95
|
started = Time.now.to_f
|
95
96
|
begin
|
96
97
|
IO.popen(command + ' 2>&1') do |io|
|
@@ -105,14 +106,11 @@ module Sensu
|
|
105
106
|
check[:status] = 2
|
106
107
|
end
|
107
108
|
check[:duration] = ('%.3f' % (Time.now.to_f - started)).to_f
|
109
|
+
check
|
108
110
|
end
|
109
|
-
publish =
|
111
|
+
publish = Proc.new do |check|
|
110
112
|
unless check[:status].nil?
|
111
113
|
publish_result(check)
|
112
|
-
else
|
113
|
-
@logger.warn('nil exit status code', {
|
114
|
-
:check => check
|
115
|
-
})
|
116
114
|
end
|
117
115
|
@checks_in_progress.delete(check[:name])
|
118
116
|
end
|
@@ -178,28 +176,28 @@ module Sensu
|
|
178
176
|
def setup_rabbitmq_monitor
|
179
177
|
@logger.debug('monitoring rabbitmq connection')
|
180
178
|
@timers << EM::PeriodicTimer.new(5) do
|
181
|
-
if @rabbitmq.
|
182
|
-
@logger.warn('reconnecting to rabbitmq')
|
183
|
-
else
|
179
|
+
if @rabbitmq.connected?
|
184
180
|
unless @check_request_queue.subscribed?
|
185
181
|
@logger.warn('re-subscribing to client subscriptions')
|
186
182
|
setup_subscriptions
|
187
183
|
end
|
184
|
+
else
|
185
|
+
@logger.warn('reconnecting to rabbitmq')
|
188
186
|
end
|
189
187
|
end
|
190
188
|
end
|
191
189
|
|
192
|
-
def setup_standalone
|
190
|
+
def setup_standalone
|
193
191
|
@logger.debug('scheduling standalone checks')
|
194
192
|
standalone_check_count = 0
|
195
|
-
stagger =
|
193
|
+
stagger = testing? ? 0 : 7
|
196
194
|
@settings.checks.each do |check|
|
197
195
|
if check[:standalone]
|
198
196
|
standalone_check_count += 1
|
199
197
|
@timers << EM::Timer.new(stagger * standalone_check_count) do
|
200
|
-
interval =
|
198
|
+
interval = testing? ? 0.5 : check[:interval]
|
201
199
|
@timers << EM::PeriodicTimer.new(interval) do
|
202
|
-
|
200
|
+
if @rabbitmq.connected?
|
203
201
|
check[:issued] = Time.now.to_i
|
204
202
|
execute_check(check)
|
205
203
|
end
|
@@ -226,19 +224,33 @@ module Sensu
|
|
226
224
|
end
|
227
225
|
end
|
228
226
|
|
229
|
-
def
|
227
|
+
def unsubscribe(&block)
|
228
|
+
if @rabbitmq.connected?
|
229
|
+
@logger.warn('unsubscribing from client subscriptions')
|
230
|
+
@check_request_queue.unsubscribe do
|
231
|
+
if block
|
232
|
+
block.call
|
233
|
+
end
|
234
|
+
end
|
235
|
+
else
|
236
|
+
if block
|
237
|
+
block.call
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def complete_checks_in_progress(&block)
|
230
243
|
@logger.info('completing checks in progress', {
|
231
244
|
:checks_in_progress => @checks_in_progress
|
232
245
|
})
|
233
|
-
|
246
|
+
complete = EM::tick_loop do
|
234
247
|
if @checks_in_progress.empty?
|
235
248
|
:stop
|
236
249
|
end
|
237
250
|
end
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
EM::stop_event_loop
|
251
|
+
complete.on_stop do
|
252
|
+
if block
|
253
|
+
block.call
|
242
254
|
end
|
243
255
|
end
|
244
256
|
end
|
@@ -251,14 +263,18 @@ module Sensu
|
|
251
263
|
@timers.each do |timer|
|
252
264
|
timer.cancel
|
253
265
|
end
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
266
|
+
unsubscribe do
|
267
|
+
complete_checks_in_progress do
|
268
|
+
@logger.warn('stopping reactor')
|
269
|
+
EM::stop_event_loop
|
258
270
|
end
|
259
|
-
else
|
260
|
-
EM::stop_event_loop
|
261
271
|
end
|
262
272
|
end
|
273
|
+
|
274
|
+
private
|
275
|
+
|
276
|
+
def testing?
|
277
|
+
File.basename($0) == 'rake'
|
278
|
+
end
|
263
279
|
end
|
264
280
|
end
|
data/lib/sensu/constants.rb
CHANGED
data/lib/sensu/redis.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Sensu
|
4
|
+
class Redis < Redis::Client
|
5
|
+
attr_accessor :host, :port, :password, :on_disconnect
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@logger = Cabin::Channel.get
|
10
|
+
@connected = false
|
11
|
+
@closing_connection = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def connection_completed
|
15
|
+
@connected = true
|
16
|
+
if @password
|
17
|
+
auth(@password).callback do |reply|
|
18
|
+
unless reply == 'OK'
|
19
|
+
@logger.fatal('redis authentication failed')
|
20
|
+
close_connection
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
info.callback do |reply|
|
25
|
+
redis_version = reply.split(/\n/).first.split(/:/).last.chomp
|
26
|
+
if redis_version < '1.3.14'
|
27
|
+
@logger.fatal('redis version must be >= 2.0 RC 1')
|
28
|
+
close_connection
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def reconnect!
|
34
|
+
EM::Timer.new(1) do
|
35
|
+
reconnect(@host, @port)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def close
|
40
|
+
@closing_connection = true
|
41
|
+
close_connection
|
42
|
+
end
|
43
|
+
|
44
|
+
def unbind
|
45
|
+
@connected = false
|
46
|
+
super
|
47
|
+
if @on_disconnect && !@closing_connection
|
48
|
+
@on_disconnect.call
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def connected?
|
53
|
+
@connected
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.connect(options)
|
57
|
+
options ||= Hash.new
|
58
|
+
if options.is_a?(String)
|
59
|
+
begin
|
60
|
+
uri = URI.parse(options)
|
61
|
+
host = uri.host
|
62
|
+
port = uri.port || 6379
|
63
|
+
password = uri.password
|
64
|
+
rescue
|
65
|
+
@logger.fatal('invalid redis url')
|
66
|
+
@logger.fatal('SENSU NOT RUNNING!')
|
67
|
+
exit 2
|
68
|
+
end
|
69
|
+
else
|
70
|
+
host = options[:host] || 'localhost'
|
71
|
+
port = options[:port] || 6379
|
72
|
+
password = options[:password]
|
73
|
+
end
|
74
|
+
EM::connect(host, port, self) do |redis|
|
75
|
+
redis.host = host
|
76
|
+
redis.port = port
|
77
|
+
redis.password = password
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/sensu/server.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'base')
|
2
|
-
|
3
|
-
require 'redis'
|
4
|
-
|
5
|
-
require File.join(File.dirname(__FILE__), 'patches', 'redis')
|
2
|
+
require File.join(File.dirname(__FILE__), 'redis')
|
6
3
|
|
7
4
|
module Sensu
|
8
5
|
class Server
|
@@ -27,8 +24,8 @@ module Sensu
|
|
27
24
|
end
|
28
25
|
|
29
26
|
def initialize(options={})
|
27
|
+
@logger = Cabin::Channel.get
|
30
28
|
base = Sensu::Base.new(options)
|
31
|
-
@logger = base.logger
|
32
29
|
@settings = base.settings
|
33
30
|
@timers = Array.new
|
34
31
|
@handlers_in_progress = 0
|
@@ -38,7 +35,13 @@ module Sensu
|
|
38
35
|
@logger.debug('connecting to redis', {
|
39
36
|
:settings => @settings[:redis]
|
40
37
|
})
|
41
|
-
@redis = Redis.connect(@settings[:redis])
|
38
|
+
@redis = Sensu::Redis.connect(@settings[:redis])
|
39
|
+
unless testing?
|
40
|
+
@redis.on_disconnect = Proc.new do
|
41
|
+
@logger.fatal('redis connection closed')
|
42
|
+
stop('TERM')
|
43
|
+
end
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
def setup_rabbitmq
|
@@ -63,7 +66,7 @@ module Sensu
|
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
66
|
-
def check_subdued?(check,
|
69
|
+
def check_subdued?(check, subdue_at)
|
67
70
|
subdue = false
|
68
71
|
if check[:subdue].is_a?(Hash)
|
69
72
|
if check[:subdue].has_key?(:start) && check[:subdue].has_key?(:end)
|
@@ -93,8 +96,8 @@ module Sensu
|
|
93
96
|
end
|
94
97
|
end
|
95
98
|
if subdue
|
96
|
-
(!check[:subdue].has_key?(:at) &&
|
97
|
-
(check[:subdue].has_key?(:at) && check[:subdue][:at].to_sym ==
|
99
|
+
(!check[:subdue].has_key?(:at) && subdue_at == :handler) ||
|
100
|
+
(check[:subdue].has_key?(:at) && check[:subdue][:at].to_sym == subdue_at)
|
98
101
|
else
|
99
102
|
false
|
100
103
|
end
|
@@ -109,11 +112,8 @@ module Sensu
|
|
109
112
|
else
|
110
113
|
['default']
|
111
114
|
end
|
112
|
-
handler_list.reject! do |handler_name|
|
113
|
-
!@settings.handler_exists?(handler_name)
|
114
|
-
end
|
115
115
|
handler_list.map! do |handler_name|
|
116
|
-
if @settings[:handlers][handler_name][:type] == 'set'
|
116
|
+
if @settings.handler_exists?(handler_name) && @settings[:handlers][handler_name][:type] == 'set'
|
117
117
|
@settings[:handlers][handler_name][:handlers]
|
118
118
|
else
|
119
119
|
handler_name
|
@@ -122,7 +122,16 @@ module Sensu
|
|
122
122
|
handler_list.flatten!
|
123
123
|
handler_list.uniq!
|
124
124
|
handler_list.reject! do |handler_name|
|
125
|
-
|
125
|
+
unless @settings.handler_exists?(handler_name)
|
126
|
+
@logger.warn('unknown handler', {
|
127
|
+
:handler => {
|
128
|
+
:name => handler_name
|
129
|
+
}
|
130
|
+
})
|
131
|
+
true
|
132
|
+
else
|
133
|
+
false
|
134
|
+
end
|
126
135
|
end
|
127
136
|
handler_list.map do |handler_name|
|
128
137
|
@settings[:handlers][handler_name].merge(:name => handler_name)
|
@@ -131,31 +140,23 @@ module Sensu
|
|
131
140
|
|
132
141
|
def handle_event(event)
|
133
142
|
unless check_subdued?(event[:check], :handler)
|
134
|
-
report = proc do |output|
|
135
|
-
if output.is_a?(String)
|
136
|
-
output.split(/\n+/).each do |line|
|
137
|
-
@logger.info('handler output', {
|
138
|
-
:output => line
|
139
|
-
})
|
140
|
-
end
|
141
|
-
end
|
142
|
-
@handlers_in_progress -= 1
|
143
|
-
end
|
144
143
|
handlers = check_handlers(event[:check])
|
145
144
|
handlers.each do |handler|
|
146
|
-
@logger.
|
145
|
+
@logger.info('handling event', {
|
147
146
|
:event => event,
|
148
147
|
:handler => handler
|
149
148
|
})
|
150
149
|
@handlers_in_progress += 1
|
151
150
|
case handler[:type]
|
152
151
|
when 'pipe'
|
153
|
-
execute =
|
152
|
+
execute = Proc.new do
|
154
153
|
begin
|
155
154
|
IO.popen(handler[:command] + ' 2>&1', 'r+') do |io|
|
156
155
|
io.write(event.to_json)
|
157
156
|
io.close_write
|
158
|
-
io.read
|
157
|
+
io.read.split(/\n+/).each do |line|
|
158
|
+
@logger.debug(line)
|
159
|
+
end
|
159
160
|
end
|
160
161
|
rescue Errno::ENOENT => error
|
161
162
|
@logger.error('handler does not exist', {
|
@@ -177,7 +178,10 @@ module Sensu
|
|
177
178
|
})
|
178
179
|
end
|
179
180
|
end
|
180
|
-
|
181
|
+
complete = Proc.new do
|
182
|
+
@handlers_in_progress -= 1
|
183
|
+
end
|
184
|
+
EM::defer(execute, complete)
|
181
185
|
when 'amqp'
|
182
186
|
exchange_name = handler[:exchange][:name]
|
183
187
|
exchange_type = handler[:exchange].has_key?(:type) ? handler[:exchange][:type].to_sym : :direct
|
@@ -324,18 +328,18 @@ module Sensu
|
|
324
328
|
end
|
325
329
|
end
|
326
330
|
|
327
|
-
def setup_publisher
|
331
|
+
def setup_publisher
|
328
332
|
@logger.debug('scheduling check requests')
|
329
333
|
check_count = 0
|
330
|
-
stagger =
|
334
|
+
stagger = testing? ? 0 : 7
|
331
335
|
@settings.checks.each do |check|
|
332
336
|
unless check[:publish] == false || check[:standalone]
|
333
337
|
check_count += 1
|
334
338
|
@timers << EM::Timer.new(stagger * check_count) do
|
335
|
-
interval =
|
339
|
+
interval = testing? ? 0.5 : check[:interval]
|
336
340
|
@timers << EM::PeriodicTimer.new(interval) do
|
337
341
|
unless check_subdued?(check, :publisher)
|
338
|
-
|
342
|
+
if @rabbitmq.connected?
|
339
343
|
payload = {
|
340
344
|
:name => check[:name],
|
341
345
|
:issued => Time.now.to_i
|
@@ -369,7 +373,7 @@ module Sensu
|
|
369
373
|
def setup_keepalive_monitor
|
370
374
|
@logger.debug('monitoring client keepalives')
|
371
375
|
@timers << EM::PeriodicTimer.new(30) do
|
372
|
-
|
376
|
+
if @rabbitmq.connected?
|
373
377
|
@logger.debug('checking for stale client info')
|
374
378
|
@redis.smembers('clients').callback do |clients|
|
375
379
|
clients.each do |client_name|
|
@@ -382,17 +386,17 @@ module Sensu
|
|
382
386
|
time_since_last_keepalive = Time.now.to_i - client[:timestamp]
|
383
387
|
case
|
384
388
|
when time_since_last_keepalive >= 180
|
385
|
-
check[:output] = 'No keep-alive sent from
|
389
|
+
check[:output] = 'No keep-alive sent from client in over 180 seconds'
|
386
390
|
check[:status] = 2
|
387
391
|
publish_result(client, check)
|
388
392
|
when time_since_last_keepalive >= 120
|
389
|
-
check[:output] = 'No keep-alive sent from
|
393
|
+
check[:output] = 'No keep-alive sent from client in over 120 seconds'
|
390
394
|
check[:status] = 1
|
391
395
|
publish_result(client, check)
|
392
396
|
else
|
393
397
|
@redis.hexists('events:' + client[:name], 'keepalive').callback do |exists|
|
394
398
|
if exists
|
395
|
-
check[:output] = 'Keep-alive sent from
|
399
|
+
check[:output] = 'Keep-alive sent from client'
|
396
400
|
check[:status] = 0
|
397
401
|
publish_result(client, check)
|
398
402
|
end
|
@@ -434,7 +438,7 @@ module Sensu
|
|
434
438
|
end
|
435
439
|
|
436
440
|
def resign_as_master(&block)
|
437
|
-
if @is_master
|
441
|
+
if @redis.connected? && @is_master
|
438
442
|
@redis.del('lock:master').callback do
|
439
443
|
@logger.warn('resigned as master')
|
440
444
|
if block
|
@@ -442,7 +446,6 @@ module Sensu
|
|
442
446
|
end
|
443
447
|
end
|
444
448
|
else
|
445
|
-
@logger.warn('not currently master')
|
446
449
|
if block
|
447
450
|
block.call
|
448
451
|
end
|
@@ -465,9 +468,7 @@ module Sensu
|
|
465
468
|
def setup_rabbitmq_monitor
|
466
469
|
@logger.debug('monitoring rabbitmq connection')
|
467
470
|
@timers << EM::PeriodicTimer.new(5) do
|
468
|
-
if @rabbitmq.
|
469
|
-
@logger.warn('reconnecting to rabbitmq')
|
470
|
-
else
|
471
|
+
if @rabbitmq.connected?
|
471
472
|
unless @keepalive_queue.subscribed?
|
472
473
|
@logger.warn('re-subscribing to keepalives')
|
473
474
|
setup_keepalives
|
@@ -476,23 +477,42 @@ module Sensu
|
|
476
477
|
@logger.warn('re-subscribing to results')
|
477
478
|
setup_results
|
478
479
|
end
|
480
|
+
else
|
481
|
+
@logger.warn('reconnecting to rabbitmq')
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
def unsubscribe(&block)
|
487
|
+
if @rabbitmq.connected?
|
488
|
+
@logger.warn('unsubscribing from keepalives')
|
489
|
+
@keepalive_queue.unsubscribe do
|
490
|
+
@logger.warn('unsubscribing from results')
|
491
|
+
@result_queue.unsubscribe do
|
492
|
+
if block
|
493
|
+
block.call
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
else
|
498
|
+
if block
|
499
|
+
block.call
|
479
500
|
end
|
480
501
|
end
|
481
502
|
end
|
482
503
|
|
483
|
-
def
|
504
|
+
def complete_handlers_in_progress(&block)
|
484
505
|
@logger.info('completing handlers in progress', {
|
485
506
|
:handlers_in_progress => @handlers_in_progress
|
486
507
|
})
|
487
|
-
|
508
|
+
complete = EM::tick_loop do
|
488
509
|
if @handlers_in_progress == 0
|
489
510
|
:stop
|
490
511
|
end
|
491
512
|
end
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
EM::stop_event_loop
|
513
|
+
complete.on_stop do
|
514
|
+
if block
|
515
|
+
block.call
|
496
516
|
end
|
497
517
|
end
|
498
518
|
end
|
@@ -505,21 +525,21 @@ module Sensu
|
|
505
525
|
@timers.each do |timer|
|
506
526
|
timer.cancel
|
507
527
|
end
|
508
|
-
|
509
|
-
@logger.warn('unsubscribing from keepalives')
|
510
|
-
@keepalive_queue.unsubscribe do
|
511
|
-
@logger.warn('unsubscribing from results')
|
512
|
-
@result_queue.unsubscribe do
|
513
|
-
resign_as_master do
|
514
|
-
stop_reactor
|
515
|
-
end
|
516
|
-
end
|
517
|
-
end
|
518
|
-
else
|
528
|
+
unsubscribe do
|
519
529
|
resign_as_master do
|
520
|
-
|
530
|
+
complete_handlers_in_progress do
|
531
|
+
@redis.close
|
532
|
+
@logger.warn('stopping reactor')
|
533
|
+
EM::stop_event_loop
|
534
|
+
end
|
521
535
|
end
|
522
536
|
end
|
523
537
|
end
|
538
|
+
|
539
|
+
private
|
540
|
+
|
541
|
+
def testing?
|
542
|
+
File.basename($0) == 'rake'
|
543
|
+
end
|
524
544
|
end
|
525
545
|
end
|
data/lib/sensu/settings.rb
CHANGED
@@ -172,74 +172,108 @@ module Sensu
|
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
+
def invalid(reason, details={})
|
176
|
+
@logger.fatal('invalid settings', {
|
177
|
+
:reason => reason
|
178
|
+
}.merge(details))
|
179
|
+
@logger.fatal('SENSU NOT RUNNING!')
|
180
|
+
exit 2
|
181
|
+
end
|
182
|
+
|
175
183
|
def validate_checks
|
176
184
|
unless @settings[:checks].is_a?(Hash)
|
177
|
-
|
185
|
+
invalid('missing checks configuration')
|
178
186
|
end
|
179
187
|
checks.each do |check|
|
180
188
|
unless check[:interval].is_a?(Integer) && check[:interval] > 0
|
181
|
-
|
189
|
+
invalid('check is missing interval', {
|
190
|
+
:check => check
|
191
|
+
})
|
182
192
|
end
|
183
193
|
unless check[:command].is_a?(String)
|
184
|
-
|
194
|
+
invalid('check is missing command', {
|
195
|
+
:check => check
|
196
|
+
})
|
185
197
|
end
|
186
198
|
unless check[:standalone]
|
187
199
|
unless check[:subscribers].is_a?(Array) && check[:subscribers].count > 0
|
188
|
-
|
200
|
+
invalid('check is missing subscribers', {
|
201
|
+
:check => check
|
202
|
+
})
|
189
203
|
end
|
190
204
|
check[:subscribers].each do |subscriber|
|
191
205
|
unless subscriber.is_a?(String) && !subscriber.empty?
|
192
|
-
|
206
|
+
invalid('check subscribers must each be a string', {
|
207
|
+
:check => check
|
208
|
+
})
|
193
209
|
end
|
194
210
|
end
|
195
211
|
end
|
196
212
|
if check.has_key?(:handler)
|
197
213
|
unless check[:handler].is_a?(String)
|
198
|
-
|
214
|
+
invalid('check handler must be a string', {
|
215
|
+
:check => check
|
216
|
+
})
|
199
217
|
end
|
200
218
|
end
|
201
219
|
if check.has_key?(:handlers)
|
202
220
|
unless check[:handlers].is_a?(Array)
|
203
|
-
|
221
|
+
invalid('check handlers must be an array', {
|
222
|
+
:check => check
|
223
|
+
})
|
204
224
|
end
|
205
225
|
end
|
206
226
|
if check.has_key?(:subdue)
|
207
227
|
unless check[:subdue].is_a?(Hash)
|
208
|
-
|
228
|
+
invalid('check subdue must be a hash', {
|
229
|
+
:check => check
|
230
|
+
})
|
209
231
|
end
|
210
232
|
if check[:subdue].has_key?(:start) || check[:subdue].has_key?(:end)
|
211
233
|
begin
|
212
234
|
Time.parse(check[:subdue][:start])
|
213
235
|
Time.parse(check[:subdue][:end])
|
214
236
|
rescue
|
215
|
-
|
237
|
+
invalid('check subdue start & end times must be valid', {
|
238
|
+
:check => check
|
239
|
+
})
|
216
240
|
end
|
217
241
|
end
|
218
242
|
if check[:subdue].has_key?(:days)
|
219
243
|
unless check[:subdue][:days].is_a?(Array)
|
220
|
-
|
244
|
+
invalid('check subdue days must be an array', {
|
245
|
+
:check => check
|
246
|
+
})
|
221
247
|
end
|
222
248
|
check[:subdue][:days].each do |day|
|
223
249
|
days = %w[sunday monday tuesday wednesday thursday friday saturday]
|
224
250
|
unless day.is_a?(String) && days.include?(day.downcase)
|
225
|
-
|
251
|
+
invalid('check subdue days must be valid days of the week', {
|
252
|
+
:check => check
|
253
|
+
})
|
226
254
|
end
|
227
255
|
end
|
228
256
|
end
|
229
257
|
if check[:subdue].has_key?(:exceptions)
|
230
258
|
unless check[:subdue][:exceptions].is_a?(Array)
|
231
|
-
|
259
|
+
invalid('check subdue exceptions must be an array', {
|
260
|
+
:check => check
|
261
|
+
})
|
232
262
|
end
|
233
263
|
check[:subdue][:exceptions].each do |exception|
|
234
264
|
unless exception.is_a?(Hash)
|
235
|
-
|
265
|
+
invalid('check subdue exceptions must each be a hash', {
|
266
|
+
:check => check
|
267
|
+
})
|
236
268
|
end
|
237
269
|
if exception.has_key?(:start) || exception.has_key?(:end)
|
238
270
|
begin
|
239
271
|
Time.parse(exception[:start])
|
240
272
|
Time.parse(exception[:end])
|
241
273
|
rescue
|
242
|
-
|
274
|
+
invalid('check subdue exception start & end times must be valid', {
|
275
|
+
:check => check
|
276
|
+
})
|
243
277
|
end
|
244
278
|
end
|
245
279
|
end
|
@@ -250,75 +284,89 @@ module Sensu
|
|
250
284
|
|
251
285
|
def validate_client
|
252
286
|
unless @settings[:client].is_a?(Hash)
|
253
|
-
|
287
|
+
invalid('missing client configuration')
|
254
288
|
end
|
255
289
|
unless @settings[:client][:name].is_a?(String)
|
256
|
-
|
290
|
+
invalid('client must have a name')
|
257
291
|
end
|
258
292
|
unless @settings[:client][:address].is_a?(String)
|
259
|
-
|
293
|
+
invalid('client must have an address')
|
260
294
|
end
|
261
295
|
unless @settings[:client][:subscriptions].is_a?(Array) && @settings[:client][:subscriptions].count > 0
|
262
|
-
|
296
|
+
invalid('client must have subscriptions')
|
263
297
|
end
|
264
298
|
@settings[:client][:subscriptions].each do |subscription|
|
265
299
|
unless subscription.is_a?(String) && !subscription.empty?
|
266
|
-
|
300
|
+
invalid('client subscriptions must each be a string')
|
267
301
|
end
|
268
302
|
end
|
269
303
|
end
|
270
304
|
|
271
305
|
def validate_api
|
272
306
|
unless @settings[:api].is_a?(Hash)
|
273
|
-
|
307
|
+
invalid('missing api configuration')
|
274
308
|
end
|
275
309
|
unless @settings[:api][:port].is_a?(Integer)
|
276
|
-
|
310
|
+
invalid('api port must be an integer')
|
277
311
|
end
|
278
312
|
if @settings[:api].has_key?(:user) || @settings[:api].has_key?(:password)
|
279
313
|
unless @settings[:api][:user].is_a?(String)
|
280
|
-
|
314
|
+
invalid('api user must be a string')
|
281
315
|
end
|
282
316
|
unless @settings[:api][:password].is_a?(String)
|
283
|
-
|
317
|
+
invalid('api password must be a string')
|
284
318
|
end
|
285
319
|
end
|
286
320
|
end
|
287
321
|
|
288
322
|
def validate_server
|
289
323
|
unless @settings[:handlers].is_a?(Hash)
|
290
|
-
|
324
|
+
invalid('missing handlers configuration')
|
291
325
|
end
|
292
326
|
unless @settings[:handlers].include?(:default)
|
293
|
-
|
327
|
+
invalid('missing default handler')
|
294
328
|
end
|
295
329
|
handlers.each do |handler|
|
296
330
|
unless handler[:type].is_a?(String)
|
297
|
-
|
331
|
+
invalid('handler is missing type', {
|
332
|
+
:handler => handler
|
333
|
+
})
|
298
334
|
end
|
299
335
|
case handler[:type]
|
300
336
|
when 'pipe'
|
301
337
|
unless handler[:command].is_a?(String)
|
302
|
-
|
338
|
+
invalid('handler is missing command', {
|
339
|
+
:handler => handler
|
340
|
+
})
|
303
341
|
end
|
304
342
|
when 'amqp'
|
305
343
|
unless handler[:exchange].is_a?(Hash)
|
306
|
-
|
344
|
+
invalid('handler is missing exchange hash', {
|
345
|
+
:handler => handler
|
346
|
+
})
|
307
347
|
end
|
308
348
|
unless handler[:exchange][:name].is_a?(String)
|
309
|
-
|
349
|
+
invalid('handler is missing exchange name', {
|
350
|
+
:handler => handler
|
351
|
+
})
|
310
352
|
end
|
311
353
|
if handler[:exchange].has_key?(:type)
|
312
354
|
unless %w[direct fanout topic].include?(handler[:exchange][:type])
|
313
|
-
|
355
|
+
invalid('handler exchange type is invalid', {
|
356
|
+
:handler => handler
|
357
|
+
})
|
314
358
|
end
|
315
359
|
end
|
316
360
|
when 'set'
|
317
361
|
unless handler[:handlers].is_a?(Array) && handler[:handlers].count > 0
|
318
|
-
|
362
|
+
invalid('handler set is missing handlers', {
|
363
|
+
:handler => handler
|
364
|
+
})
|
319
365
|
end
|
320
366
|
else
|
321
|
-
|
367
|
+
invalid('unknown handler type', {
|
368
|
+
:handler => handler
|
369
|
+
})
|
322
370
|
end
|
323
371
|
end
|
324
372
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 62196233
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
9
|
- 6
|
10
10
|
- beta
|
11
|
-
-
|
12
|
-
version: 0.9.6.beta.
|
11
|
+
- 5
|
12
|
+
version: 0.9.6.beta.5
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Sean Porter
|
@@ -18,7 +18,7 @@ autorequire:
|
|
18
18
|
bindir: bin
|
19
19
|
cert_chain: []
|
20
20
|
|
21
|
-
date: 2012-05-
|
21
|
+
date: 2012-05-25 00:00:00 -07:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
@@ -193,10 +193,9 @@ files:
|
|
193
193
|
- lib/sensu/client.rb
|
194
194
|
- lib/sensu/constants.rb
|
195
195
|
- lib/sensu/logger.rb
|
196
|
-
- lib/sensu/patches/amqp.rb
|
197
|
-
- lib/sensu/patches/redis.rb
|
198
196
|
- lib/sensu/patches/ruby.rb
|
199
197
|
- lib/sensu/process.rb
|
198
|
+
- lib/sensu/redis.rb
|
200
199
|
- lib/sensu/server.rb
|
201
200
|
- lib/sensu/settings.rb
|
202
201
|
- lib/sensu/socket.rb
|
data/lib/sensu/patches/amqp.rb
DELETED
data/lib/sensu/patches/redis.rb
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
module Redis
|
2
|
-
class Client
|
3
|
-
attr_accessor :redis_host, :redis_port, :redis_password
|
4
|
-
|
5
|
-
def connection_completed
|
6
|
-
@connected = true
|
7
|
-
@reconnecting = false
|
8
|
-
if @redis_password
|
9
|
-
auth(@redis_password).callback do |reply|
|
10
|
-
unless reply == 'OK'
|
11
|
-
raise('could not authenticate')
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
info.callback do |reply|
|
16
|
-
redis_version = reply.split(/\n/).first.split(/:/).last.chomp
|
17
|
-
if redis_version < '1.3.14'
|
18
|
-
raise('redis version must be >= 2.0 RC 1')
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def close
|
24
|
-
@closing_connection = true
|
25
|
-
close_connection_after_writing
|
26
|
-
end
|
27
|
-
|
28
|
-
def unbind
|
29
|
-
unless !@connected || @closing_connection
|
30
|
-
EM::Timer.new(1) do
|
31
|
-
@reconnecting = true
|
32
|
-
reconnect(@redis_host, @redis_port)
|
33
|
-
end
|
34
|
-
else
|
35
|
-
until @queue.empty?
|
36
|
-
@queue.shift.fail RuntimeError.new('connection closed')
|
37
|
-
end
|
38
|
-
unless @connected
|
39
|
-
raise('could not connect to redis')
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def reconnecting?
|
45
|
-
@reconnecting || false
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.connect(options)
|
50
|
-
options ||= Hash.new
|
51
|
-
if options.is_a?(String)
|
52
|
-
begin
|
53
|
-
uri = URI.parse(options)
|
54
|
-
host = uri.host
|
55
|
-
port = uri.port || 6379
|
56
|
-
password = uri.password
|
57
|
-
rescue
|
58
|
-
raise('invalid redis url')
|
59
|
-
end
|
60
|
-
else
|
61
|
-
host = options[:host] || 'localhost'
|
62
|
-
port = options[:port] || 6379
|
63
|
-
password = options[:password]
|
64
|
-
end
|
65
|
-
EM::connect(host, port, Redis::Client) do |client|
|
66
|
-
client.redis_host = host
|
67
|
-
client.redis_port = port
|
68
|
-
client.redis_password = password
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|