sensu 0.9.2 → 0.9.3.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sensu.rb +1 -1
- data/lib/sensu/client.rb +30 -25
- data/lib/sensu/config.rb +3 -0
- data/lib/sensu/patches/ruby.rb +10 -10
- data/lib/sensu/server.rb +71 -66
- metadata +12 -9
data/lib/sensu.rb
CHANGED
data/lib/sensu/client.rb
CHANGED
@@ -10,6 +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 = 16
|
13
14
|
EM::run do
|
14
15
|
client.setup_amqp
|
15
16
|
client.setup_keepalives
|
@@ -150,13 +151,13 @@ module Sensu
|
|
150
151
|
|
151
152
|
def setup_standalone(options={})
|
152
153
|
@logger.debug('[standalone] -- setup standalone')
|
153
|
-
|
154
|
+
standalone_check_count = 0
|
154
155
|
@settings.checks.each do |name, details|
|
155
156
|
if details.standalone
|
156
|
-
|
157
|
-
check = Hashie::Mash.new(details.merge(
|
157
|
+
standalone_check_count += 1
|
158
|
+
check = Hashie::Mash.new(details.merge(:name => name))
|
158
159
|
stagger = options[:test] ? 0 : 7
|
159
|
-
@timers << EM::Timer.new(stagger*
|
160
|
+
@timers << EM::Timer.new(stagger*standalone_check_count) do
|
160
161
|
interval = options[:test] ? 0.5 : details.interval
|
161
162
|
@timers << EM::PeriodicTimer.new(interval) do
|
162
163
|
check.issued = Time.now.to_i
|
@@ -207,29 +208,33 @@ module Sensu
|
|
207
208
|
attr_accessor :settings, :logger, :amq
|
208
209
|
|
209
210
|
def receive_data(data)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
211
|
+
if data == 'ping'
|
212
|
+
@logger.debug('[socket] -- received ping')
|
213
|
+
send_data('pong')
|
214
|
+
else
|
215
|
+
@logger.debug('[socket] -- received data -- ' + data)
|
216
|
+
begin
|
217
|
+
check = Hashie::Mash.new(JSON.parse(data))
|
218
|
+
validates = %w[name output].all? do |key|
|
219
|
+
check[key].is_a?(String)
|
220
|
+
end
|
221
|
+
check.status ||= 0
|
222
|
+
if validates && check.status.is_a?(Integer)
|
223
|
+
@logger.info('[socket] -- publishing check result -- ' + [check.name, check.status, check.output].join(' -- '))
|
224
|
+
@amq.queue('results').publish({
|
225
|
+
:client => @settings.client.name,
|
226
|
+
:check => check.to_hash
|
227
|
+
}.to_json)
|
228
|
+
send_data('ok')
|
229
|
+
else
|
230
|
+
@logger.warn('[socket] -- check name and output must be strings, status defaults to 0 -- e.g. {"name": "x", "output": "y"}')
|
231
|
+
send_data('invalid')
|
232
|
+
end
|
233
|
+
rescue JSON::ParserError => error
|
234
|
+
@logger.warn('[socket] -- check result must be valid JSON: ' + error.to_s)
|
235
|
+
send_data('invalid')
|
224
236
|
end
|
225
|
-
rescue JSON::ParserError => error
|
226
|
-
@logger.warn('[socket] -- check result must be valid JSON: ' + error.to_s)
|
227
237
|
end
|
228
|
-
close_connection
|
229
|
-
end
|
230
|
-
|
231
|
-
def unbind
|
232
|
-
@logger.debug('[socket] -- connection closed')
|
233
238
|
end
|
234
239
|
end
|
235
240
|
end
|
data/lib/sensu/config.rb
CHANGED
@@ -55,6 +55,9 @@ module Sensu
|
|
55
55
|
|
56
56
|
def validate_common_settings
|
57
57
|
@settings.checks.each do |name, details|
|
58
|
+
if details.key?('status') || details.key?('output')
|
59
|
+
invalid_config('reserved key (status or output) defined in check ' + name)
|
60
|
+
end
|
58
61
|
unless details.interval.is_a?(Integer) && details.interval > 0
|
59
62
|
invalid_config('missing interval for check ' + name)
|
60
63
|
end
|
data/lib/sensu/patches/ruby.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
class Array
|
2
|
+
def deep_merge(other_array, &merger)
|
3
|
+
concat(other_array).uniq
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
1
7
|
class Hash
|
2
8
|
def symbolize_keys(item=self)
|
3
9
|
case item
|
@@ -31,17 +37,11 @@ class Hash
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
|
-
def deep_merge(
|
35
|
-
merger
|
36
|
-
|
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
|
40
|
+
def deep_merge(other_hash, &merger)
|
41
|
+
merger ||= proc do |key, oldval, newval|
|
42
|
+
oldval.deep_merge(newval, &merger) rescue newval
|
43
43
|
end
|
44
|
-
|
44
|
+
merge(other_hash, &merger)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
data/lib/sensu/server.rb
CHANGED
@@ -91,22 +91,20 @@ module Sensu
|
|
91
91
|
details = @settings.handlers[handler]
|
92
92
|
case details['type']
|
93
93
|
when 'pipe'
|
94
|
-
|
95
|
-
output = ''
|
94
|
+
execute = proc do
|
96
95
|
Bundler.with_clean_env do
|
97
96
|
begin
|
98
97
|
IO.popen(details.command + ' 2>&1', 'r+') do |io|
|
99
98
|
io.write(event.to_json)
|
100
99
|
io.close_write
|
101
|
-
|
100
|
+
io.read
|
102
101
|
end
|
103
102
|
rescue Errno::EPIPE => error
|
104
|
-
|
103
|
+
handler + ' -- broken pipe: ' + error.to_s
|
105
104
|
end
|
106
105
|
end
|
107
|
-
output
|
108
106
|
end
|
109
|
-
EM::defer(
|
107
|
+
EM::defer(execute, report)
|
110
108
|
when 'amqp'
|
111
109
|
exchange = details.exchange.name
|
112
110
|
exchange_type = details.exchange.key?('type') ? details.exchange['type'].to_sym : :direct
|
@@ -130,79 +128,86 @@ module Sensu
|
|
130
128
|
@redis.get('client:' + result.client).callback do |client_json|
|
131
129
|
unless client_json.nil?
|
132
130
|
client = Hashie::Mash.new(JSON.parse(client_json))
|
133
|
-
check = @settings.checks.key?(result.check.name) ?
|
134
|
-
event = Hashie::Mash.new(
|
131
|
+
check = @settings.checks.key?(result.check.name) ? @settings.checks[result.check.name].merge(result.check) : result.check
|
132
|
+
event = Hashie::Mash.new(
|
135
133
|
:client => client,
|
136
134
|
:check => check,
|
137
135
|
:occurrences => 1
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
136
|
+
)
|
137
|
+
history_key = 'history:' + client.name + ':' + check.name
|
138
|
+
@redis.rpush(history_key, check.status).callback do
|
139
|
+
@redis.lrange(history_key, -21, -1).callback do |history|
|
140
|
+
event.check.history = history
|
141
|
+
total_state_change = 0
|
142
|
+
unless history.count < 21
|
143
|
+
state_changes = 0
|
144
|
+
change_weight = 0.8
|
145
|
+
history.each do |status|
|
146
|
+
previous_status ||= status
|
147
|
+
unless status == previous_status
|
148
|
+
state_changes += change_weight
|
149
|
+
end
|
150
|
+
change_weight += 0.02
|
151
|
+
previous_status = status
|
152
|
+
end
|
153
|
+
total_state_change = (state_changes.fdiv(20) * 100).to_i
|
154
|
+
@redis.lpop(history_key)
|
155
|
+
end
|
156
|
+
@redis.hget('events:' + client.name, check.name).callback do |event_json|
|
157
|
+
previous_occurrence = event_json ? Hashie::Mash.new(JSON.parse(event_json)) : false
|
158
|
+
is_flapping = false
|
159
|
+
if check.key?('low_flap_threshold') && check.key?('high_flap_threshold')
|
160
|
+
was_flapping = previous_occurrence ? previous_occurrence.flapping : false
|
161
|
+
is_flapping = case
|
162
|
+
when total_state_change >= check.high_flap_threshold
|
163
|
+
true
|
164
|
+
when was_flapping && total_state_change <= check.low_flap_threshold
|
165
|
+
false
|
166
|
+
else
|
167
|
+
was_flapping
|
157
168
|
end
|
158
|
-
total_state_change = (state_changes.fdiv(20) * 100).to_i
|
159
|
-
@redis.lpop(history_key)
|
160
169
|
end
|
161
|
-
|
162
|
-
previous_occurrence
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
170
|
+
if check.status != 0
|
171
|
+
if previous_occurrence && check.status == previous_occurrence.status
|
172
|
+
event.occurrences = previous_occurrence.occurrences += 1
|
173
|
+
end
|
174
|
+
@redis.hset('events:' + client.name, check.name, {
|
175
|
+
:status => check.status,
|
176
|
+
:output => check.output,
|
177
|
+
:flapping => is_flapping,
|
178
|
+
:occurrences => event.occurrences
|
179
|
+
}.to_json).callback do
|
180
|
+
unless check.handle == false
|
181
|
+
event.check.flapping = is_flapping
|
182
|
+
event.action = 'create'
|
183
|
+
handle_event(event)
|
171
184
|
else
|
172
|
-
|
185
|
+
@logger.debug('[result] -- handling disabled -- ' + [client.name, check.name, check.status].join(' -- '))
|
173
186
|
end
|
174
187
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
188
|
+
elsif previous_occurrence
|
189
|
+
unless is_flapping
|
190
|
+
unless check.auto_resolve == false && !check.force_resolve
|
191
|
+
@redis.hdel('events:' + client.name, check.name).callback do
|
192
|
+
unless check.handle == false
|
193
|
+
event.action = 'resolve'
|
194
|
+
handle_event(event)
|
195
|
+
else
|
196
|
+
@logger.debug('[result] -- handling disabled -- ' + [client.name, check.name, check.status].join(' -- '))
|
183
197
|
end
|
184
198
|
end
|
185
|
-
else
|
186
|
-
@logger.debug('[result] -- check is flapping -- ' + client.name + ' -- ' + check.name)
|
187
|
-
@redis.hset('events:' + client.name, check.name, previous_occurrence.merge({'flapping' => true}).to_json)
|
188
|
-
end
|
189
|
-
elsif check.status != 0
|
190
|
-
if previous_occurrence && check.status == previous_occurrence.status
|
191
|
-
event.occurrences = previous_occurrence.occurrences += 1
|
192
199
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
:occurrences => event.occurrences
|
198
|
-
}.to_json).callback do
|
199
|
-
unless check.handle == false
|
200
|
+
else
|
201
|
+
@logger.debug('[result] -- check is flapping -- ' + [client.name, check.name, check.status].join(' -- '))
|
202
|
+
@redis.hset('events:' + client.name, check.name, previous_occurrence.merge(:flapping => true).to_json).callback do
|
203
|
+
if check['type'] == 'metric'
|
200
204
|
event.check.flapping = is_flapping
|
201
|
-
event.action = 'create'
|
202
205
|
handle_event(event)
|
203
206
|
end
|
204
207
|
end
|
205
208
|
end
|
209
|
+
elsif check['type'] == 'metric'
|
210
|
+
handle_event(event)
|
206
211
|
end
|
207
212
|
end
|
208
213
|
end
|
@@ -225,7 +230,7 @@ module Sensu
|
|
225
230
|
@logger.debug('[publisher] -- setup publisher')
|
226
231
|
stagger = options[:test] ? 0 : 7
|
227
232
|
@settings.checks.each_with_index do |(name, details), index|
|
228
|
-
check_request = Hashie::Mash.new(
|
233
|
+
check_request = Hashie::Mash.new(:name => name)
|
229
234
|
unless details.publish == false || details.standalone
|
230
235
|
@timers << EM::Timer.new(stagger*index) do
|
231
236
|
details.subscribers.each do |exchange|
|
@@ -250,13 +255,13 @@ module Sensu
|
|
250
255
|
@redis.get('client:' + client_id).callback do |client_json|
|
251
256
|
client = Hashie::Mash.new(JSON.parse(client_json))
|
252
257
|
time_since_last_keepalive = Time.now.to_i - client.timestamp
|
253
|
-
result = Hashie::Mash.new(
|
258
|
+
result = Hashie::Mash.new(
|
254
259
|
:client => client.name,
|
255
260
|
:check => {
|
256
261
|
:name => 'keepalive',
|
257
262
|
:issued => Time.now.to_i
|
258
263
|
}
|
259
|
-
|
264
|
+
)
|
260
265
|
case
|
261
266
|
when time_since_last_keepalive >= 180
|
262
267
|
result.check.status = 2
|
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: 31098117
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
|
9
|
+
- 3
|
10
|
+
- beta
|
11
|
+
version: 0.9.3.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: 2012-01-
|
20
|
+
date: 2012-01-12 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:
|