sensu 0.9.1 → 0.9.2.beta
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.rb +1 -1
- data/lib/sensu/api.rb +10 -5
- data/lib/sensu/client.rb +72 -50
- data/lib/sensu/config.rb +72 -80
- data/lib/sensu/patches/ruby.rb +7 -1
- data/lib/sensu/server.rb +32 -17
- metadata +12 -9
data/lib/sensu.rb
CHANGED
data/lib/sensu/api.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'config')
|
2
2
|
|
3
|
+
require 'thin'
|
3
4
|
require 'sinatra/async'
|
4
5
|
require 'redis'
|
5
6
|
|
@@ -12,7 +13,9 @@ module Sensu
|
|
12
13
|
def self.run(options={})
|
13
14
|
EM::run do
|
14
15
|
self.setup(options)
|
15
|
-
|
16
|
+
|
17
|
+
Thin::Logging.silent = true
|
18
|
+
Thin::Server.start(self, $settings.api.port)
|
16
19
|
|
17
20
|
%w[INT TERM].each do |signal|
|
18
21
|
Signal.trap(signal) do
|
@@ -24,8 +27,8 @@ module Sensu
|
|
24
27
|
|
25
28
|
def self.setup(options={})
|
26
29
|
config = Sensu::Config.new(options)
|
30
|
+
$logger = config.logger
|
27
31
|
$settings = config.settings
|
28
|
-
$logger = config.logger || config.open_log
|
29
32
|
if options[:daemonize]
|
30
33
|
Process.daemonize
|
31
34
|
end
|
@@ -246,7 +249,7 @@ module Sensu
|
|
246
249
|
end
|
247
250
|
end
|
248
251
|
|
249
|
-
def self.
|
252
|
+
def self.setup_test_scaffolding(options={})
|
250
253
|
self.setup(options)
|
251
254
|
$settings.client.timestamp = Time.now.to_i
|
252
255
|
$redis.set('client:' + $settings.client.name, $settings.client.to_json).callback do
|
@@ -258,7 +261,8 @@ module Sensu
|
|
258
261
|
:occurrences => 1
|
259
262
|
}.to_json).callback do
|
260
263
|
$redis.set('stash:test/test', '{"key": "value"}').callback do
|
261
|
-
|
264
|
+
Thin::Logging.silent = true
|
265
|
+
Thin::Server.start(self, $settings.api.port)
|
262
266
|
end
|
263
267
|
end
|
264
268
|
end
|
@@ -267,7 +271,8 @@ module Sensu
|
|
267
271
|
|
268
272
|
def self.stop(signal)
|
269
273
|
$logger.warn('[stop] -- stopping sensu api -- ' + signal)
|
270
|
-
|
274
|
+
$logger.warn('[stop] -- stopping reactor')
|
275
|
+
EM::PeriodicTimer.new(0.25) do
|
271
276
|
EM::stop_event_loop
|
272
277
|
end
|
273
278
|
end
|
data/lib/sensu/client.rb
CHANGED
@@ -15,6 +15,7 @@ module Sensu
|
|
15
15
|
client.setup_keepalives
|
16
16
|
client.setup_subscriptions
|
17
17
|
client.setup_queue_monitor
|
18
|
+
client.setup_standalone
|
18
19
|
client.setup_socket
|
19
20
|
|
20
21
|
%w[INT TERM].each do |signal|
|
@@ -27,8 +28,10 @@ module Sensu
|
|
27
28
|
|
28
29
|
def initialize(options={})
|
29
30
|
config = Sensu::Config.new(options)
|
31
|
+
@logger = config.logger
|
30
32
|
@settings = config.settings
|
31
|
-
@
|
33
|
+
@timers = Array.new
|
34
|
+
@checks_in_progress = Array.new
|
32
35
|
end
|
33
36
|
|
34
37
|
def setup_amqp
|
@@ -46,7 +49,7 @@ module Sensu
|
|
46
49
|
def setup_keepalives
|
47
50
|
@logger.debug('[keepalive] -- setup keepalives')
|
48
51
|
publish_keepalive
|
49
|
-
EM::PeriodicTimer.new(30) do
|
52
|
+
@timers << EM::PeriodicTimer.new(30) do
|
50
53
|
publish_keepalive
|
51
54
|
end
|
52
55
|
end
|
@@ -60,16 +63,24 @@ module Sensu
|
|
60
63
|
end
|
61
64
|
|
62
65
|
def execute_check(check)
|
63
|
-
@logger.debug('[execute] --
|
64
|
-
@checks_in_progress ||= Array.new
|
66
|
+
@logger.debug('[execute] -- attempting to execute check -- ' + check.name)
|
65
67
|
if @settings.checks.key?(check.name)
|
66
68
|
unless @checks_in_progress.include?(check.name)
|
69
|
+
@logger.debug('[execute] -- executing check -- ' + check.name)
|
67
70
|
@checks_in_progress.push(check.name)
|
68
71
|
unmatched_tokens = Array.new
|
69
72
|
command = @settings.checks[check.name].command.gsub(/:::(.*?):::/) do
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
token = $1.to_s
|
74
|
+
begin
|
75
|
+
value = @settings.client.instance_eval(token)
|
76
|
+
if value.nil?
|
77
|
+
unmatched_tokens.push(token)
|
78
|
+
end
|
79
|
+
rescue NoMethodError
|
80
|
+
value = nil
|
81
|
+
unmatched_tokens.push(token)
|
82
|
+
end
|
83
|
+
value
|
73
84
|
end
|
74
85
|
if unmatched_tokens.empty?
|
75
86
|
execute = proc do
|
@@ -97,6 +108,8 @@ module Sensu
|
|
97
108
|
publish_result(check)
|
98
109
|
@checks_in_progress.delete(check.name)
|
99
110
|
end
|
111
|
+
else
|
112
|
+
@logger.debug('[execute] -- previous check execution still in progress -- ' + check.name)
|
100
113
|
end
|
101
114
|
else
|
102
115
|
@logger.warn('[execute] -- unkown check -- ' + check.name)
|
@@ -110,60 +123,50 @@ module Sensu
|
|
110
123
|
|
111
124
|
def setup_subscriptions
|
112
125
|
@logger.debug('[subscribe] -- setup subscriptions')
|
113
|
-
@
|
114
|
-
@settings.client.subscriptions.
|
115
|
-
@settings.client.subscriptions.each do |exchange|
|
126
|
+
@check_request_queue = @amq.queue(String.unique, :exclusive => true)
|
127
|
+
@settings.client.subscriptions.uniq.each do |exchange|
|
116
128
|
@logger.debug('[subscribe] -- queue binding to exchange -- ' + exchange)
|
117
|
-
@
|
129
|
+
@check_request_queue.bind(@amq.fanout(exchange))
|
118
130
|
end
|
119
|
-
@
|
120
|
-
check = Hashie::Mash.new(JSON.parse(
|
121
|
-
@logger.info('[subscribe] -- received check -- ' + check.name)
|
122
|
-
|
123
|
-
@logger.info('[subscribe] -- check requires matching -- ' + check.name)
|
124
|
-
matches = check.matching.all? do |key, value|
|
125
|
-
desired = case key
|
126
|
-
when /^!/
|
127
|
-
key = key.slice(1..-1)
|
128
|
-
false
|
129
|
-
else
|
130
|
-
true
|
131
|
-
end
|
132
|
-
matched = case key
|
133
|
-
when 'subscribes'
|
134
|
-
value.all? do |subscription|
|
135
|
-
@settings.client.subscriptions.include?(subscription)
|
136
|
-
end
|
137
|
-
else
|
138
|
-
@settings.client[key] == value
|
139
|
-
end
|
140
|
-
desired == matched
|
141
|
-
end
|
142
|
-
if matches
|
143
|
-
@logger.info('[subscribe] -- client matches -- ' + check.name)
|
144
|
-
execute_check(check)
|
145
|
-
else
|
146
|
-
@logger.info('[subscribe] -- client does not match -- ' + check.name)
|
147
|
-
end
|
148
|
-
else
|
149
|
-
execute_check(check)
|
150
|
-
end
|
131
|
+
@check_request_queue.subscribe do |check_request_json|
|
132
|
+
check = Hashie::Mash.new(JSON.parse(check_request_json))
|
133
|
+
@logger.info('[subscribe] -- received check request -- ' + check.name)
|
134
|
+
execute_check(check)
|
151
135
|
end
|
152
136
|
end
|
153
137
|
|
154
138
|
def setup_queue_monitor
|
155
139
|
@logger.debug('[monitor] -- setup queue monitor')
|
156
|
-
EM::PeriodicTimer.new(5) do
|
157
|
-
unless @
|
140
|
+
@timers << EM::PeriodicTimer.new(5) do
|
141
|
+
unless @check_request_queue.subscribed?
|
158
142
|
@logger.warn('[monitor] -- re-subscribing to subscriptions')
|
159
|
-
@
|
160
|
-
EM::Timer.new(1) do
|
143
|
+
@check_request_queue.delete
|
144
|
+
@timers << EM::Timer.new(1) do
|
161
145
|
setup_subscriptions
|
162
146
|
end
|
163
147
|
end
|
164
148
|
end
|
165
149
|
end
|
166
150
|
|
151
|
+
def setup_standalone(options={})
|
152
|
+
@logger.debug('[standalone] -- setup standalone')
|
153
|
+
standalone_count = 0
|
154
|
+
@settings.checks.each do |name, details|
|
155
|
+
if details.standalone
|
156
|
+
standalone_count += 1
|
157
|
+
check = Hashie::Mash.new(details.merge({:name => name}))
|
158
|
+
stagger = options[:test] ? 0 : 7
|
159
|
+
@timers << EM::Timer.new(stagger*standalone_count) do
|
160
|
+
interval = options[:test] ? 0.5 : details.interval
|
161
|
+
@timers << EM::PeriodicTimer.new(interval) do
|
162
|
+
check.issued = Time.now.to_i
|
163
|
+
execute_check(check)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
167
170
|
def setup_socket
|
168
171
|
@logger.debug('[socket] -- starting up socket')
|
169
172
|
EM::start_server('127.0.0.1', 3030, ClientSocket) do |socket|
|
@@ -173,10 +176,29 @@ module Sensu
|
|
173
176
|
end
|
174
177
|
end
|
175
178
|
|
179
|
+
def stop_reactor
|
180
|
+
@logger.info('[stop] -- completing checks in progress')
|
181
|
+
complete_in_progress = EM::tick_loop do
|
182
|
+
if @checks_in_progress.empty?
|
183
|
+
:stop
|
184
|
+
end
|
185
|
+
end
|
186
|
+
complete_in_progress.on_stop do
|
187
|
+
@logger.warn('[stop] -- stopping reactor')
|
188
|
+
EM::PeriodicTimer.new(0.25) do
|
189
|
+
EM::stop_event_loop
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
176
194
|
def stop(signal)
|
177
195
|
@logger.warn('[stop] -- stopping sensu client -- ' + signal)
|
178
|
-
|
179
|
-
|
196
|
+
@timers.each do |timer|
|
197
|
+
timer.cancel
|
198
|
+
end
|
199
|
+
@logger.warn('[stop] -- unsubscribing from subscriptions')
|
200
|
+
@check_request_queue.unsubscribe do
|
201
|
+
stop_reactor
|
180
202
|
end
|
181
203
|
end
|
182
204
|
end
|
@@ -201,7 +223,7 @@ module Sensu
|
|
201
223
|
@logger.warn('[socket] -- a check name, exit status, and output are required -- e.g. {"name": "x", "status": 0, "output": "y"}')
|
202
224
|
end
|
203
225
|
rescue JSON::ParserError => error
|
204
|
-
@logger.warn('[socket] -- check result must be valid JSON: ' + error
|
226
|
+
@logger.warn('[socket] -- check result must be valid JSON: ' + error)
|
205
227
|
end
|
206
228
|
close_connection
|
207
229
|
end
|
data/lib/sensu/config.rb
CHANGED
@@ -15,85 +15,45 @@ require 'cabin/outputs/em-stdlib-logger'
|
|
15
15
|
|
16
16
|
module Sensu
|
17
17
|
class Config
|
18
|
-
attr_accessor :
|
18
|
+
attr_accessor :logger, :settings
|
19
19
|
|
20
20
|
DEFAULT_OPTIONS = {
|
21
|
-
:log_file => '/tmp/sensu.log',
|
22
21
|
:config_file => '/etc/sensu/config.json',
|
23
|
-
:config_dir => '/etc/sensu/conf.d'
|
24
|
-
:validate => true,
|
25
|
-
:daemonize => false,
|
26
|
-
:pid_file => '/tmp/' + File.basename($0) + '.pid',
|
27
|
-
:service => File.basename($0)
|
22
|
+
:config_dir => '/etc/sensu/conf.d'
|
28
23
|
}
|
29
24
|
|
30
25
|
def initialize(options={})
|
31
26
|
@options = DEFAULT_OPTIONS.merge(options)
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
read_config
|
36
|
-
if @options[:validate]
|
37
|
-
validate_config
|
38
|
-
end
|
27
|
+
setup_logging
|
28
|
+
setup_settings
|
39
29
|
end
|
40
30
|
|
41
31
|
def invalid_config(message)
|
42
32
|
raise 'configuration invalid, ' + message
|
43
33
|
end
|
44
34
|
|
45
|
-
def
|
46
|
-
@
|
47
|
-
|
48
|
-
ruby_logger = case @options[:service]
|
49
|
-
when 'rake'
|
50
|
-
Logger.new(@options[:log_file])
|
51
|
-
else
|
35
|
+
def setup_logging
|
36
|
+
if @options[:log_file]
|
37
|
+
if File.writable?(@options[:log_file]) || !File.exist?(@options[:log_file]) && File.writable?(File.dirname(@options[:log_file]))
|
52
38
|
STDOUT.reopen(@options[:log_file], 'a')
|
53
39
|
STDERR.reopen(STDOUT)
|
54
40
|
STDOUT.sync = true
|
55
|
-
|
41
|
+
else
|
42
|
+
invalid_config('log file is not writable: ' + @options[:log_file])
|
56
43
|
end
|
57
|
-
else
|
58
|
-
invalid_config('log file is not writable: ' + @options[:log_file])
|
59
44
|
end
|
60
|
-
@logger
|
45
|
+
@logger = Cabin::Channel.new
|
46
|
+
log_output = File.basename($0) == 'rake' ? '/tmp/sensu_test.log' : STDOUT
|
47
|
+
@logger.subscribe(Cabin::Outputs::EmStdlibLogger.new(Logger.new(log_output)))
|
61
48
|
@logger.level = @options[:verbose] ? :debug : :info
|
62
49
|
if Signal.list.include?('USR1')
|
63
50
|
Signal.trap('USR1') do
|
64
51
|
@logger.level = @logger.level == :info ? :debug : :info
|
65
52
|
end
|
66
53
|
end
|
67
|
-
@logger
|
68
|
-
end
|
69
|
-
|
70
|
-
def read_config
|
71
|
-
if File.readable?(@options[:config_file])
|
72
|
-
begin
|
73
|
-
@settings = Hashie::Mash.new(JSON.parse(File.open(@options[:config_file], 'r').read))
|
74
|
-
rescue JSON::ParserError => error
|
75
|
-
invalid_config('configuration file (' + @options[:config_file] + ') must be valid JSON: ' + error.to_s)
|
76
|
-
end
|
77
|
-
else
|
78
|
-
invalid_config('configuration file does not exist or is not readable: ' + @options[:config_file])
|
79
|
-
end
|
80
|
-
if File.exists?(@options[:config_dir])
|
81
|
-
Dir[@options[:config_dir] + '/**/*.json'].each do |snippet_file|
|
82
|
-
begin
|
83
|
-
snippet_hash = JSON.parse(File.open(snippet_file, 'r').read)
|
84
|
-
rescue JSON::ParserError => error
|
85
|
-
invalid_config('configuration snippet file (' + snippet_file + ') must be valid JSON: ' + error.to_s)
|
86
|
-
end
|
87
|
-
merged_settings = @settings.to_hash.deep_merge(snippet_hash)
|
88
|
-
if @logger
|
89
|
-
@logger.warn('[settings] configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json)
|
90
|
-
end
|
91
|
-
@settings = Hashie::Mash.new(merged_settings)
|
92
|
-
end
|
93
|
-
end
|
94
54
|
end
|
95
55
|
|
96
|
-
def
|
56
|
+
def validate_common_settings
|
97
57
|
@settings.checks.each do |name, details|
|
98
58
|
unless details.interval.is_a?(Integer) && details.interval > 0
|
99
59
|
invalid_config('missing interval for check ' + name)
|
@@ -101,8 +61,10 @@ module Sensu
|
|
101
61
|
unless details.command.is_a?(String)
|
102
62
|
invalid_config('missing command for check ' + name)
|
103
63
|
end
|
104
|
-
unless details.
|
105
|
-
|
64
|
+
unless details.standalone
|
65
|
+
unless details.subscribers.is_a?(Array) && details.subscribers.count > 0
|
66
|
+
invalid_config('missing subscribers for check ' + name)
|
67
|
+
end
|
106
68
|
end
|
107
69
|
if details.key?('handler')
|
108
70
|
unless details.handler.is_a?(String)
|
@@ -117,7 +79,7 @@ module Sensu
|
|
117
79
|
end
|
118
80
|
end
|
119
81
|
|
120
|
-
def
|
82
|
+
def validate_server_settings
|
121
83
|
unless @settings.handlers.include?('default')
|
122
84
|
invalid_config('missing default handler')
|
123
85
|
end
|
@@ -125,28 +87,32 @@ module Sensu
|
|
125
87
|
unless details.is_a?(Hash)
|
126
88
|
invalid_config('hander details must be a hash ' + name)
|
127
89
|
end
|
128
|
-
unless details.
|
90
|
+
unless details['type'].is_a?(String)
|
129
91
|
invalid_config('missing type for handler ' + name)
|
130
92
|
end
|
131
93
|
case details['type']
|
132
94
|
when 'pipe'
|
133
|
-
unless details.
|
95
|
+
unless details.command.is_a?(String)
|
134
96
|
invalid_config('missing command for pipe handler ' + name)
|
135
97
|
end
|
136
98
|
when 'amqp'
|
137
|
-
unless details.
|
99
|
+
unless details.exchange.is_a?(Hash)
|
138
100
|
invalid_config('missing exchange details for amqp handler ' + name)
|
139
101
|
end
|
140
|
-
unless details.exchange.
|
102
|
+
unless details.exchange.name.is_a?(String)
|
141
103
|
invalid_config('missing exchange name for amqp handler ' + name)
|
142
104
|
end
|
105
|
+
when 'set'
|
106
|
+
unless details.handlers.is_a?(Array) && details.handlers.count > 0
|
107
|
+
invalid_config('missing handler set for handler ' + name)
|
108
|
+
end
|
143
109
|
else
|
144
110
|
invalid_config('unknown type for handler ' + name)
|
145
111
|
end
|
146
112
|
end
|
147
113
|
end
|
148
114
|
|
149
|
-
def
|
115
|
+
def validate_client_settings
|
150
116
|
unless @settings.client.name.is_a?(String)
|
151
117
|
invalid_config('client must have a name')
|
152
118
|
end
|
@@ -166,54 +132,80 @@ module Sensu
|
|
166
132
|
end
|
167
133
|
end
|
168
134
|
|
169
|
-
def
|
170
|
-
|
171
|
-
@logger.debug('[config] -- validating configuration')
|
172
|
-
end
|
135
|
+
def validate_settings
|
136
|
+
@logger.debug('[validate] -- validating configuration')
|
173
137
|
has_keys(%w[rabbitmq checks])
|
174
|
-
|
175
|
-
case
|
138
|
+
validate_common_settings
|
139
|
+
case File.basename($0)
|
176
140
|
when 'rake'
|
177
141
|
has_keys(%w[redis api handlers client])
|
178
|
-
|
179
|
-
|
142
|
+
validate_server_settings
|
143
|
+
validate_client_settings
|
180
144
|
when 'sensu-server'
|
181
145
|
has_keys(%w[redis handlers])
|
182
|
-
|
146
|
+
validate_server_settings
|
183
147
|
when 'sensu-api'
|
184
148
|
has_keys(%w[redis api])
|
185
149
|
when 'sensu-client'
|
186
150
|
has_keys(%w[client])
|
187
|
-
|
151
|
+
validate_client_settings
|
152
|
+
end
|
153
|
+
@logger.info('[validate] -- configuration valid -- running')
|
154
|
+
end
|
155
|
+
|
156
|
+
def setup_settings
|
157
|
+
if File.readable?(@options[:config_file])
|
158
|
+
begin
|
159
|
+
config_hash = JSON.parse(File.open(@options[:config_file], 'r').read)
|
160
|
+
rescue JSON::ParserError => error
|
161
|
+
invalid_config('configuration file (' + @options[:config_file] + ') must be valid JSON: ' + error)
|
162
|
+
end
|
163
|
+
@settings = Hashie::Mash.new(config_hash)
|
164
|
+
else
|
165
|
+
invalid_config('configuration file does not exist or is not readable: ' + @options[:config_file])
|
188
166
|
end
|
189
|
-
if @
|
190
|
-
@
|
167
|
+
if File.exists?(@options[:config_dir])
|
168
|
+
Dir[@options[:config_dir] + '/**/*.json'].each do |snippet_file|
|
169
|
+
if File.readable?(snippet_file)
|
170
|
+
begin
|
171
|
+
snippet_hash = JSON.parse(File.open(snippet_file, 'r').read)
|
172
|
+
rescue JSON::ParserError => error
|
173
|
+
invalid_config('configuration snippet file (' + snippet_file + ') must be valid JSON: ' + error)
|
174
|
+
end
|
175
|
+
merged_settings = @settings.to_hash.deep_merge(snippet_hash)
|
176
|
+
@logger.warn('[settings] configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json)
|
177
|
+
@settings = Hashie::Mash.new(merged_settings)
|
178
|
+
else
|
179
|
+
invalid_config('configuration snippet file is not readable: ' + snippet_file)
|
180
|
+
end
|
181
|
+
end
|
191
182
|
end
|
183
|
+
validate_settings
|
192
184
|
end
|
193
185
|
|
194
186
|
def self.read_arguments(arguments)
|
195
187
|
options = Hash.new
|
196
188
|
optparse = OptionParser.new do |opts|
|
197
|
-
opts.on('-h', '--help', 'Display this
|
189
|
+
opts.on('-h', '--help', 'Display this message') do
|
198
190
|
puts opts
|
199
191
|
exit
|
200
192
|
end
|
201
|
-
opts.on('-c', '--config FILE', 'Sensu JSON config FILE
|
193
|
+
opts.on('-c', '--config FILE', 'Sensu JSON config FILE. Default is /etc/sensu/config.json') do |file|
|
202
194
|
options[:config_file] = file
|
203
195
|
end
|
204
|
-
opts.on('-d', '--config_dir DIR', '
|
196
|
+
opts.on('-d', '--config_dir DIR', 'DIR for supplemental Sensu JSON config files. Default is /etc/sensu/conf.d/') do |dir|
|
205
197
|
options[:config_dir] = dir
|
206
198
|
end
|
207
|
-
opts.on('-l', '--log FILE', '
|
199
|
+
opts.on('-l', '--log FILE', 'Log to a given FILE. Default is to log to stdout') do |file|
|
208
200
|
options[:log_file] = file
|
209
201
|
end
|
210
|
-
opts.on('-v', '--verbose', 'Enable verbose logging
|
202
|
+
opts.on('-v', '--verbose', 'Enable verbose logging') do
|
211
203
|
options[:verbose] = true
|
212
204
|
end
|
213
|
-
opts.on('-b', '--background', 'Fork into
|
205
|
+
opts.on('-b', '--background', 'Fork into the background') do
|
214
206
|
options[:daemonize] = true
|
215
207
|
end
|
216
|
-
opts.on('-p', '--pid_file FILE', '
|
208
|
+
opts.on('-p', '--pid_file FILE', 'Write the PID to a given FILE') do |file|
|
217
209
|
options[:pid_file] = file
|
218
210
|
end
|
219
211
|
end
|
data/lib/sensu/patches/ruby.rb
CHANGED
@@ -33,7 +33,13 @@ class Hash
|
|
33
33
|
|
34
34
|
def deep_merge(hash)
|
35
35
|
merger = proc do |key, value1, value2|
|
36
|
-
value1.is_a?(Hash) && value2.is_a?(Hash)
|
36
|
+
if value1.is_a?(Hash) && value2.is_a?(Hash)
|
37
|
+
value1.merge(value2, &merger)
|
38
|
+
elsif value1.is_a?(Array) && value2.is_a?(Array)
|
39
|
+
value1.concat(value2).uniq
|
40
|
+
else
|
41
|
+
value2
|
42
|
+
end
|
37
43
|
end
|
38
44
|
self.merge(hash, &merger)
|
39
45
|
end
|
data/lib/sensu/server.rb
CHANGED
@@ -35,9 +35,10 @@ module Sensu
|
|
35
35
|
|
36
36
|
def initialize(options={})
|
37
37
|
config = Sensu::Config.new(options)
|
38
|
+
@logger = config.logger
|
38
39
|
@settings = config.settings
|
39
|
-
@logger = config.logger || config.open_log
|
40
40
|
@timers = Array.new
|
41
|
+
@handlers_in_progress = 0
|
41
42
|
end
|
42
43
|
|
43
44
|
def setup_redis
|
@@ -72,14 +73,21 @@ module Sensu
|
|
72
73
|
else
|
73
74
|
['default']
|
74
75
|
end
|
76
|
+
handlers.map! do |handler|
|
77
|
+
@settings.handlers[handler]['type'] == 'set' ? @settings.handlers[handler].handlers : handler
|
78
|
+
end
|
79
|
+
handlers.flatten!
|
80
|
+
handlers.uniq!
|
75
81
|
report = proc do |output|
|
76
82
|
output.split(/\n+/).each do |line|
|
77
83
|
@logger.info('[handler] -- ' + line)
|
78
84
|
end
|
85
|
+
@handlers_in_progress -= 1
|
79
86
|
end
|
80
87
|
handlers.each do |handler|
|
81
88
|
if @settings.handlers.key?(handler)
|
82
89
|
@logger.debug('[event] -- handling event -- ' + [handler, event.client.name, event.check.name].join(' -- '))
|
90
|
+
@handlers_in_progress += 1
|
83
91
|
details = @settings.handlers[handler]
|
84
92
|
case details['type']
|
85
93
|
when 'pipe'
|
@@ -93,7 +101,7 @@ module Sensu
|
|
93
101
|
output = io.read
|
94
102
|
end
|
95
103
|
rescue Errno::EPIPE => error
|
96
|
-
output = handler + ' -- broken pipe: ' + error
|
104
|
+
output = handler + ' -- broken pipe: ' + error
|
97
105
|
end
|
98
106
|
end
|
99
107
|
output
|
@@ -106,6 +114,10 @@ module Sensu
|
|
106
114
|
@logger.debug('[event] -- publishing event to rabbitmq exchange -- ' + [exchange, event.client.name, event.check.name].join(' -- '))
|
107
115
|
payload = details.send_only_check_output ? event.check.output : event.to_json
|
108
116
|
@amq.method(exchange_type).call(exchange, exchange_options).publish(payload)
|
117
|
+
@handlers_in_progress -= 1
|
118
|
+
when 'set'
|
119
|
+
@logger.warn('[event] -- handler sets cannot be nested -- ' + handler)
|
120
|
+
@handlers_in_progress -= 1
|
109
121
|
end
|
110
122
|
else
|
111
123
|
@logger.warn('[event] -- unknown handler -- ' + handler)
|
@@ -214,20 +226,13 @@ module Sensu
|
|
214
226
|
stagger = options[:test] ? 0 : 7
|
215
227
|
@settings.checks.each_with_index do |(name, details), index|
|
216
228
|
check_request = Hashie::Mash.new({:name => name})
|
217
|
-
unless details.publish == false
|
229
|
+
unless details.publish == false || details.standalone
|
218
230
|
@timers << EM::Timer.new(stagger*index) do
|
219
|
-
details.subscribers.each do |
|
220
|
-
if target.is_a?(Hash)
|
221
|
-
@logger.debug('[publisher] -- check requires matching -- ' + target.to_hash.to_s + ' -- ' + name)
|
222
|
-
check_request.matching = target
|
223
|
-
exchange = 'uchiwa'
|
224
|
-
else
|
225
|
-
exchange = target
|
226
|
-
end
|
231
|
+
details.subscribers.each do |exchange|
|
227
232
|
interval = options[:test] ? 0.5 : details.interval
|
228
233
|
@timers << EM::PeriodicTimer.new(interval) do
|
229
|
-
check_request.issued = Time.now.to_i
|
230
234
|
@logger.info('[publisher] -- publishing check request -- ' + name + ' -- ' + exchange)
|
235
|
+
check_request.issued = Time.now.to_i
|
231
236
|
@amq.fanout(exchange).publish(check_request.to_json)
|
232
237
|
end
|
233
238
|
end
|
@@ -333,9 +338,19 @@ module Sensu
|
|
333
338
|
end
|
334
339
|
|
335
340
|
def stop_reactor
|
336
|
-
|
337
|
-
|
338
|
-
EM::
|
341
|
+
EM::Timer.new(1) do
|
342
|
+
@logger.info('[stop] -- completing handlers in progress')
|
343
|
+
complete_in_progress = EM::tick_loop do
|
344
|
+
if @handlers_in_progress == 0
|
345
|
+
:stop
|
346
|
+
end
|
347
|
+
end
|
348
|
+
complete_in_progress.on_stop do
|
349
|
+
@logger.warn('[stop] -- stopping reactor')
|
350
|
+
EM::PeriodicTimer.new(0.25) do
|
351
|
+
EM::stop_event_loop
|
352
|
+
end
|
353
|
+
end
|
339
354
|
end
|
340
355
|
end
|
341
356
|
|
@@ -344,10 +359,10 @@ module Sensu
|
|
344
359
|
@timers.each do |timer|
|
345
360
|
timer.cancel
|
346
361
|
end
|
362
|
+
@logger.warn('[stop] -- unsubscribing from keepalives')
|
347
363
|
@keepalive_queue.unsubscribe do
|
348
|
-
@logger.warn('[stop] --
|
364
|
+
@logger.warn('[stop] -- unsubscribing from results')
|
349
365
|
@result_queue.unsubscribe do
|
350
|
-
@logger.warn('[stop] -- unsubscribed from rabbitmq queue -- results')
|
351
366
|
if @is_master
|
352
367
|
@redis.del('lock:master').callback do
|
353
368
|
@logger.warn('[stop] -- resigned as master')
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sensu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 31098113
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
|
9
|
+
- 2
|
10
|
+
- beta
|
11
|
+
version: 0.9.2.beta
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Sean Porter
|
@@ -16,7 +17,7 @@ autorequire:
|
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date:
|
20
|
+
date: 2012-01-04 00:00:00 -08:00
|
20
21
|
default_executable:
|
21
22
|
dependencies:
|
22
23
|
- !ruby/object:Gem::Dependency
|
@@ -258,12 +259,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
258
259
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
260
|
none: false
|
260
261
|
requirements:
|
261
|
-
- - "
|
262
|
+
- - ">"
|
262
263
|
- !ruby/object:Gem::Version
|
263
|
-
hash:
|
264
|
+
hash: 25
|
264
265
|
segments:
|
265
|
-
-
|
266
|
-
|
266
|
+
- 1
|
267
|
+
- 3
|
268
|
+
- 1
|
269
|
+
version: 1.3.1
|
267
270
|
requirements: []
|
268
271
|
|
269
272
|
rubyforge_project:
|