sensu 0.9.3.beta.1 → 0.9.3.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sensu/api.rb +70 -28
- data/lib/sensu/client.rb +10 -3
- data/lib/sensu/config.rb +10 -5
- data/lib/sensu/server.rb +13 -8
- data/lib/sensu.rb +1 -1
- data/sensu.gemspec +3 -2
- metadata +26 -10
data/lib/sensu/api.rb
CHANGED
@@ -54,7 +54,9 @@ module Sensu
|
|
54
54
|
clients.each_with_index do |client, index|
|
55
55
|
$redis.get('client:' + client).callback do |client_json|
|
56
56
|
response.push(JSON.parse(client_json))
|
57
|
-
|
57
|
+
if index == clients.size - 1
|
58
|
+
body response.to_json
|
59
|
+
end
|
58
60
|
end
|
59
61
|
end
|
60
62
|
else
|
@@ -66,7 +68,9 @@ module Sensu
|
|
66
68
|
aget '/client/:name' do |client|
|
67
69
|
$logger.debug('[client] -- ' + request.ip + ' -- GET -- request for client -- ' + client)
|
68
70
|
$redis.get('client:' + client).callback do |client_json|
|
69
|
-
|
71
|
+
if client_json.nil?
|
72
|
+
status 404
|
73
|
+
end
|
70
74
|
body client_json
|
71
75
|
end
|
72
76
|
end
|
@@ -77,6 +81,7 @@ module Sensu
|
|
77
81
|
if client_exists
|
78
82
|
$redis.hgetall('events:' + client).callback do |events|
|
79
83
|
events.keys.each do |check_name|
|
84
|
+
$logger.info('[client] -- publishing check result to resolve event -- ' + client + ' -- ' + check_name)
|
80
85
|
check = {
|
81
86
|
:name => check_name,
|
82
87
|
:issued => Time.now.to_i,
|
@@ -86,7 +91,9 @@ module Sensu
|
|
86
91
|
}
|
87
92
|
$amq.queue('results').publish({:client => client, :check => check}.to_json)
|
88
93
|
end
|
94
|
+
$logger.info('[client] -- client will be deleted -- ' + client)
|
89
95
|
EM::Timer.new(5) do
|
96
|
+
$logger.info('[client] -- deleting client -- ' + client)
|
90
97
|
$redis.srem('clients', client)
|
91
98
|
$redis.del('events:' + client)
|
92
99
|
$redis.del('client:' + client)
|
@@ -119,6 +126,26 @@ module Sensu
|
|
119
126
|
end
|
120
127
|
end
|
121
128
|
|
129
|
+
apost '/check/request' do
|
130
|
+
$logger.debug('[check] -- ' + request.ip + ' -- POST -- request to publish a check request')
|
131
|
+
begin
|
132
|
+
post_body = Hashie::Mash.new(JSON.parse(request.body.read))
|
133
|
+
rescue JSON::ParserError
|
134
|
+
status 400
|
135
|
+
body nil
|
136
|
+
end
|
137
|
+
if post_body.check.is_a?(String) && post_body.subscribers.is_a?(Array)
|
138
|
+
post_body.subscribers.each do |exchange|
|
139
|
+
$logger.info('[check] -- publishing check request -- ' + post_body.check + ' -- ' + exchange)
|
140
|
+
$amq.fanout(exchange).publish({:name => post_body.check, :issued => Time.now.to_i}.to_json)
|
141
|
+
end
|
142
|
+
status 201
|
143
|
+
else
|
144
|
+
status 400
|
145
|
+
end
|
146
|
+
body nil
|
147
|
+
end
|
148
|
+
|
122
149
|
aget '/events' do
|
123
150
|
$logger.debug('[events] -- ' + request.ip + ' -- GET -- request for event list')
|
124
151
|
response = Hash.new
|
@@ -129,8 +156,12 @@ module Sensu
|
|
129
156
|
events.each do |key, value|
|
130
157
|
events[key] = JSON.parse(value)
|
131
158
|
end
|
132
|
-
|
133
|
-
|
159
|
+
unless events.empty?
|
160
|
+
response[client] = events
|
161
|
+
end
|
162
|
+
if index == clients.size - 1
|
163
|
+
body response.to_json
|
164
|
+
end
|
134
165
|
end
|
135
166
|
end
|
136
167
|
else
|
@@ -142,31 +173,34 @@ module Sensu
|
|
142
173
|
aget '/event/:client/:check' do |client, check|
|
143
174
|
$logger.debug('[event] -- ' + request.ip + ' -- GET -- request for event -- ' + client + ' -- ' + check)
|
144
175
|
$redis.hgetall('events:' + client).callback do |events|
|
145
|
-
|
146
|
-
|
147
|
-
|
176
|
+
event_json = events[check]
|
177
|
+
if event_json.nil?
|
178
|
+
status 404
|
179
|
+
end
|
180
|
+
body event_json
|
148
181
|
end
|
149
182
|
end
|
150
183
|
|
151
184
|
apost '/event/resolve' do
|
152
185
|
$logger.debug('[event] -- ' + request.ip + ' -- POST -- request to resolve event')
|
153
186
|
begin
|
154
|
-
|
187
|
+
post_body = Hashie::Mash.new(JSON.parse(request.body.read))
|
155
188
|
rescue JSON::ParserError
|
156
189
|
status 400
|
157
190
|
body nil
|
158
191
|
end
|
159
|
-
if
|
160
|
-
$redis.hgetall('events:' +
|
161
|
-
if events.
|
192
|
+
if post_body.client.is_a?(String) && post_body.check.is_a?(String)
|
193
|
+
$redis.hgetall('events:' + post_body.client).callback do |events|
|
194
|
+
if events.include?(post_body.check)
|
195
|
+
$logger.info('[event] -- publishing check result to resolve event -- ' + post_body.client + ' -- ' + post_body.check)
|
162
196
|
check = {
|
163
|
-
:name =>
|
197
|
+
:name => post_body.check,
|
164
198
|
:issued => Time.now.to_i,
|
165
199
|
:status => 0,
|
166
200
|
:output => 'Resolving on request of the API',
|
167
201
|
:force_resolve => true
|
168
202
|
}
|
169
|
-
$amq.queue('results').publish({:client =>
|
203
|
+
$amq.queue('results').publish({:client => post_body.client, :check => check}.to_json)
|
170
204
|
status 201
|
171
205
|
else
|
172
206
|
status 404
|
@@ -182,12 +216,12 @@ module Sensu
|
|
182
216
|
apost '/stash/*' do |path|
|
183
217
|
$logger.debug('[stash] -- ' + request.ip + ' -- POST -- request for stash -- ' + path)
|
184
218
|
begin
|
185
|
-
|
219
|
+
post_body = JSON.parse(request.body.read)
|
186
220
|
rescue JSON::ParserError
|
187
221
|
status 400
|
188
222
|
body nil
|
189
223
|
end
|
190
|
-
$redis.set('stash:' + path,
|
224
|
+
$redis.set('stash:' + path, post_body.to_json).callback do
|
191
225
|
$redis.sadd('stashes', path).callback do
|
192
226
|
status 201
|
193
227
|
body nil
|
@@ -197,16 +231,18 @@ module Sensu
|
|
197
231
|
|
198
232
|
aget '/stash/*' do |path|
|
199
233
|
$logger.debug('[stash] -- ' + request.ip + ' -- GET -- request for stash -- ' + path)
|
200
|
-
$redis.get('stash:' + path).callback do |
|
201
|
-
|
202
|
-
|
234
|
+
$redis.get('stash:' + path).callback do |stash_json|
|
235
|
+
if stash_json.nil?
|
236
|
+
status 404
|
237
|
+
end
|
238
|
+
body stash_json
|
203
239
|
end
|
204
240
|
end
|
205
241
|
|
206
242
|
adelete '/stash/*' do |path|
|
207
243
|
$logger.debug('[stash] -- ' + request.ip + ' -- DELETE -- request for stash -- ' + path)
|
208
|
-
$redis.exists('stash:' + path).callback do |
|
209
|
-
if
|
244
|
+
$redis.exists('stash:' + path).callback do |stash_exists|
|
245
|
+
if stash_exists
|
210
246
|
$redis.srem('stashes', path).callback do
|
211
247
|
$redis.del('stash:' + path).callback do
|
212
248
|
status 204
|
@@ -230,17 +266,21 @@ module Sensu
|
|
230
266
|
apost '/stashes' do
|
231
267
|
$logger.debug('[stashes] -- ' + request.ip + ' -- POST -- request for multiple stashes')
|
232
268
|
begin
|
233
|
-
|
269
|
+
post_body = JSON.parse(request.body.read)
|
234
270
|
rescue JSON::ParserError
|
235
271
|
status 400
|
236
272
|
body nil
|
237
273
|
end
|
238
274
|
response = Hash.new
|
239
|
-
if
|
240
|
-
|
241
|
-
$redis.get('stash:' + path).callback do |
|
242
|
-
|
243
|
-
|
275
|
+
if post_body.is_a?(Array) && post_body.size > 0
|
276
|
+
post_body.each_with_index do |path, index|
|
277
|
+
$redis.get('stash:' + path).callback do |stash_json|
|
278
|
+
unless stash_json.nil?
|
279
|
+
response[path] = JSON.parse(stash_json)
|
280
|
+
end
|
281
|
+
if index == post_body.size - 1
|
282
|
+
body response.to_json
|
283
|
+
end
|
244
284
|
end
|
245
285
|
end
|
246
286
|
else
|
@@ -249,20 +289,22 @@ module Sensu
|
|
249
289
|
end
|
250
290
|
end
|
251
291
|
|
252
|
-
def self.
|
292
|
+
def self.run_test(options={}, &block)
|
253
293
|
self.setup(options)
|
254
294
|
$settings.client.timestamp = Time.now.to_i
|
255
295
|
$redis.set('client:' + $settings.client.name, $settings.client.to_json).callback do
|
256
296
|
$redis.sadd('clients', $settings.client.name).callback do
|
257
297
|
$redis.hset('events:' + $settings.client.name, 'test', {
|
258
298
|
:status => 2,
|
259
|
-
:output =>
|
299
|
+
:output => "CRITICAL\n",
|
300
|
+
:issued => Time.now.utc.iso8601,
|
260
301
|
:flapping => false,
|
261
302
|
:occurrences => 1
|
262
303
|
}.to_json).callback do
|
263
304
|
$redis.set('stash:test/test', '{"key": "value"}').callback do
|
264
305
|
Thin::Logging.silent = true
|
265
306
|
Thin::Server.start(self, $settings.api.port)
|
307
|
+
block.call
|
266
308
|
end
|
267
309
|
end
|
268
310
|
end
|
data/lib/sensu/client.rb
CHANGED
@@ -10,7 +10,7 @@ module Sensu
|
|
10
10
|
if options[:pid_file]
|
11
11
|
Process.write_pid(options[:pid_file])
|
12
12
|
end
|
13
|
-
EM::threadpool_size =
|
13
|
+
EM::threadpool_size = 14
|
14
14
|
EM::run do
|
15
15
|
client.setup_amqp
|
16
16
|
client.setup_keepalives
|
@@ -86,9 +86,15 @@ module Sensu
|
|
86
86
|
if unmatched_tokens.empty?
|
87
87
|
execute = proc do
|
88
88
|
Bundler.with_clean_env do
|
89
|
-
|
90
|
-
|
89
|
+
started = Time.now.to_f
|
90
|
+
begin
|
91
|
+
IO.popen(command + ' 2>&1') do |io|
|
92
|
+
check.output = io.read
|
93
|
+
end
|
94
|
+
rescue => error
|
95
|
+
check.output = 'unexpected error: ' + error.to_s
|
91
96
|
end
|
97
|
+
check.duration = ('%.3f' % (Time.now.to_f - started)).to_f
|
92
98
|
end
|
93
99
|
check.status = $?.exitstatus
|
94
100
|
end
|
@@ -218,6 +224,7 @@ module Sensu
|
|
218
224
|
validates = %w[name output].all? do |key|
|
219
225
|
check[key].is_a?(String)
|
220
226
|
end
|
227
|
+
check.issued = Time.now.to_i
|
221
228
|
check.status ||= 0
|
222
229
|
if validates && check.status.is_a?(Integer)
|
223
230
|
@logger.info('[socket] -- publishing check result -- ' + [check.name, check.status, check.output].join(' -- '))
|
data/lib/sensu/config.rb
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'patches', 'ruby')
|
2
2
|
|
3
|
-
require 'rubygems'
|
3
|
+
require 'rubygems'
|
4
4
|
require 'bundler'
|
5
5
|
require 'bundler/setup'
|
6
6
|
|
7
7
|
gem 'eventmachine', '~> 1.0.0.beta.4'
|
8
8
|
|
9
9
|
require 'optparse'
|
10
|
+
require 'time'
|
10
11
|
require 'json'
|
11
12
|
require 'hashie'
|
12
13
|
require 'amqp'
|
13
14
|
require 'cabin'
|
14
|
-
require 'cabin/outputs/em
|
15
|
+
require 'cabin/outputs/em/stdlib-logger'
|
16
|
+
|
17
|
+
if ENV['RBTRACE']
|
18
|
+
require 'rbtrace'
|
19
|
+
end
|
15
20
|
|
16
21
|
module Sensu
|
17
22
|
class Config
|
@@ -44,7 +49,7 @@ module Sensu
|
|
44
49
|
end
|
45
50
|
@logger = Cabin::Channel.new
|
46
51
|
log_output = File.basename($0) == 'rake' ? '/tmp/sensu_test.log' : STDOUT
|
47
|
-
@logger.subscribe(Cabin::Outputs::
|
52
|
+
@logger.subscribe(Cabin::Outputs::EM::StdlibLogger.new(Logger.new(log_output)))
|
48
53
|
@logger.level = @options[:verbose] ? :debug : :info
|
49
54
|
if Signal.list.include?('USR1')
|
50
55
|
Signal.trap('USR1') do
|
@@ -93,7 +98,7 @@ module Sensu
|
|
93
98
|
unless details['type'].is_a?(String)
|
94
99
|
invalid_config('missing type for handler ' + name)
|
95
100
|
end
|
96
|
-
case details
|
101
|
+
case details.type
|
97
102
|
when 'pipe'
|
98
103
|
unless details.command.is_a?(String)
|
99
104
|
invalid_config('missing command for pipe handler ' + name)
|
@@ -176,7 +181,7 @@ module Sensu
|
|
176
181
|
invalid_config('configuration snippet file (' + snippet_file + ') must be valid JSON: ' + error.to_s)
|
177
182
|
end
|
178
183
|
merged_settings = @settings.to_hash.deep_merge(snippet_hash)
|
179
|
-
@logger.warn('[settings] configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json)
|
184
|
+
@logger.warn('[settings] -- configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json)
|
180
185
|
@settings = Hashie::Mash.new(merged_settings)
|
181
186
|
else
|
182
187
|
invalid_config('configuration snippet file is not readable: ' + snippet_file)
|
data/lib/sensu/server.rb
CHANGED
@@ -16,7 +16,7 @@ module Sensu
|
|
16
16
|
if options[:pid_file]
|
17
17
|
Process.write_pid(options[:pid_file])
|
18
18
|
end
|
19
|
-
EM::threadpool_size =
|
19
|
+
EM::threadpool_size = 14
|
20
20
|
EM::run do
|
21
21
|
server.setup_redis
|
22
22
|
server.setup_amqp
|
@@ -74,7 +74,7 @@ module Sensu
|
|
74
74
|
['default']
|
75
75
|
end
|
76
76
|
handlers.map! do |handler|
|
77
|
-
@settings.handlers[handler]
|
77
|
+
@settings.handlers[handler].type == 'set' ? @settings.handlers[handler].handlers : handler
|
78
78
|
end
|
79
79
|
handlers.flatten!
|
80
80
|
handlers.uniq!
|
@@ -89,7 +89,7 @@ module Sensu
|
|
89
89
|
@logger.debug('[event] -- handling event -- ' + [handler, event.client.name, event.check.name].join(' -- '))
|
90
90
|
@handlers_in_progress += 1
|
91
91
|
details = @settings.handlers[handler]
|
92
|
-
case details
|
92
|
+
case details.type
|
93
93
|
when 'pipe'
|
94
94
|
execute = proc do
|
95
95
|
Bundler.with_clean_env do
|
@@ -99,15 +99,19 @@ module Sensu
|
|
99
99
|
io.close_write
|
100
100
|
io.read
|
101
101
|
end
|
102
|
+
rescue Errno::ENOENT => error
|
103
|
+
handler + ' -- does not exist: ' + error.to_s
|
102
104
|
rescue Errno::EPIPE => error
|
103
105
|
handler + ' -- broken pipe: ' + error.to_s
|
106
|
+
rescue => error
|
107
|
+
handler + ' -- unexpected error: ' + error.to_s
|
104
108
|
end
|
105
109
|
end
|
106
110
|
end
|
107
111
|
EM::defer(execute, report)
|
108
112
|
when 'amqp'
|
109
113
|
exchange = details.exchange.name
|
110
|
-
exchange_type = details.exchange.key?('type') ? details.exchange
|
114
|
+
exchange_type = details.exchange.key?('type') ? details.exchange.type.to_sym : :direct
|
111
115
|
exchange_options = details.exchange.reject { |key, value| %w[name type].include?(key) }
|
112
116
|
@logger.debug('[event] -- publishing event to rabbitmq exchange -- ' + [exchange, event.client.name, event.check.name].join(' -- '))
|
113
117
|
payload = details.send_only_check_output ? event.check.output : event.to_json
|
@@ -174,10 +178,11 @@ module Sensu
|
|
174
178
|
@redis.hset('events:' + client.name, check.name, {
|
175
179
|
:status => check.status,
|
176
180
|
:output => check.output,
|
181
|
+
:issued => Time.at(check.issued).utc.iso8601,
|
177
182
|
:flapping => is_flapping,
|
178
183
|
:occurrences => event.occurrences
|
179
184
|
}.to_json).callback do
|
180
|
-
unless check.
|
185
|
+
unless check.handle == false
|
181
186
|
event.check.flapping = is_flapping
|
182
187
|
event.action = 'create'
|
183
188
|
handle_event(event)
|
@@ -189,7 +194,7 @@ module Sensu
|
|
189
194
|
unless is_flapping
|
190
195
|
unless check.auto_resolve == false && !check.force_resolve
|
191
196
|
@redis.hdel('events:' + client.name, check.name).callback do
|
192
|
-
unless check.
|
197
|
+
unless check.handle == false
|
193
198
|
event.action = 'resolve'
|
194
199
|
handle_event(event)
|
195
200
|
else
|
@@ -200,13 +205,13 @@ module Sensu
|
|
200
205
|
else
|
201
206
|
@logger.debug('[result] -- check is flapping -- ' + [client.name, check.name, check.status].join(' -- '))
|
202
207
|
@redis.hset('events:' + client.name, check.name, previous_occurrence.merge(:flapping => true).to_json).callback do
|
203
|
-
if check
|
208
|
+
if check.type == 'metric'
|
204
209
|
event.check.flapping = is_flapping
|
205
210
|
handle_event(event)
|
206
211
|
end
|
207
212
|
end
|
208
213
|
end
|
209
|
-
elsif check
|
214
|
+
elsif check.type == 'metric'
|
210
215
|
handle_event(event)
|
211
216
|
end
|
212
217
|
end
|
data/lib/sensu.rb
CHANGED
data/sensu.gemspec
CHANGED
@@ -16,8 +16,8 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.add_dependency("eventmachine", "~> 1.0.0.beta.4")
|
17
17
|
s.add_dependency("amqp", "0.7.4")
|
18
18
|
s.add_dependency("json")
|
19
|
-
s.add_dependency("hashie")
|
20
|
-
s.add_dependency("cabin", "0.1.
|
19
|
+
s.add_dependency("hashie", "~> 1.2.0")
|
20
|
+
s.add_dependency("cabin", "0.1.8")
|
21
21
|
s.add_dependency("ruby-redis")
|
22
22
|
s.add_dependency("rack", "~> 1.3.4")
|
23
23
|
s.add_dependency("async_sinatra")
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_development_dependency("rake")
|
27
27
|
s.add_development_dependency("em-spec")
|
28
28
|
s.add_development_dependency("em-http-request")
|
29
|
+
s.add_development_dependency("rbtrace")
|
29
30
|
|
30
31
|
s.files = Dir.glob("{bin,lib}/**/*") + %w[sensu.gemspec README.org MIT-LICENSE.txt]
|
31
32
|
s.executables = Dir.glob("bin/**/*").map { |file| File.basename(file) }
|
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: 62196271
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
9
|
- 3
|
10
10
|
- beta
|
11
|
-
-
|
12
|
-
version: 0.9.3.beta.
|
11
|
+
- 2
|
12
|
+
version: 0.9.3.beta.2
|
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-01-
|
21
|
+
date: 2012-01-17 00:00:00 -08:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
@@ -89,12 +89,14 @@ dependencies:
|
|
89
89
|
requirement: &id005 !ruby/object:Gem::Requirement
|
90
90
|
none: false
|
91
91
|
requirements:
|
92
|
-
- -
|
92
|
+
- - ~>
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
hash:
|
94
|
+
hash: 31
|
95
95
|
segments:
|
96
|
+
- 1
|
97
|
+
- 2
|
96
98
|
- 0
|
97
|
-
version:
|
99
|
+
version: 1.2.0
|
98
100
|
type: :runtime
|
99
101
|
version_requirements: *id005
|
100
102
|
- !ruby/object:Gem::Dependency
|
@@ -105,12 +107,12 @@ dependencies:
|
|
105
107
|
requirements:
|
106
108
|
- - "="
|
107
109
|
- !ruby/object:Gem::Version
|
108
|
-
hash:
|
110
|
+
hash: 11
|
109
111
|
segments:
|
110
112
|
- 0
|
111
113
|
- 1
|
112
|
-
-
|
113
|
-
version: 0.1.
|
114
|
+
- 8
|
115
|
+
version: 0.1.8
|
114
116
|
type: :runtime
|
115
117
|
version_requirements: *id006
|
116
118
|
- !ruby/object:Gem::Dependency
|
@@ -213,6 +215,20 @@ dependencies:
|
|
213
215
|
version: "0"
|
214
216
|
type: :development
|
215
217
|
version_requirements: *id013
|
218
|
+
- !ruby/object:Gem::Dependency
|
219
|
+
name: rbtrace
|
220
|
+
prerelease: false
|
221
|
+
requirement: &id014 !ruby/object:Gem::Requirement
|
222
|
+
none: false
|
223
|
+
requirements:
|
224
|
+
- - ">="
|
225
|
+
- !ruby/object:Gem::Version
|
226
|
+
hash: 3
|
227
|
+
segments:
|
228
|
+
- 0
|
229
|
+
version: "0"
|
230
|
+
type: :development
|
231
|
+
version_requirements: *id014
|
216
232
|
description: A monitoring framework that aims to be simple, malleable, and scalable. Uses the publish/subscribe model.
|
217
233
|
email:
|
218
234
|
- sean.porter@sonian.net
|