sensu 0.9.3.beta.1 → 0.9.3.beta.2
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/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
|