sensu 0.13.0.alpha.2-java
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +455 -0
- data/MIT-LICENSE.txt +20 -0
- data/README.md +11 -0
- data/bin/sensu-api +10 -0
- data/bin/sensu-client +10 -0
- data/bin/sensu-server +10 -0
- data/lib/sensu.rb +3 -0
- data/lib/sensu/api.rb +674 -0
- data/lib/sensu/cli.rb +51 -0
- data/lib/sensu/client.rb +261 -0
- data/lib/sensu/constants.rb +9 -0
- data/lib/sensu/daemon.rb +221 -0
- data/lib/sensu/redis.rb +20 -0
- data/lib/sensu/sandbox.rb +11 -0
- data/lib/sensu/server.rb +764 -0
- data/lib/sensu/socket.rb +79 -0
- data/lib/sensu/utilities.rb +60 -0
- data/sensu.gemspec +38 -0
- metadata +277 -0
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Sonian Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+

|
2
|
+
|
3
|
+
A monitoring framework that aims to be simple, malleable, and scalable.
|
4
|
+
|
5
|
+
[](https://travis-ci.org/sensu/sensu)
|
6
|
+
|
7
|
+
## Documentation
|
8
|
+
Please refer to the [Sensu Docs](http://docs.sensuapp.org/).
|
9
|
+
|
10
|
+
## License
|
11
|
+
Sensu is released under the [MIT license](https://raw.github.com/sensu/sensu/master/MIT-LICENSE.txt).
|
data/bin/sensu-api
ADDED
data/bin/sensu-client
ADDED
data/bin/sensu-server
ADDED
data/lib/sensu.rb
ADDED
data/lib/sensu/api.rb
ADDED
@@ -0,0 +1,674 @@
|
|
1
|
+
require 'sensu/daemon'
|
2
|
+
|
3
|
+
gem 'sinatra', '1.3.5'
|
4
|
+
gem 'async_sinatra', '1.0.0'
|
5
|
+
|
6
|
+
unless RUBY_PLATFORM =~ /java/
|
7
|
+
gem 'thin', '1.5.0'
|
8
|
+
require 'thin'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'sinatra/async'
|
12
|
+
|
13
|
+
module Sensu
|
14
|
+
class API < Sinatra::Base
|
15
|
+
register Sinatra::Async
|
16
|
+
|
17
|
+
class << self
|
18
|
+
include Daemon
|
19
|
+
|
20
|
+
def run(options={})
|
21
|
+
bootstrap(options)
|
22
|
+
setup_process(options)
|
23
|
+
EM::run do
|
24
|
+
start
|
25
|
+
setup_signal_traps
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_reactor_run
|
30
|
+
EM::next_tick do
|
31
|
+
setup_redis
|
32
|
+
set :redis, @redis
|
33
|
+
setup_transport
|
34
|
+
set :transport, @transport
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def bootstrap(options)
|
39
|
+
setup_logger(options)
|
40
|
+
set :logger, @logger
|
41
|
+
load_settings(options)
|
42
|
+
set :checks, @settings[:checks]
|
43
|
+
set :all_checks, @settings.checks
|
44
|
+
if @settings[:api][:user] && @settings[:api][:password]
|
45
|
+
use Rack::Auth::Basic do |user, password|
|
46
|
+
user == @settings[:api][:user] && password == @settings[:api][:password]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
on_reactor_run
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_server
|
54
|
+
Thin::Logging.silent = true
|
55
|
+
bind = @settings[:api][:bind] || '0.0.0.0'
|
56
|
+
@thin = Thin::Server.new(bind, @settings[:api][:port], self)
|
57
|
+
@thin.start
|
58
|
+
end
|
59
|
+
|
60
|
+
def stop_server(&block)
|
61
|
+
@thin.stop
|
62
|
+
retry_until_true do
|
63
|
+
unless @thin.running?
|
64
|
+
block.call
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def start
|
71
|
+
start_server
|
72
|
+
super
|
73
|
+
end
|
74
|
+
|
75
|
+
def stop
|
76
|
+
@logger.warn('stopping')
|
77
|
+
stop_server do
|
78
|
+
@redis.close
|
79
|
+
@transport.close
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test(options={})
|
85
|
+
bootstrap(options)
|
86
|
+
start
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
configure do
|
91
|
+
disable :protection
|
92
|
+
disable :show_exceptions
|
93
|
+
end
|
94
|
+
|
95
|
+
not_found do
|
96
|
+
''
|
97
|
+
end
|
98
|
+
|
99
|
+
error do
|
100
|
+
''
|
101
|
+
end
|
102
|
+
|
103
|
+
helpers do
|
104
|
+
def request_log_line
|
105
|
+
settings.logger.info([env['REQUEST_METHOD'], env['REQUEST_PATH']].join(' '), {
|
106
|
+
:remote_address => env['REMOTE_ADDR'],
|
107
|
+
:user_agent => env['HTTP_USER_AGENT'],
|
108
|
+
:request_method => env['REQUEST_METHOD'],
|
109
|
+
:request_uri => env['REQUEST_URI'],
|
110
|
+
:request_body => env['rack.input'].read
|
111
|
+
})
|
112
|
+
env['rack.input'].rewind
|
113
|
+
end
|
114
|
+
|
115
|
+
def bad_request!
|
116
|
+
ahalt 400
|
117
|
+
end
|
118
|
+
|
119
|
+
def not_found!
|
120
|
+
ahalt 404
|
121
|
+
end
|
122
|
+
|
123
|
+
def unavailable!
|
124
|
+
ahalt 503
|
125
|
+
end
|
126
|
+
|
127
|
+
def created!(response)
|
128
|
+
status 201
|
129
|
+
body response
|
130
|
+
end
|
131
|
+
|
132
|
+
def accepted!(response)
|
133
|
+
status 202
|
134
|
+
body response
|
135
|
+
end
|
136
|
+
|
137
|
+
def issued!
|
138
|
+
accepted!(MultiJson.dump(:issued => Time.now.to_i))
|
139
|
+
end
|
140
|
+
|
141
|
+
def no_content!
|
142
|
+
status 204
|
143
|
+
body ''
|
144
|
+
end
|
145
|
+
|
146
|
+
def read_data(rules={}, &block)
|
147
|
+
begin
|
148
|
+
data = MultiJson.load(env['rack.input'].read)
|
149
|
+
valid = rules.all? do |key, rule|
|
150
|
+
data[key].is_a?(rule[:type]) || (rule[:nil_ok] && data[key].nil?)
|
151
|
+
end
|
152
|
+
if valid
|
153
|
+
block.call(data)
|
154
|
+
else
|
155
|
+
bad_request!
|
156
|
+
end
|
157
|
+
rescue MultiJson::ParseError
|
158
|
+
bad_request!
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def integer_parameter(parameter)
|
163
|
+
parameter =~ /^[0-9]+$/ ? parameter.to_i : nil
|
164
|
+
end
|
165
|
+
|
166
|
+
def pagination(items)
|
167
|
+
limit = integer_parameter(params[:limit])
|
168
|
+
offset = integer_parameter(params[:offset]) || 0
|
169
|
+
unless limit.nil?
|
170
|
+
headers['X-Pagination'] = MultiJson.dump(
|
171
|
+
:limit => limit,
|
172
|
+
:offset => offset,
|
173
|
+
:total => items.size
|
174
|
+
)
|
175
|
+
paginated = items.slice(offset, limit)
|
176
|
+
Array(paginated)
|
177
|
+
else
|
178
|
+
items
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def transport_info(&block)
|
183
|
+
info = {
|
184
|
+
:keepalives => {
|
185
|
+
:messages => nil,
|
186
|
+
:consumers => nil
|
187
|
+
},
|
188
|
+
:results => {
|
189
|
+
:messages => nil,
|
190
|
+
:consumers => nil
|
191
|
+
},
|
192
|
+
:connected => settings.transport.connected?
|
193
|
+
}
|
194
|
+
if settings.transport.connected?
|
195
|
+
settings.transport.stats('keepalives') do |stats|
|
196
|
+
info[:keepalives] = stats
|
197
|
+
settings.transport.stats('results') do |stats|
|
198
|
+
info[:results] = stats
|
199
|
+
block.call(info)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
else
|
203
|
+
block.call(info)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def resolve_event(event_json)
|
208
|
+
event = MultiJson.load(event_json)
|
209
|
+
check = event[:check].merge(
|
210
|
+
:output => 'Resolving on request of the API',
|
211
|
+
:status => 0,
|
212
|
+
:issued => Time.now.to_i,
|
213
|
+
:executed => Time.now.to_i,
|
214
|
+
:force_resolve => true
|
215
|
+
)
|
216
|
+
check.delete(:history)
|
217
|
+
payload = {
|
218
|
+
:client => event[:client][:name],
|
219
|
+
:check => check
|
220
|
+
}
|
221
|
+
settings.logger.info('publishing check result', {
|
222
|
+
:payload => payload
|
223
|
+
})
|
224
|
+
settings.transport.publish(:direct, 'results', MultiJson.dump(payload)) do |info|
|
225
|
+
if info[:error]
|
226
|
+
settings.logger.error('failed to publish check result', {
|
227
|
+
:payload => payload,
|
228
|
+
:error => info[:error].to_s
|
229
|
+
})
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
before do
|
236
|
+
request_log_line
|
237
|
+
content_type 'application/json'
|
238
|
+
end
|
239
|
+
|
240
|
+
aget '/info/?' do
|
241
|
+
transport_info do |info|
|
242
|
+
response = {
|
243
|
+
:sensu => {
|
244
|
+
:version => VERSION
|
245
|
+
},
|
246
|
+
:transport => info,
|
247
|
+
:redis => {
|
248
|
+
:connected => settings.redis.connected?
|
249
|
+
}
|
250
|
+
}
|
251
|
+
body MultiJson.dump(response)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
aget '/health/?' do
|
256
|
+
if settings.redis.connected? && settings.transport.connected?
|
257
|
+
healthy = Array.new
|
258
|
+
min_consumers = integer_parameter(params[:consumers])
|
259
|
+
max_messages = integer_parameter(params[:messages])
|
260
|
+
transport_info do |info|
|
261
|
+
if min_consumers
|
262
|
+
healthy << (info[:keepalives][:consumers] >= min_consumers)
|
263
|
+
healthy << (info[:results][:consumers] >= min_consumers)
|
264
|
+
end
|
265
|
+
if max_messages
|
266
|
+
healthy << (info[:keepalives][:messages] <= max_messages)
|
267
|
+
healthy << (info[:results][:messages] <= max_messages)
|
268
|
+
end
|
269
|
+
healthy.all? ? no_content! : unavailable!
|
270
|
+
end
|
271
|
+
else
|
272
|
+
unavailable!
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
aget '/clients/?' do
|
277
|
+
response = Array.new
|
278
|
+
settings.redis.smembers('clients') do |clients|
|
279
|
+
clients = pagination(clients)
|
280
|
+
unless clients.empty?
|
281
|
+
clients.each_with_index do |client_name, index|
|
282
|
+
settings.redis.get('client:' + client_name) do |client_json|
|
283
|
+
response << MultiJson.load(client_json)
|
284
|
+
if index == clients.size - 1
|
285
|
+
body MultiJson.dump(response)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
else
|
290
|
+
body MultiJson.dump(response)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
aget %r{/clients?/([\w\.-]+)/?$} do |client_name|
|
296
|
+
settings.redis.get('client:' + client_name) do |client_json|
|
297
|
+
unless client_json.nil?
|
298
|
+
body client_json
|
299
|
+
else
|
300
|
+
not_found!
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
aget %r{/clients/([\w\.-]+)/history/?$} do |client_name|
|
306
|
+
response = Array.new
|
307
|
+
settings.redis.smembers('history:' + client_name) do |checks|
|
308
|
+
unless checks.empty?
|
309
|
+
checks.each_with_index do |check_name, index|
|
310
|
+
history_key = 'history:' + client_name + ':' + check_name
|
311
|
+
settings.redis.lrange(history_key, -21, -1) do |history|
|
312
|
+
history.map! do |status|
|
313
|
+
status.to_i
|
314
|
+
end
|
315
|
+
execution_key = 'execution:' + client_name + ':' + check_name
|
316
|
+
settings.redis.get(execution_key) do |last_execution|
|
317
|
+
unless history.empty? || last_execution.nil?
|
318
|
+
item = {
|
319
|
+
:check => check_name,
|
320
|
+
:history => history,
|
321
|
+
:last_execution => last_execution.to_i,
|
322
|
+
:last_status => history.last
|
323
|
+
}
|
324
|
+
response << item
|
325
|
+
end
|
326
|
+
if index == checks.size - 1
|
327
|
+
body MultiJson.dump(response)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
else
|
333
|
+
body MultiJson.dump(response)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
adelete %r{/clients?/([\w\.-]+)/?$} do |client_name|
|
339
|
+
settings.redis.get('client:' + client_name) do |client_json|
|
340
|
+
unless client_json.nil?
|
341
|
+
settings.redis.hgetall('events:' + client_name) do |events|
|
342
|
+
events.each do |check_name, event_json|
|
343
|
+
resolve_event(event_json)
|
344
|
+
end
|
345
|
+
EM::Timer.new(5) do
|
346
|
+
client = MultiJson.load(client_json)
|
347
|
+
settings.logger.info('deleting client', {
|
348
|
+
:client => client
|
349
|
+
})
|
350
|
+
settings.redis.srem('clients', client_name) do
|
351
|
+
settings.redis.del('client:' + client_name)
|
352
|
+
settings.redis.del('events:' + client_name)
|
353
|
+
settings.redis.smembers('history:' + client_name) do |checks|
|
354
|
+
checks.each do |check_name|
|
355
|
+
settings.redis.del('history:' + client_name + ':' + check_name)
|
356
|
+
settings.redis.del('execution:' + client_name + ':' + check_name)
|
357
|
+
end
|
358
|
+
settings.redis.del('history:' + client_name)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
issued!
|
363
|
+
end
|
364
|
+
else
|
365
|
+
not_found!
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
aget '/checks/?' do
|
371
|
+
body MultiJson.dump(settings.all_checks)
|
372
|
+
end
|
373
|
+
|
374
|
+
aget %r{/checks?/([\w\.-]+)/?$} do |check_name|
|
375
|
+
if settings.checks[check_name]
|
376
|
+
response = settings.checks[check_name].merge(:name => check_name)
|
377
|
+
body MultiJson.dump(response)
|
378
|
+
else
|
379
|
+
not_found!
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
apost '/request/?' do
|
384
|
+
rules = {
|
385
|
+
:check => {:type => String, :nil_ok => false},
|
386
|
+
:subscribers => {:type => Array, :nil_ok => true}
|
387
|
+
}
|
388
|
+
read_data(rules) do |data|
|
389
|
+
if settings.checks[data[:check]]
|
390
|
+
check = settings.checks[data[:check]]
|
391
|
+
subscribers = data[:subscribers] || check[:subscribers] || Array.new
|
392
|
+
payload = {
|
393
|
+
:name => data[:check],
|
394
|
+
:command => check[:command],
|
395
|
+
:issued => Time.now.to_i
|
396
|
+
}
|
397
|
+
settings.logger.info('publishing check request', {
|
398
|
+
:payload => payload,
|
399
|
+
:subscribers => subscribers
|
400
|
+
})
|
401
|
+
subscribers.uniq.each do |exchange_name|
|
402
|
+
settings.transport.publish(:fanout, exchange_name, MultiJson.dump(payload)) do |info|
|
403
|
+
if info[:error]
|
404
|
+
settings.logger.error('failed to publish check request', {
|
405
|
+
:exchange_name => exchange_name,
|
406
|
+
:payload => payload,
|
407
|
+
:error => info[:error].to_s
|
408
|
+
})
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
issued!
|
413
|
+
else
|
414
|
+
not_found!
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
aget '/events/?' do
|
420
|
+
response = Array.new
|
421
|
+
settings.redis.smembers('clients') do |clients|
|
422
|
+
unless clients.empty?
|
423
|
+
clients.each_with_index do |client_name, index|
|
424
|
+
settings.redis.hgetall('events:' + client_name) do |events|
|
425
|
+
events.each do |check_name, event_json|
|
426
|
+
response << MultiJson.load(event_json)
|
427
|
+
end
|
428
|
+
if index == clients.size - 1
|
429
|
+
body MultiJson.dump(response)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
else
|
434
|
+
body MultiJson.dump(response)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
aget %r{/events/([\w\.-]+)/?$} do |client_name|
|
440
|
+
response = Array.new
|
441
|
+
settings.redis.hgetall('events:' + client_name) do |events|
|
442
|
+
events.each do |check_name, event_json|
|
443
|
+
response << MultiJson.load(event_json)
|
444
|
+
end
|
445
|
+
body MultiJson.dump(response)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
449
|
+
aget %r{/events?/([\w\.-]+)/([\w\.-]+)/?$} do |client_name, check_name|
|
450
|
+
settings.redis.hgetall('events:' + client_name) do |events|
|
451
|
+
event_json = events[check_name]
|
452
|
+
unless event_json.nil?
|
453
|
+
body event_json
|
454
|
+
else
|
455
|
+
not_found!
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
adelete %r{/events?/([\w\.-]+)/([\w\.-]+)/?$} do |client_name, check_name|
|
461
|
+
settings.redis.hgetall('events:' + client_name) do |events|
|
462
|
+
if events.include?(check_name)
|
463
|
+
resolve_event(events[check_name])
|
464
|
+
issued!
|
465
|
+
else
|
466
|
+
not_found!
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
apost '/resolve/?' do
|
472
|
+
rules = {
|
473
|
+
:client => {:type => String, :nil_ok => false},
|
474
|
+
:check => {:type => String, :nil_ok => false}
|
475
|
+
}
|
476
|
+
read_data(rules) do |data|
|
477
|
+
settings.redis.hgetall('events:' + data[:client]) do |events|
|
478
|
+
if events.include?(data[:check])
|
479
|
+
resolve_event(events[data[:check]])
|
480
|
+
issued!
|
481
|
+
else
|
482
|
+
not_found!
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
aget '/aggregates/?' do
|
489
|
+
response = Array.new
|
490
|
+
settings.redis.smembers('aggregates') do |checks|
|
491
|
+
unless checks.empty?
|
492
|
+
checks.each_with_index do |check_name, index|
|
493
|
+
settings.redis.smembers('aggregates:' + check_name) do |aggregates|
|
494
|
+
aggregates.reverse!
|
495
|
+
aggregates.map! do |issued|
|
496
|
+
issued.to_i
|
497
|
+
end
|
498
|
+
item = {
|
499
|
+
:check => check_name,
|
500
|
+
:issued => aggregates
|
501
|
+
}
|
502
|
+
response << item
|
503
|
+
if index == checks.size - 1
|
504
|
+
body MultiJson.dump(response)
|
505
|
+
end
|
506
|
+
end
|
507
|
+
end
|
508
|
+
else
|
509
|
+
body MultiJson.dump(response)
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
aget %r{/aggregates/([\w\.-]+)/?$} do |check_name|
|
515
|
+
settings.redis.smembers('aggregates:' + check_name) do |aggregates|
|
516
|
+
unless aggregates.empty?
|
517
|
+
aggregates.reverse!
|
518
|
+
aggregates.map! do |issued|
|
519
|
+
issued.to_i
|
520
|
+
end
|
521
|
+
age = integer_parameter(params[:age])
|
522
|
+
if age
|
523
|
+
timestamp = Time.now.to_i - age
|
524
|
+
aggregates.reject! do |issued|
|
525
|
+
issued > timestamp
|
526
|
+
end
|
527
|
+
end
|
528
|
+
body MultiJson.dump(pagination(aggregates))
|
529
|
+
else
|
530
|
+
not_found!
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
adelete %r{/aggregates/([\w\.-]+)/?$} do |check_name|
|
536
|
+
settings.redis.smembers('aggregates:' + check_name) do |aggregates|
|
537
|
+
unless aggregates.empty?
|
538
|
+
aggregates.each do |check_issued|
|
539
|
+
result_set = check_name + ':' + check_issued
|
540
|
+
settings.redis.del('aggregation:' + result_set)
|
541
|
+
settings.redis.del('aggregate:' + result_set)
|
542
|
+
end
|
543
|
+
settings.redis.del('aggregates:' + check_name) do
|
544
|
+
settings.redis.srem('aggregates', check_name) do
|
545
|
+
no_content!
|
546
|
+
end
|
547
|
+
end
|
548
|
+
else
|
549
|
+
not_found!
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
aget %r{/aggregates?/([\w\.-]+)/([\w\.-]+)/?$} do |check_name, check_issued|
|
555
|
+
result_set = check_name + ':' + check_issued
|
556
|
+
settings.redis.hgetall('aggregate:' + result_set) do |aggregate|
|
557
|
+
unless aggregate.empty?
|
558
|
+
response = aggregate.inject(Hash.new) do |totals, (status, count)|
|
559
|
+
totals[status] = Integer(count)
|
560
|
+
totals
|
561
|
+
end
|
562
|
+
settings.redis.hgetall('aggregation:' + result_set) do |results|
|
563
|
+
parsed_results = results.inject(Array.new) do |parsed, (client_name, check_json)|
|
564
|
+
check = MultiJson.load(check_json)
|
565
|
+
parsed << check.merge(:client => client_name)
|
566
|
+
end
|
567
|
+
if params[:summarize]
|
568
|
+
options = params[:summarize].split(',')
|
569
|
+
if options.include?('output')
|
570
|
+
outputs = Hash.new(0)
|
571
|
+
parsed_results.each do |result|
|
572
|
+
outputs[result[:output]] += 1
|
573
|
+
end
|
574
|
+
response[:outputs] = outputs
|
575
|
+
end
|
576
|
+
end
|
577
|
+
if params[:results]
|
578
|
+
response[:results] = parsed_results
|
579
|
+
end
|
580
|
+
body MultiJson.dump(response)
|
581
|
+
end
|
582
|
+
else
|
583
|
+
not_found!
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
apost %r{/stash(?:es)?/(.*)/?} do |path|
|
589
|
+
read_data do |data|
|
590
|
+
settings.redis.set('stash:' + path, MultiJson.dump(data)) do
|
591
|
+
settings.redis.sadd('stashes', path) do
|
592
|
+
created!(MultiJson.dump(:path => path))
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
aget %r{/stash(?:es)?/(.*)/?} do |path|
|
599
|
+
settings.redis.get('stash:' + path) do |stash_json|
|
600
|
+
unless stash_json.nil?
|
601
|
+
body stash_json
|
602
|
+
else
|
603
|
+
not_found!
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
adelete %r{/stash(?:es)?/(.*)/?} do |path|
|
609
|
+
settings.redis.exists('stash:' + path) do |stash_exists|
|
610
|
+
if stash_exists
|
611
|
+
settings.redis.srem('stashes', path) do
|
612
|
+
settings.redis.del('stash:' + path) do
|
613
|
+
no_content!
|
614
|
+
end
|
615
|
+
end
|
616
|
+
else
|
617
|
+
not_found!
|
618
|
+
end
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
aget '/stashes/?' do
|
623
|
+
response = Array.new
|
624
|
+
settings.redis.smembers('stashes') do |stashes|
|
625
|
+
unless stashes.empty?
|
626
|
+
stashes.each_with_index do |path, index|
|
627
|
+
settings.redis.get('stash:' + path) do |stash_json|
|
628
|
+
settings.redis.ttl('stash:' + path) do |ttl|
|
629
|
+
unless stash_json.nil?
|
630
|
+
item = {
|
631
|
+
:path => path,
|
632
|
+
:content => MultiJson.load(stash_json),
|
633
|
+
:expire => ttl
|
634
|
+
}
|
635
|
+
response << item
|
636
|
+
else
|
637
|
+
settings.redis.srem('stashes', path)
|
638
|
+
end
|
639
|
+
if index == stashes.size - 1
|
640
|
+
body MultiJson.dump(pagination(response))
|
641
|
+
end
|
642
|
+
end
|
643
|
+
end
|
644
|
+
end
|
645
|
+
else
|
646
|
+
body MultiJson.dump(response)
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
apost '/stashes/?' do
|
652
|
+
rules = {
|
653
|
+
:path => {:type => String, :nil_ok => false},
|
654
|
+
:content => {:type => Hash, :nil_ok => false},
|
655
|
+
:expire => {:type => Integer, :nil_ok => true}
|
656
|
+
}
|
657
|
+
read_data(rules) do |data|
|
658
|
+
stash_key = 'stash:' + data[:path]
|
659
|
+
settings.redis.set(stash_key, MultiJson.dump(data[:content])) do
|
660
|
+
settings.redis.sadd('stashes', data[:path]) do
|
661
|
+
response = MultiJson.dump(:path => data[:path])
|
662
|
+
if data[:expire]
|
663
|
+
settings.redis.expire(stash_key, data[:expire]) do
|
664
|
+
created!(response)
|
665
|
+
end
|
666
|
+
else
|
667
|
+
created!(response)
|
668
|
+
end
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|