sensu 0.9.5 → 0.9.6.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/README.org +8 -42
- data/bin/sensu-api +5 -2
- data/bin/sensu-client +5 -2
- data/bin/sensu-server +5 -2
- data/lib/sensu/api.rb +125 -95
- data/lib/sensu/base.rb +57 -0
- data/lib/sensu/cli.rb +37 -0
- data/lib/sensu/client.rb +126 -129
- data/lib/sensu/constants.rb +8 -0
- data/lib/sensu/logger.rb +39 -0
- data/lib/sensu/patches/ruby.rb +4 -80
- data/lib/sensu/process.rb +57 -0
- data/lib/sensu/server.rb +229 -163
- data/lib/sensu/settings.rb +280 -0
- data/lib/sensu/socket.rb +52 -0
- data/sensu.gemspec +22 -23
- metadata +171 -185
- data/lib/sensu/config.rb +0 -266
- data/lib/sensu/version.rb +0 -3
data/README.org
CHANGED
@@ -1,46 +1,12 @@
|
|
1
|
-
*
|
2
|
-
|
1
|
+
* Sensu
|
2
|
+
A monitoring framework that aims to be simple, malleable, and scalable.
|
3
3
|
|
4
|
-
[[https://github.com/
|
4
|
+
[[https://github.com/sensu/sensu/raw/master/sensu-logo.png]]
|
5
5
|
|
6
|
-
[[
|
6
|
+
[[https://secure.travis-ci.org/sensu/sensu.png]]
|
7
7
|
|
8
|
-
[[
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
- [[http://joemiller.me/2012/01/24/re-use-nagios-plugins-in-sensu-for-quick-profit/][How to reuse your existing Nagios plugins]]
|
13
|
-
- [[http://joemiller.me/2012/02/02/sensu-and-graphite/][Sensu and Graphite]]
|
14
|
-
* Other Projects
|
15
|
-
- [[https://github.com/sonian/sensu-community-plugins][Sensu Community Plugins]]
|
16
|
-
- [[https://github.com/sonian/sensu-dashboard][Sensu Dashboard]]
|
17
|
-
- [[https://github.com/sonian/sensu-plugin][Sensu Plugin & Handler Helper]]
|
18
|
-
* License
|
8
|
+
[[https://gemnasium.com/portertech/sensu.png]]
|
9
|
+
** Documentation
|
10
|
+
Please refer to the [[https://github.com/sensu/sensu/wiki][Sensu Wiki]].
|
11
|
+
** License
|
19
12
|
Sensu is released under the [[https://github.com/sonian/sensu/blob/master/MIT-LICENSE.txt][MIT license]].
|
20
|
-
* Contributing
|
21
|
-
- [[http://help.github.com/fork-a-repo/][Fork]] Sensu
|
22
|
-
- Use a [[https://github.com/dchelimsky/rspec/wiki/Topic-Branches][topic branch]]
|
23
|
-
- Create a [[http://help.github.com/send-pull-requests/][pull request]]
|
24
|
-
|
25
|
-
Keep it simple.
|
26
|
-
** Testing
|
27
|
-
*** Travis CI
|
28
|
-
[[https://secure.travis-ci.org/sonian/sensu.png]]
|
29
|
-
*** System Dependencies
|
30
|
-
- Ruby (MRI) & Rubygems
|
31
|
-
- RabbitMQ
|
32
|
-
- Redis
|
33
|
-
*** Running
|
34
|
-
: bundle install
|
35
|
-
: rake
|
36
|
-
* Contributors
|
37
|
-
- [[http://twitter.com/portertech][Sean Porter]]
|
38
|
-
- [[http://twitter.com/amdprophet][Justin Kolberg]]
|
39
|
-
- [[http://twitter.com/kartar][James Turnbull]]
|
40
|
-
- [[http://twitter.com/joshpasqualetto][Josh Pasqualetto]]
|
41
|
-
- [[http://github.com/lum][Steve Lum]]
|
42
|
-
- [[http://twitter.com/miller_joe][Joe Miller]]
|
43
|
-
- [[http://twitter.com/decklin][Decklin Foster]]
|
44
|
-
- [[http://twitter.com/ohlol][Scott Smith]]
|
45
|
-
- [[http://twitter.com/webframp][Sean Escriva]]
|
46
|
-
- [[http://twitter.com/fujin_][AJ Christensen]]
|
data/bin/sensu-api
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
5
|
+
end
|
6
|
+
|
4
7
|
require 'sensu/api'
|
5
8
|
|
6
|
-
options = Sensu::
|
9
|
+
options = Sensu::CLI.read
|
7
10
|
Sensu::API.run(options)
|
data/bin/sensu-client
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
5
|
+
end
|
6
|
+
|
4
7
|
require 'sensu/client'
|
5
8
|
|
6
|
-
options = Sensu::
|
9
|
+
options = Sensu::CLI.read
|
7
10
|
Sensu::Client.run(options)
|
data/bin/sensu-server
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
unless $:.include?(File.dirname(__FILE__) + '/../lib/')
|
4
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
5
|
+
end
|
6
|
+
|
4
7
|
require 'sensu/server'
|
5
8
|
|
6
|
-
options = Sensu::
|
9
|
+
options = Sensu::CLI.read
|
7
10
|
Sensu::Server.run(options)
|
data/lib/sensu/api.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '
|
1
|
+
require File.join(File.dirname(__FILE__), 'base')
|
2
2
|
|
3
3
|
require 'thin'
|
4
4
|
require 'sinatra/async'
|
@@ -15,7 +15,7 @@ module Sensu
|
|
15
15
|
self.setup(options)
|
16
16
|
|
17
17
|
Thin::Logging.silent = true
|
18
|
-
Thin::Server.start(self, $settings
|
18
|
+
Thin::Server.start(self, $settings[:api][:port])
|
19
19
|
|
20
20
|
%w[INT TERM].each do |signal|
|
21
21
|
Signal.trap(signal) do
|
@@ -26,27 +26,36 @@ module Sensu
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.setup(options={})
|
29
|
-
|
30
|
-
$logger =
|
31
|
-
$settings =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
$
|
40
|
-
$logger.debug('[setup] -- connecting to rabbitmq')
|
41
|
-
$rabbitmq = AMQP.connect($settings.rabbitmq.to_hash.symbolize_keys)
|
29
|
+
base = Sensu::Base.new(options)
|
30
|
+
$logger = base.logger
|
31
|
+
$settings = base.settings
|
32
|
+
$logger.debug('connecting to redis', {
|
33
|
+
:settings => $settings[:redis]
|
34
|
+
})
|
35
|
+
$redis = Redis.connect($settings[:redis])
|
36
|
+
$logger.debug('connecting to rabbitmq', {
|
37
|
+
:settings => $settings[:rabbitmq]
|
38
|
+
})
|
39
|
+
$rabbitmq = AMQP.connect($settings[:rabbitmq])
|
42
40
|
$amq = AMQP::Channel.new($rabbitmq)
|
43
|
-
if $settings
|
41
|
+
if $settings[:api][:user] && $settings[:api][:password]
|
44
42
|
use Rack::Auth::Basic do |user, password|
|
45
|
-
user == $settings
|
43
|
+
user == $settings[:api][:user] && password == $settings[:api][:password]
|
46
44
|
end
|
47
45
|
end
|
48
46
|
end
|
49
47
|
|
48
|
+
def request_log(env)
|
49
|
+
$logger.info([env['REQUEST_METHOD'], env['REQUEST_PATH']].join(' '), {
|
50
|
+
:remote_address => env['REMOTE_ADDR'],
|
51
|
+
:user_agent => env['HTTP_USER_AGENT'],
|
52
|
+
:request_method => env['REQUEST_METHOD'],
|
53
|
+
:request_uri => env['REQUEST_URI'],
|
54
|
+
:request_body => env['rack.input'].read
|
55
|
+
})
|
56
|
+
env['rack.input'].rewind
|
57
|
+
end
|
58
|
+
|
50
59
|
configure do
|
51
60
|
disable :protection
|
52
61
|
end
|
@@ -60,10 +69,10 @@ module Sensu
|
|
60
69
|
end
|
61
70
|
|
62
71
|
aget '/info' do
|
63
|
-
|
72
|
+
request_log(env)
|
64
73
|
response = {
|
65
74
|
:sensu => {
|
66
|
-
:version =>
|
75
|
+
:version => VERSION
|
67
76
|
},
|
68
77
|
:health => {
|
69
78
|
:redis => 'ok',
|
@@ -80,12 +89,12 @@ module Sensu
|
|
80
89
|
end
|
81
90
|
|
82
91
|
aget '/clients' do
|
83
|
-
|
92
|
+
request_log(env)
|
84
93
|
response = Array.new
|
85
94
|
$redis.smembers('clients').callback do |clients|
|
86
95
|
unless clients.empty?
|
87
|
-
clients.each_with_index do |
|
88
|
-
$redis.get('client:' +
|
96
|
+
clients.each_with_index do |client_name, index|
|
97
|
+
$redis.get('client:' + client_name).callback do |client_json|
|
89
98
|
response.push(JSON.parse(client_json))
|
90
99
|
if index == clients.size - 1
|
91
100
|
body response.to_json
|
@@ -98,9 +107,9 @@ module Sensu
|
|
98
107
|
end
|
99
108
|
end
|
100
109
|
|
101
|
-
aget '/client/:name' do |
|
102
|
-
|
103
|
-
$redis.get('client:' +
|
110
|
+
aget '/client/:name' do |client_name|
|
111
|
+
request_log(env)
|
112
|
+
$redis.get('client:' + client_name).callback do |client_json|
|
104
113
|
unless client_json.nil?
|
105
114
|
body client_json
|
106
115
|
else
|
@@ -110,30 +119,37 @@ module Sensu
|
|
110
119
|
end
|
111
120
|
end
|
112
121
|
|
113
|
-
adelete '/client/:name' do |
|
114
|
-
|
115
|
-
$redis.
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
:
|
125
|
-
:
|
122
|
+
adelete '/client/:name' do |client_name|
|
123
|
+
request_log(env)
|
124
|
+
$redis.get('client:' + client_name).callback do |client_json|
|
125
|
+
unless client_json.nil?
|
126
|
+
client = JSON.parse(client_json, :symbolize_names => true)
|
127
|
+
$logger.info('deleting client', {
|
128
|
+
:client => client
|
129
|
+
})
|
130
|
+
$redis.hgetall('events:' + client_name).callback do |events|
|
131
|
+
events.each_key do |check_name|
|
132
|
+
payload = {
|
133
|
+
:client => client_name,
|
134
|
+
:check => {
|
135
|
+
:name => check_name,
|
136
|
+
:output => 'Client is being removed on request of the API',
|
137
|
+
:status => 0,
|
138
|
+
:issued => Time.now.to_i,
|
139
|
+
:force_resolve => true
|
140
|
+
}
|
126
141
|
}
|
127
|
-
$
|
142
|
+
$logger.info('publishing check result', {
|
143
|
+
:payload => payload
|
144
|
+
})
|
145
|
+
$amq.queue('results').publish(payload.to_json)
|
128
146
|
end
|
129
|
-
$logger.info('[client] -- client will be deleted -- ' + client)
|
130
147
|
EM::Timer.new(5) do
|
131
|
-
$
|
132
|
-
$redis.
|
133
|
-
$redis.del('
|
134
|
-
$
|
135
|
-
|
136
|
-
$redis.del('history:' + client + ':' + check_name)
|
148
|
+
$redis.srem('clients', client_name)
|
149
|
+
$redis.del('events:' + client_name)
|
150
|
+
$redis.del('client:' + client_name)
|
151
|
+
$settings[:checks].each_key do |check_name|
|
152
|
+
$redis.del('history:' + client_name + ':' + check_name)
|
137
153
|
end
|
138
154
|
end
|
139
155
|
status 204
|
@@ -147,15 +163,14 @@ module Sensu
|
|
147
163
|
end
|
148
164
|
|
149
165
|
aget '/checks' do
|
150
|
-
|
151
|
-
|
152
|
-
body response.to_json
|
166
|
+
request_log(env)
|
167
|
+
body $settings.checks.to_json
|
153
168
|
end
|
154
169
|
|
155
|
-
aget '/check/:name' do |
|
156
|
-
|
157
|
-
if $settings.
|
158
|
-
response = $settings
|
170
|
+
aget '/check/:name' do |check_name|
|
171
|
+
request_log(env)
|
172
|
+
if $settings.check_exists?(check_name)
|
173
|
+
response = $settings[:checks][check_name].merge(:name => check_name)
|
159
174
|
body response.to_json
|
160
175
|
else
|
161
176
|
status 404
|
@@ -164,17 +179,24 @@ module Sensu
|
|
164
179
|
end
|
165
180
|
|
166
181
|
apost '/check/request' do
|
167
|
-
|
182
|
+
request_log(env)
|
168
183
|
begin
|
169
|
-
post_body =
|
184
|
+
post_body = JSON.parse(request.body.read, :symbolize_names => true)
|
170
185
|
rescue JSON::ParserError
|
171
186
|
status 400
|
172
187
|
body ''
|
173
188
|
end
|
174
|
-
if post_body
|
175
|
-
|
176
|
-
|
177
|
-
|
189
|
+
if post_body[:check].is_a?(String) && post_body[:subscribers].is_a?(Array)
|
190
|
+
payload = {
|
191
|
+
:name => post_body[:check],
|
192
|
+
:issued => Time.now.to_i
|
193
|
+
}
|
194
|
+
$logger.info('publishing check request', {
|
195
|
+
:payload => payload,
|
196
|
+
:subscribers => post_body[:subscribers]
|
197
|
+
})
|
198
|
+
post_body[:subscribers].uniq.each do |exchange_name|
|
199
|
+
$amq.fanout(exchange_name).publish(payload.to_json)
|
178
200
|
end
|
179
201
|
status 201
|
180
202
|
else
|
@@ -184,14 +206,14 @@ module Sensu
|
|
184
206
|
end
|
185
207
|
|
186
208
|
aget '/events' do
|
187
|
-
|
209
|
+
request_log(env)
|
188
210
|
response = Array.new
|
189
211
|
$redis.smembers('clients').callback do |clients|
|
190
212
|
unless clients.empty?
|
191
|
-
clients.each_with_index do |
|
192
|
-
$redis.hgetall('events:' +
|
193
|
-
events.each do |
|
194
|
-
response.push(JSON.parse(
|
213
|
+
clients.each_with_index do |client_name, index|
|
214
|
+
$redis.hgetall('events:' + client_name).callback do |events|
|
215
|
+
events.each do |check_name, event_json|
|
216
|
+
response.push(JSON.parse(event_json).merge(:client => client_name, :check => check_name))
|
195
217
|
end
|
196
218
|
if index == clients.size - 1
|
197
219
|
body response.to_json
|
@@ -204,12 +226,12 @@ module Sensu
|
|
204
226
|
end
|
205
227
|
end
|
206
228
|
|
207
|
-
aget '/event/:client/:check' do |
|
208
|
-
|
209
|
-
$redis.hgetall('events:' +
|
210
|
-
event_json = events[
|
229
|
+
aget '/event/:client/:check' do |client_name, check_name|
|
230
|
+
request_log(env)
|
231
|
+
$redis.hgetall('events:' + client_name).callback do |events|
|
232
|
+
event_json = events[check_name]
|
211
233
|
unless event_json.nil?
|
212
|
-
response = JSON.parse(event_json).merge(:client =>
|
234
|
+
response = JSON.parse(event_json).merge(:client => client_name, :check => check_name)
|
213
235
|
body response.to_json
|
214
236
|
else
|
215
237
|
status 404
|
@@ -219,25 +241,30 @@ module Sensu
|
|
219
241
|
end
|
220
242
|
|
221
243
|
apost '/event/resolve' do
|
222
|
-
|
244
|
+
request_log(env)
|
223
245
|
begin
|
224
|
-
post_body =
|
246
|
+
post_body = JSON.parse(request.body.read, :symbolize_names => true)
|
225
247
|
rescue JSON::ParserError
|
226
248
|
status 400
|
227
249
|
body ''
|
228
250
|
end
|
229
|
-
if post_body
|
230
|
-
$redis.hgetall('events:' + post_body
|
231
|
-
if events.include?(post_body
|
232
|
-
|
233
|
-
|
234
|
-
:
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
251
|
+
if post_body[:client].is_a?(String) && post_body[:check].is_a?(String)
|
252
|
+
$redis.hgetall('events:' + post_body[:client]).callback do |events|
|
253
|
+
if events.include?(post_body[:check])
|
254
|
+
payload = {
|
255
|
+
:client => post_body[:client],
|
256
|
+
:check => {
|
257
|
+
:name => post_body[:check],
|
258
|
+
:output => 'Resolving on request of the API',
|
259
|
+
:status => 0,
|
260
|
+
:issued => Time.now.to_i,
|
261
|
+
:force_resolve => true
|
262
|
+
}
|
239
263
|
}
|
240
|
-
$
|
264
|
+
$logger.info('publishing check result', {
|
265
|
+
:payload => payload
|
266
|
+
})
|
267
|
+
$amq.queue('results').publish(payload.to_json)
|
241
268
|
status 201
|
242
269
|
else
|
243
270
|
status 404
|
@@ -251,7 +278,7 @@ module Sensu
|
|
251
278
|
end
|
252
279
|
|
253
280
|
apost '/stash/*' do |path|
|
254
|
-
|
281
|
+
request_log(env)
|
255
282
|
begin
|
256
283
|
post_body = JSON.parse(request.body.read)
|
257
284
|
rescue JSON::ParserError
|
@@ -267,7 +294,7 @@ module Sensu
|
|
267
294
|
end
|
268
295
|
|
269
296
|
aget '/stash/*' do |path|
|
270
|
-
|
297
|
+
request_log(env)
|
271
298
|
$redis.get('stash:' + path).callback do |stash_json|
|
272
299
|
if stash_json.nil?
|
273
300
|
status 404
|
@@ -279,7 +306,7 @@ module Sensu
|
|
279
306
|
end
|
280
307
|
|
281
308
|
adelete '/stash/*' do |path|
|
282
|
-
|
309
|
+
request_log(env)
|
283
310
|
$redis.exists('stash:' + path).callback do |stash_exists|
|
284
311
|
if stash_exists
|
285
312
|
$redis.srem('stashes', path).callback do
|
@@ -296,14 +323,14 @@ module Sensu
|
|
296
323
|
end
|
297
324
|
|
298
325
|
aget '/stashes' do
|
299
|
-
|
326
|
+
request_log(env)
|
300
327
|
$redis.smembers('stashes') do |stashes|
|
301
328
|
body stashes.to_json
|
302
329
|
end
|
303
330
|
end
|
304
331
|
|
305
332
|
apost '/stashes' do
|
306
|
-
|
333
|
+
request_log(env)
|
307
334
|
begin
|
308
335
|
post_body = JSON.parse(request.body.read)
|
309
336
|
rescue JSON::ParserError
|
@@ -330,20 +357,20 @@ module Sensu
|
|
330
357
|
|
331
358
|
def self.run_test(options={}, &block)
|
332
359
|
self.setup(options)
|
333
|
-
$settings
|
334
|
-
$redis.set('client:' + $settings
|
335
|
-
$redis.sadd('clients', $settings
|
336
|
-
$redis.hset('events:' + $settings
|
360
|
+
$settings[:client][:timestamp] = Time.now.to_i
|
361
|
+
$redis.set('client:' + $settings[:client][:name], $settings[:client].to_json).callback do
|
362
|
+
$redis.sadd('clients', $settings[:client][:name]).callback do
|
363
|
+
$redis.hset('events:' + $settings[:client][:name], 'test', {
|
337
364
|
:output => "CRITICAL\n",
|
338
365
|
:status => 2,
|
339
|
-
:issued => Time.now.
|
366
|
+
:issued => Time.now.to_i,
|
340
367
|
:flapping => false,
|
341
368
|
:occurrences => 1
|
342
369
|
}.to_json).callback do
|
343
370
|
$redis.set('stash:test/test', '{"key": "value"}').callback do
|
344
371
|
$redis.sadd('stashes', 'test/test').callback do
|
345
372
|
Thin::Logging.silent = true
|
346
|
-
Thin::Server.start(self, $settings
|
373
|
+
Thin::Server.start(self, $settings[:api][:port])
|
347
374
|
block.call
|
348
375
|
end
|
349
376
|
end
|
@@ -353,8 +380,11 @@ module Sensu
|
|
353
380
|
end
|
354
381
|
|
355
382
|
def self.stop(signal)
|
356
|
-
$logger.warn('
|
357
|
-
|
383
|
+
$logger.warn('received signal', {
|
384
|
+
:signal => signal
|
385
|
+
})
|
386
|
+
$logger.warn('stopping')
|
387
|
+
$logger.warn('stopping reactor')
|
358
388
|
EM::PeriodicTimer.new(0.25) do
|
359
389
|
EM::stop_event_loop
|
360
390
|
end
|