sensu 0.8.16 → 0.8.18
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/README.org +3 -1
- data/lib/sensu/api.rb +13 -8
- data/lib/sensu/client.rb +8 -4
- data/lib/sensu/config.rb +20 -4
- data/lib/sensu/helpers/redis.rb +25 -0
- data/lib/sensu/helpers/ruby.rb +46 -0
- data/lib/sensu/server.rb +11 -5
- data/lib/sensu.rb +1 -1
- data/sensu.gemspec +1 -1
- metadata +7 -6
- data/lib/sensu/helpers.rb +0 -26
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -40,7 +40,7 @@ GEM
|
|
40
40
|
rspec-expectations (2.6.0)
|
41
41
|
diff-lcs (~> 1.1.2)
|
42
42
|
rspec-mocks (2.6.0)
|
43
|
-
ruby-redis
|
43
|
+
ruby-redis (0.0.2)
|
44
44
|
eventmachine
|
45
45
|
sinatra (1.3.1)
|
46
46
|
rack (~> 1.3, >= 1.3.4)
|
@@ -68,5 +68,5 @@ DEPENDENCIES
|
|
68
68
|
json
|
69
69
|
rack (~> 1.3.4)
|
70
70
|
rake
|
71
|
-
ruby-redis
|
71
|
+
ruby-redis
|
72
72
|
thin
|
data/README.org
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
* Documentation
|
10
10
|
Find it [[https://github.com/sonian/sensu/wiki][HERE]].
|
11
11
|
* Other Projects
|
12
|
-
- [[https://github.com/sonian/sensu-
|
12
|
+
- [[https://github.com/sonian/sensu-plugin][Sensu Community Plugins]]
|
13
13
|
- [[https://github.com/sonian/sensu-dashboard][Sensu Dashboard]]
|
14
14
|
* License
|
15
15
|
Sensu is released under the [[https://github.com/sonian/sensu/blob/master/MIT-LICENSE.txt][MIT license]].
|
@@ -34,3 +34,5 @@
|
|
34
34
|
- [[http://twitter.com/amdprophet][Justin Kolberg]]
|
35
35
|
- [[http://twitter.com/kartar][James Turnbull]]
|
36
36
|
- [[http://twitter.com/joshpasqualetto][Josh Pasqualetto]]
|
37
|
+
- Steve Lum
|
38
|
+
- [[http://twitter.com/miller_joe][Joe Miller]]
|
data/lib/sensu/api.rb
CHANGED
@@ -3,6 +3,8 @@ require File.join(File.dirname(__FILE__), 'config')
|
|
3
3
|
require 'sinatra/async'
|
4
4
|
require 'redis'
|
5
5
|
|
6
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'redis')
|
7
|
+
|
6
8
|
module Sensu
|
7
9
|
class API < Sinatra::Base
|
8
10
|
register Sinatra::Async
|
@@ -10,7 +12,7 @@ module Sensu
|
|
10
12
|
def self.run(options={})
|
11
13
|
EM.run do
|
12
14
|
self.setup(options)
|
13
|
-
self.run!(:port =>
|
15
|
+
self.run!(:port => $settings.api.port)
|
14
16
|
|
15
17
|
%w[INT TERM].each do |signal|
|
16
18
|
Signal.trap(signal) do
|
@@ -22,12 +24,12 @@ module Sensu
|
|
22
24
|
|
23
25
|
def self.setup(options={})
|
24
26
|
config = Sensu::Config.new(options)
|
25
|
-
|
27
|
+
$settings = config.settings
|
26
28
|
$logger = config.logger
|
27
29
|
$logger.debug('[setup] -- connecting to redis')
|
28
|
-
$redis = EM.connect(
|
30
|
+
$redis = EM.connect($settings.redis.host, $settings.redis.port, Redis::Reconnect)
|
29
31
|
$logger.debug('[setup] -- connecting to rabbitmq')
|
30
|
-
connection = AMQP.connect(
|
32
|
+
connection = AMQP.connect($settings.rabbitmq.to_hash.symbolize_keys)
|
31
33
|
$amq = MQ.new(connection)
|
32
34
|
end
|
33
35
|
|
@@ -86,6 +88,9 @@ module Sensu
|
|
86
88
|
$redis.srem('clients', client)
|
87
89
|
$redis.del('events:' + client)
|
88
90
|
$redis.del('client:' + client)
|
91
|
+
$settings.checks.each_key do |check_name|
|
92
|
+
$redis.del('history:' + client + ':' + check_name)
|
93
|
+
end
|
89
94
|
end
|
90
95
|
status 204
|
91
96
|
body nil
|
@@ -229,16 +234,16 @@ module Sensu
|
|
229
234
|
|
230
235
|
def self.test(options={})
|
231
236
|
self.setup(options)
|
232
|
-
$redis.set('client:' +
|
233
|
-
$redis.sadd('clients',
|
234
|
-
$redis.hset('events:' +
|
237
|
+
$redis.set('client:' + $settings.client.name, $settings.client.to_json).callback do
|
238
|
+
$redis.sadd('clients', $settings.client.name).callback do
|
239
|
+
$redis.hset('events:' + $settings.client.name, 'test', {
|
235
240
|
:status => 2,
|
236
241
|
:output => 'CRITICAL',
|
237
242
|
:flapping => false,
|
238
243
|
:occurrences => 1
|
239
244
|
}.to_json).callback do
|
240
245
|
$redis.set('stash:test/test', '{"key": "value"}').callback do
|
241
|
-
self.run!(:port =>
|
246
|
+
self.run!(:port => $settings.api.port)
|
242
247
|
end
|
243
248
|
end
|
244
249
|
end
|
data/lib/sensu/client.rb
CHANGED
@@ -84,8 +84,12 @@ module Sensu
|
|
84
84
|
end
|
85
85
|
check.status = $?.exitstatus
|
86
86
|
end
|
87
|
-
publish = proc do
|
88
|
-
|
87
|
+
publish = proc do
|
88
|
+
unless check.status.nil?
|
89
|
+
publish_result(check)
|
90
|
+
else
|
91
|
+
@logger.warn('[execute] -- nil exit status code -- ' + check.name)
|
92
|
+
end
|
89
93
|
@checks_in_progress.delete(check.name)
|
90
94
|
end
|
91
95
|
EM.defer(execute, publish)
|
@@ -182,8 +186,8 @@ module Sensu
|
|
182
186
|
else
|
183
187
|
@logger.warn('[socket] -- a check name, exit status, and output are required -- e.g. {name: x, status: 0, output: "y"}')
|
184
188
|
end
|
185
|
-
rescue JSON::ParserError
|
186
|
-
@logger.warn('[socket] --
|
189
|
+
rescue JSON::ParserError => error
|
190
|
+
@logger.warn('[socket] -- check result must be valid JSON: ' + error)
|
187
191
|
end
|
188
192
|
close_connection
|
189
193
|
end
|
data/lib/sensu/config.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'ruby')
|
2
|
+
|
1
3
|
require 'rubygems' if RUBY_VERSION < '1.9.0'
|
2
4
|
require 'bundler'
|
3
5
|
require 'bundler/setup'
|
4
6
|
|
5
|
-
require File.join(File.dirname(__FILE__), 'helpers')
|
6
|
-
|
7
7
|
gem 'eventmachine', '~> 1.0.0.beta.4'
|
8
8
|
|
9
9
|
require 'optparse'
|
@@ -34,12 +34,25 @@ module Sensu
|
|
34
34
|
if File.readable?(config_file)
|
35
35
|
begin
|
36
36
|
@settings = Hashie::Mash.new(JSON.parse(File.open(config_file, 'r').read))
|
37
|
-
rescue JSON::ParserError =>
|
38
|
-
invalid_config('configuration file must be valid JSON: ' +
|
37
|
+
rescue JSON::ParserError => error
|
38
|
+
invalid_config('configuration file (' + config_file + ') must be valid JSON: ' + error)
|
39
39
|
end
|
40
40
|
else
|
41
41
|
invalid_config('configuration file does not exist or is not readable: ' + config_file)
|
42
42
|
end
|
43
|
+
config_dir = options[:config_dir] || '/etc/sensu/conf.d'
|
44
|
+
if File.exists?(config_dir)
|
45
|
+
Dir[config_dir + '/**/*.json'].each do |snippet_file|
|
46
|
+
begin
|
47
|
+
snippet_hash = JSON.parse(File.open(snippet_file, 'r').read)
|
48
|
+
rescue JSON::ParserError => error
|
49
|
+
invalid_config('configuration snippet file (' + snippet_file + ') must be valid JSON: ' + error)
|
50
|
+
end
|
51
|
+
merged_settings = @settings.to_hash.deep_merge(snippet_hash)
|
52
|
+
@logger.warn('[settings] configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json)
|
53
|
+
@settings = Hashie::Mash.new(merged_settings)
|
54
|
+
end
|
55
|
+
end
|
43
56
|
validate_config(options['type'])
|
44
57
|
end
|
45
58
|
|
@@ -122,6 +135,9 @@ module Sensu
|
|
122
135
|
opts.on('-c', '--config FILE', 'Sensu JSON config FILE (default: /etc/sensu/config.json)') do |file|
|
123
136
|
options[:config_file] = file
|
124
137
|
end
|
138
|
+
opts.on('-d', '--config_dir DIR', 'Directory for supplemental Sensu JSON config files (default: /etc/sensu/conf.d/)') do |dir|
|
139
|
+
options[:config_dir] = dir
|
140
|
+
end
|
125
141
|
opts.on('-l', '--log FILE', 'Sensu log FILE (default: /tmp/sensu.log)') do |file|
|
126
142
|
options[:log_file] = file
|
127
143
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Redis
|
2
|
+
class Reconnect < Redis::Client
|
3
|
+
def connection_completed
|
4
|
+
@connected = true
|
5
|
+
@port, @host = Socket.unpack_sockaddr_in(get_peername)
|
6
|
+
end
|
7
|
+
|
8
|
+
def close
|
9
|
+
@closing_connection = true
|
10
|
+
close_connection_after_writing
|
11
|
+
end
|
12
|
+
|
13
|
+
def unbind
|
14
|
+
unless !@connected || @closing_connection
|
15
|
+
EM.add_timer(1) do
|
16
|
+
reconnect(@host, @port)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
until @queue.empty?
|
20
|
+
@queue.shift.fail RuntimeError.new 'connection closed'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Hash
|
2
|
+
def symbolize_keys(item=self)
|
3
|
+
case item
|
4
|
+
when Array
|
5
|
+
item.map do |i|
|
6
|
+
symbolize_keys(i)
|
7
|
+
end
|
8
|
+
when Hash
|
9
|
+
Hash[
|
10
|
+
item.map do |key, value|
|
11
|
+
new_key = key.is_a?(String) ? key.to_sym : key
|
12
|
+
new_value = symbolize_keys(value)
|
13
|
+
[new_key, new_value]
|
14
|
+
end
|
15
|
+
]
|
16
|
+
else
|
17
|
+
item
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def deep_diff(hash)
|
22
|
+
(self.keys | hash.keys).inject(Hash.new) do |diff, key|
|
23
|
+
unless self[key] == hash[key]
|
24
|
+
if self[key].is_a?(Hash) && hash[key].is_a?(Hash)
|
25
|
+
diff[key] = self[key].deep_diff(hash[key])
|
26
|
+
else
|
27
|
+
diff[key] = [self[key], hash[key]]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
diff
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def deep_merge(hash)
|
35
|
+
merger = proc do |key, value1, value2|
|
36
|
+
value1.is_a?(Hash) && value2.is_a?(Hash) ? value1.merge(value2, &merger) : value2
|
37
|
+
end
|
38
|
+
self.merge(hash, &merger)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class String
|
43
|
+
def self.unique(chars=32)
|
44
|
+
rand(36**chars).to_s(36)
|
45
|
+
end
|
46
|
+
end
|
data/lib/sensu/server.rb
CHANGED
@@ -2,6 +2,8 @@ require File.join(File.dirname(__FILE__), 'config')
|
|
2
2
|
|
3
3
|
require 'redis'
|
4
4
|
|
5
|
+
require File.join(File.dirname(__FILE__), 'helpers', 'redis')
|
6
|
+
|
5
7
|
module Sensu
|
6
8
|
class Server
|
7
9
|
attr_accessor :redis, :is_worker
|
@@ -44,7 +46,7 @@ module Sensu
|
|
44
46
|
|
45
47
|
def setup_redis
|
46
48
|
@logger.debug('[redis] -- connecting to redis')
|
47
|
-
@redis = EM.connect(@settings.redis.host, @settings.redis.port, Redis::
|
49
|
+
@redis = EM.connect(@settings.redis.host, @settings.redis.port, Redis::Reconnect)
|
48
50
|
end
|
49
51
|
|
50
52
|
def setup_amqp
|
@@ -85,10 +87,14 @@ module Sensu
|
|
85
87
|
handle = proc do
|
86
88
|
output = ''
|
87
89
|
Bundler.with_clean_env do
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
90
|
+
begin
|
91
|
+
IO.popen(@settings.handlers[handler] + ' 2>&1', 'r+') do |io|
|
92
|
+
io.write(event.to_json)
|
93
|
+
io.close_write
|
94
|
+
output = io.read
|
95
|
+
end
|
96
|
+
rescue Errno::EPIPE => error
|
97
|
+
output = handler + ' -- broken pipe: ' + error
|
92
98
|
end
|
93
99
|
end
|
94
100
|
output
|
data/lib/sensu.rb
CHANGED
data/sensu.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_dependency("json")
|
19
19
|
s.add_dependency("hashie")
|
20
20
|
s.add_dependency("cabin", "0.1.7")
|
21
|
-
s.add_dependency("ruby-redis
|
21
|
+
s.add_dependency("ruby-redis")
|
22
22
|
s.add_dependency("rack", "~> 1.3.4")
|
23
23
|
s.add_dependency("async_sinatra")
|
24
24
|
s.add_dependency("thin")
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 8
|
9
|
-
-
|
10
|
-
version: 0.8.
|
9
|
+
- 18
|
10
|
+
version: 0.8.18
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sean Porter
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-12-
|
19
|
+
date: 2011-12-13 00:00:00 -08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -112,7 +112,7 @@ dependencies:
|
|
112
112
|
type: :runtime
|
113
113
|
version_requirements: *id006
|
114
114
|
- !ruby/object:Gem::Dependency
|
115
|
-
name: ruby-redis
|
115
|
+
name: ruby-redis
|
116
116
|
prerelease: false
|
117
117
|
requirement: &id007 !ruby/object:Gem::Requirement
|
118
118
|
none: false
|
@@ -238,7 +238,8 @@ files:
|
|
238
238
|
- lib/sensu/api.rb
|
239
239
|
- lib/sensu/client.rb
|
240
240
|
- lib/sensu/config.rb
|
241
|
-
- lib/sensu/helpers.rb
|
241
|
+
- lib/sensu/helpers/redis.rb
|
242
|
+
- lib/sensu/helpers/ruby.rb
|
242
243
|
- lib/sensu/server.rb
|
243
244
|
- sensu.gemspec
|
244
245
|
has_rdoc: true
|
data/lib/sensu/helpers.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
def symbolize_keys(item=self)
|
3
|
-
case item
|
4
|
-
when Array
|
5
|
-
item.map do |i|
|
6
|
-
symbolize_keys(i)
|
7
|
-
end
|
8
|
-
when Hash
|
9
|
-
Hash[
|
10
|
-
item.map do |key, value|
|
11
|
-
new_key = key.is_a?(String) ? key.to_sym : key
|
12
|
-
new_value = symbolize_keys(value)
|
13
|
-
[new_key, new_value]
|
14
|
-
end
|
15
|
-
]
|
16
|
-
else
|
17
|
-
item
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class String
|
23
|
-
def self.unique(chars=32)
|
24
|
-
rand(36**chars).to_s(36)
|
25
|
-
end
|
26
|
-
end
|