sensu 0.9.7.beta.3 → 0.9.7.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -1
- data/lib/sensu/api.rb +5 -1
- data/lib/sensu/base.rb +3 -6
- data/lib/sensu/cli.rb +2 -0
- data/lib/sensu/client.rb +66 -69
- data/lib/sensu/constants.rb +1 -1
- data/lib/sensu/logger.rb +24 -4
- data/lib/sensu/process.rb +1 -1
- data/lib/sensu/redis.rb +1 -1
- data/lib/sensu/server.rb +31 -22
- data/lib/sensu/settings.rb +7 -7
- metadata +4 -5
- data/lib/sensu/patches/ruby.rb +0 -9
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,9 @@ TCP and UDP handler types, for writing event data to sockets.
|
|
9
9
|
|
10
10
|
API resources now support singular & plural, Rails friendly.
|
11
11
|
|
12
|
+
Client safe mode, require local check definition in order to execute
|
13
|
+
a check, disable for simpler deployment (default).
|
14
|
+
|
12
15
|
### Non-backwards compatible changes
|
13
16
|
|
14
17
|
AMQP handlers can no longer use `"send_only_check_output": true`, but
|
@@ -19,6 +22,11 @@ Ruby 1.8.7-p249 is no longer supported, as the AMQP library no longer
|
|
19
22
|
does. Please use the Sensu APT/YUM packages which contain an embedded
|
20
23
|
Ruby.
|
21
24
|
|
25
|
+
Client expects check requests to contain a command, be sure to upgrade
|
26
|
+
servers prior to upgrading clients.
|
27
|
+
|
28
|
+
Check subdue options have been modified, "start" is now "begin".
|
29
|
+
|
22
30
|
### Other
|
23
31
|
|
24
32
|
Improved RabbitMQ and Redis connection recovery.
|
@@ -33,4 +41,4 @@ Improved client socket ping/pong.
|
|
33
41
|
|
34
42
|
Strict dependency version locking.
|
35
43
|
|
36
|
-
Adjusted logging level for metric
|
44
|
+
Adjusted logging level for metric events.
|
data/lib/sensu/api.rb
CHANGED
@@ -18,7 +18,7 @@ module Sensu
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def bootstrap(options={})
|
21
|
-
$logger =
|
21
|
+
$logger = Sensu::Logger.get
|
22
22
|
base = Sensu::Base.new(options)
|
23
23
|
$settings = base.settings
|
24
24
|
if $settings[:api][:user] && $settings[:api][:password]
|
@@ -62,10 +62,14 @@ module Sensu
|
|
62
62
|
exit 2
|
63
63
|
end
|
64
64
|
$rabbitmq = AMQP.connect($settings[:rabbitmq], :on_tcp_connection_failure => connection_failure)
|
65
|
+
$rabbitmq.logger = Sensu::NullLogger.get
|
65
66
|
$rabbitmq.on_tcp_connection_loss do |connection, settings|
|
66
67
|
$logger.warn('reconnecting to rabbitmq')
|
67
68
|
connection.reconnect(false, 10)
|
68
69
|
end
|
70
|
+
$rabbitmq.on_skipped_heartbeats do
|
71
|
+
$logger.warn('skipped rabbitmq heartbeat')
|
72
|
+
end
|
69
73
|
$amq = AMQP::Channel.new($rabbitmq)
|
70
74
|
$amq.auto_recovery = true
|
71
75
|
end
|
data/lib/sensu/base.rb
CHANGED
@@ -2,15 +2,11 @@ require 'rubygems'
|
|
2
2
|
|
3
3
|
gem 'eventmachine', '1.0.0.rc.4'
|
4
4
|
|
5
|
-
require 'optparse'
|
6
5
|
require 'json'
|
7
6
|
require 'time'
|
8
7
|
require 'uri'
|
9
|
-
require 'cabin'
|
10
8
|
require 'amqp'
|
11
9
|
|
12
|
-
require File.join(File.dirname(__FILE__), 'patches', 'ruby')
|
13
|
-
|
14
10
|
require File.join(File.dirname(__FILE__), 'constants')
|
15
11
|
require File.join(File.dirname(__FILE__), 'cli')
|
16
12
|
require File.join(File.dirname(__FILE__), 'logger')
|
@@ -29,8 +25,9 @@ module Sensu
|
|
29
25
|
end
|
30
26
|
|
31
27
|
def setup_logging
|
32
|
-
logger = Sensu::Logger.new
|
33
|
-
logger.
|
28
|
+
logger = Sensu::Logger.new
|
29
|
+
logger.level = @options[:verbose] ? :debug : @options[:log_level] || :info
|
30
|
+
logger.reopen(@options[:log_file])
|
34
31
|
logger.setup_traps
|
35
32
|
end
|
36
33
|
|
data/lib/sensu/cli.rb
CHANGED
data/lib/sensu/client.rb
CHANGED
@@ -12,7 +12,7 @@ module Sensu
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize(options={})
|
15
|
-
@logger =
|
15
|
+
@logger = Sensu::Logger.get
|
16
16
|
base = Sensu::Base.new(options)
|
17
17
|
@settings = base.settings
|
18
18
|
@timers = Array.new
|
@@ -31,10 +31,15 @@ module Sensu
|
|
31
31
|
exit 2
|
32
32
|
end
|
33
33
|
@rabbitmq = AMQP.connect(@settings[:rabbitmq], :on_tcp_connection_failure => connection_failure)
|
34
|
+
@rabbitmq.logger = Sensu::NullLogger.get
|
34
35
|
@rabbitmq.on_tcp_connection_loss do |connection, settings|
|
35
36
|
@logger.warn('reconnecting to rabbitmq')
|
36
37
|
connection.reconnect(false, 10)
|
37
38
|
end
|
39
|
+
@rabbitmq.on_skipped_heartbeats do
|
40
|
+
@logger.warn('skipped rabbitmq heartbeat')
|
41
|
+
@logger.warn('rabbitmq heartbeats are not recommended for clients')
|
42
|
+
end
|
38
43
|
@amq = AMQP::Channel.new(@rabbitmq)
|
39
44
|
@amq.auto_recovery = true
|
40
45
|
end
|
@@ -62,13 +67,7 @@ module Sensu
|
|
62
67
|
:client => @settings[:client][:name],
|
63
68
|
:check => check
|
64
69
|
}
|
65
|
-
|
66
|
-
if @settings.check_exists?(check[:name])
|
67
|
-
if @settings[:checks][check[:name]][:type] == 'metric'
|
68
|
-
log_level = :debug
|
69
|
-
end
|
70
|
-
end
|
71
|
-
@logger.send(log_level, 'publishing check result', {
|
70
|
+
@logger.info('publishing check result', {
|
72
71
|
:payload => payload
|
73
72
|
})
|
74
73
|
@amq.queue('results').publish(payload.to_json)
|
@@ -78,76 +77,62 @@ module Sensu
|
|
78
77
|
@logger.debug('attempting to execute check', {
|
79
78
|
:check => check
|
80
79
|
})
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
95
|
-
if substitute.nil?
|
96
|
-
unmatched_tokens.push(token)
|
97
|
-
end
|
98
|
-
substitute
|
80
|
+
unless @checks_in_progress.include?(check[:name])
|
81
|
+
@logger.debug('executing check', {
|
82
|
+
:check => check
|
83
|
+
})
|
84
|
+
@checks_in_progress.push(check[:name])
|
85
|
+
unmatched_tokens = Array.new
|
86
|
+
command = check[:command].gsub(/:::(.*?):::/) do
|
87
|
+
token = $1.to_s
|
88
|
+
matched = token.split('.').inject(@settings[:client]) do |client, attribute|
|
89
|
+
client[attribute].nil? ? break : client[attribute]
|
90
|
+
end
|
91
|
+
if matched.nil?
|
92
|
+
unmatched_tokens.push(token)
|
99
93
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
check[:status] = $?.exitstatus
|
109
|
-
rescue => error
|
110
|
-
@logger.warn('unexpected error', {
|
111
|
-
:error => error.to_s
|
112
|
-
})
|
113
|
-
check[:output] = 'Unexpected error: ' + error.to_s
|
114
|
-
check[:status] = 2
|
94
|
+
matched
|
95
|
+
end
|
96
|
+
if unmatched_tokens.empty?
|
97
|
+
execute = Proc.new do
|
98
|
+
started = Time.now.to_f
|
99
|
+
begin
|
100
|
+
IO.popen(command + ' 2>&1') do |io|
|
101
|
+
check[:output] = io.read
|
115
102
|
end
|
116
|
-
check[:
|
117
|
-
|
103
|
+
check[:status] = $?.exitstatus
|
104
|
+
rescue => error
|
105
|
+
@logger.warn('unexpected error', {
|
106
|
+
:error => error.to_s
|
107
|
+
})
|
108
|
+
check[:output] = 'Unexpected error: ' + error.to_s
|
109
|
+
check[:status] = 2
|
118
110
|
end
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
111
|
+
check[:duration] = ('%.3f' % (Time.now.to_f - started)).to_f
|
112
|
+
check
|
113
|
+
end
|
114
|
+
publish = Proc.new do |check|
|
115
|
+
unless check[:status].nil?
|
116
|
+
publish_result(check)
|
124
117
|
end
|
125
|
-
EM::defer(execute, publish)
|
126
|
-
else
|
127
|
-
@logger.warn('missing client attributes', {
|
128
|
-
:check => check,
|
129
|
-
:unmatched_tokens => unmatched_tokens
|
130
|
-
})
|
131
|
-
check[:output] = 'Missing client attributes: ' + unmatched_tokens.join(', ')
|
132
|
-
check[:status] = 3
|
133
|
-
check[:handle] = false
|
134
|
-
publish_result(check)
|
135
118
|
@checks_in_progress.delete(check[:name])
|
136
119
|
end
|
120
|
+
EM::defer(execute, publish)
|
137
121
|
else
|
138
|
-
@logger.warn('
|
139
|
-
:check => check
|
122
|
+
@logger.warn('missing client attributes', {
|
123
|
+
:check => check,
|
124
|
+
:unmatched_tokens => unmatched_tokens
|
140
125
|
})
|
126
|
+
check[:output] = 'Missing client attributes: ' + unmatched_tokens.join(', ')
|
127
|
+
check[:status] = 3
|
128
|
+
check[:handle] = false
|
129
|
+
publish_result(check)
|
130
|
+
@checks_in_progress.delete(check[:name])
|
141
131
|
end
|
142
132
|
else
|
143
|
-
@logger.warn('
|
133
|
+
@logger.warn('previous check execution in progress', {
|
144
134
|
:check => check
|
145
135
|
})
|
146
|
-
check[:output] = 'Unknown check'
|
147
|
-
check[:status] = 3
|
148
|
-
check[:handle] = false
|
149
|
-
publish_result(check)
|
150
|
-
@checks_in_progress.delete(check[:name])
|
151
136
|
end
|
152
137
|
end
|
153
138
|
|
@@ -159,8 +144,7 @@ module Sensu
|
|
159
144
|
@logger.debug('binding queue to exchange', {
|
160
145
|
:queue => @uniq_queue_name,
|
161
146
|
:exchange => {
|
162
|
-
:name => exchange_name
|
163
|
-
:type => 'fanout'
|
147
|
+
:name => exchange_name
|
164
148
|
}
|
165
149
|
})
|
166
150
|
@check_request_queue.bind(@amq.fanout(exchange_name))
|
@@ -171,7 +155,20 @@ module Sensu
|
|
171
155
|
@logger.info('received check request', {
|
172
156
|
:check => check
|
173
157
|
})
|
174
|
-
|
158
|
+
if @settings.check_exists?(check[:name])
|
159
|
+
check.merge!(@settings[:checks][check[:name]])
|
160
|
+
execute_check(check)
|
161
|
+
elsif @settings[:client][:safe_mode]
|
162
|
+
@logger.warn('check is not defined', {
|
163
|
+
:check => check
|
164
|
+
})
|
165
|
+
check[:output] = 'Check is not defined (safe mode)'
|
166
|
+
check[:status] = 3
|
167
|
+
check[:handle] = false
|
168
|
+
publish_result(check)
|
169
|
+
else
|
170
|
+
execute_check(check)
|
171
|
+
end
|
175
172
|
rescue JSON::ParserError => error
|
176
173
|
@logger.warn('check request payload must be valid json', {
|
177
174
|
:payload => payload,
|
data/lib/sensu/constants.rb
CHANGED
data/lib/sensu/logger.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
require 'cabin'
|
2
|
+
|
1
3
|
module Sensu
|
2
4
|
class Logger
|
3
|
-
def initialize
|
5
|
+
def initialize
|
4
6
|
@logger = Cabin::Channel.get
|
5
7
|
STDOUT.sync = true
|
8
|
+
STDERR.reopen(STDOUT)
|
6
9
|
@logger.subscribe(STDOUT)
|
7
|
-
|
8
|
-
|
10
|
+
end
|
11
|
+
|
12
|
+
def level=(log_level)
|
13
|
+
@logger.level = log_level
|
9
14
|
end
|
10
15
|
|
11
16
|
def reopen(file=nil)
|
@@ -14,8 +19,8 @@ module Sensu
|
|
14
19
|
@log_file = file
|
15
20
|
if File.writable?(file) || !File.exist?(file) && File.writable?(File.dirname(file))
|
16
21
|
STDOUT.reopen(file, 'a')
|
17
|
-
STDERR.reopen(STDOUT)
|
18
22
|
STDOUT.sync = true
|
23
|
+
STDERR.reopen(STDOUT)
|
19
24
|
else
|
20
25
|
@logger.error('log file is not writable', {
|
21
26
|
:log_file => file
|
@@ -36,5 +41,20 @@ module Sensu
|
|
36
41
|
end
|
37
42
|
end
|
38
43
|
end
|
44
|
+
|
45
|
+
def self.get
|
46
|
+
Cabin::Channel.get
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class NullLogger
|
51
|
+
[:debug, :info, :warn, :error, :fatal].each do |method|
|
52
|
+
define_method(method) do |*arguments|
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get
|
57
|
+
self.new
|
58
|
+
end
|
39
59
|
end
|
40
60
|
end
|
data/lib/sensu/process.rb
CHANGED
data/lib/sensu/redis.rb
CHANGED
data/lib/sensu/server.rb
CHANGED
@@ -14,7 +14,7 @@ module Sensu
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def initialize(options={})
|
17
|
-
@logger =
|
17
|
+
@logger = Sensu::Logger.get
|
18
18
|
base = Sensu::Base.new(options)
|
19
19
|
@settings = base.settings
|
20
20
|
@timers = Array.new
|
@@ -59,12 +59,16 @@ module Sensu
|
|
59
59
|
exit 2
|
60
60
|
end
|
61
61
|
@rabbitmq = AMQP.connect(@settings[:rabbitmq], :on_tcp_connection_failure => connection_failure)
|
62
|
+
@rabbitmq.logger = Sensu::NullLogger.get
|
62
63
|
@rabbitmq.on_tcp_connection_loss do |connection, settings|
|
63
64
|
@logger.warn('reconnecting to rabbitmq')
|
64
65
|
resign_as_master do
|
65
66
|
connection.reconnect(false, 10)
|
66
67
|
end
|
67
68
|
end
|
69
|
+
@rabbitmq.on_skipped_heartbeats do
|
70
|
+
@logger.warn('skipped rabbitmq heartbeat')
|
71
|
+
end
|
68
72
|
@amq = AMQP::Channel.new(@rabbitmq)
|
69
73
|
@amq.auto_recovery = true
|
70
74
|
end
|
@@ -86,17 +90,17 @@ module Sensu
|
|
86
90
|
def check_subdued?(check, subdue_at)
|
87
91
|
subdue = false
|
88
92
|
if check[:subdue].is_a?(Hash)
|
89
|
-
if check[:subdue].has_key?(:
|
90
|
-
|
93
|
+
if check[:subdue].has_key?(:begin) && check[:subdue].has_key?(:end)
|
94
|
+
begin_time = Time.parse(check[:subdue][:begin])
|
91
95
|
end_time = Time.parse(check[:subdue][:end])
|
92
|
-
if end_time <
|
96
|
+
if end_time < begin_time
|
93
97
|
if Time.now < end_time
|
94
|
-
|
98
|
+
begin_time = Time.parse('12:00:00 AM')
|
95
99
|
else
|
96
100
|
end_time = Time.parse('11:59:59 PM')
|
97
101
|
end
|
98
102
|
end
|
99
|
-
if Time.now >=
|
103
|
+
if Time.now >= begin_time && Time.now <= end_time
|
100
104
|
subdue = true
|
101
105
|
end
|
102
106
|
end
|
@@ -108,13 +112,12 @@ module Sensu
|
|
108
112
|
end
|
109
113
|
if subdue && check[:subdue].has_key?(:exceptions)
|
110
114
|
subdue = check[:subdue][:exceptions].none? do |exception|
|
111
|
-
Time.now >= Time.parse(exception[:
|
115
|
+
Time.now >= Time.parse(exception[:begin]) && Time.now <= Time.parse(exception[:end])
|
112
116
|
end
|
113
117
|
end
|
114
118
|
end
|
115
119
|
if subdue
|
116
|
-
(
|
117
|
-
(check[:subdue].has_key?(:at) && check[:subdue][:at].to_sym == subdue_at)
|
120
|
+
subdue_at == (check[:subdue][:at] || 'handler').to_sym
|
118
121
|
else
|
119
122
|
false
|
120
123
|
end
|
@@ -191,7 +194,7 @@ module Sensu
|
|
191
194
|
})
|
192
195
|
end
|
193
196
|
else
|
194
|
-
@logger.
|
197
|
+
@logger.warn('unknown mutator', {
|
195
198
|
:mutator => {
|
196
199
|
:name => handler[:mutator]
|
197
200
|
}
|
@@ -208,7 +211,8 @@ module Sensu
|
|
208
211
|
unless check_subdued?(event[:check], :handler)
|
209
212
|
handlers = check_handlers(event[:check])
|
210
213
|
handlers.each do |handler|
|
211
|
-
|
214
|
+
log_level = event[:check][:type] == 'metric' ? :debug : :info
|
215
|
+
@logger.send(log_level, 'handling event', {
|
212
216
|
:event => event,
|
213
217
|
:handler => handler
|
214
218
|
})
|
@@ -416,6 +420,21 @@ module Sensu
|
|
416
420
|
end
|
417
421
|
end
|
418
422
|
|
423
|
+
def publish_check_request(check)
|
424
|
+
payload = {
|
425
|
+
:name => check[:name],
|
426
|
+
:command => check[:command],
|
427
|
+
:issued => Time.now.to_i
|
428
|
+
}
|
429
|
+
@logger.info('publishing check request', {
|
430
|
+
:payload => payload,
|
431
|
+
:subscribers => check[:subscribers]
|
432
|
+
})
|
433
|
+
check[:subscribers].uniq.each do |exchange_name|
|
434
|
+
@amq.fanout(exchange_name).publish(payload.to_json)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
419
438
|
def setup_publisher
|
420
439
|
@logger.debug('scheduling check requests')
|
421
440
|
check_count = 0
|
@@ -427,17 +446,7 @@ module Sensu
|
|
427
446
|
interval = testing? ? 0.5 : check[:interval]
|
428
447
|
@master_timers << EM::PeriodicTimer.new(interval) do
|
429
448
|
unless check_subdued?(check, :publisher)
|
430
|
-
|
431
|
-
:name => check[:name],
|
432
|
-
:issued => Time.now.to_i
|
433
|
-
}
|
434
|
-
@logger.info('publishing check request', {
|
435
|
-
:payload => payload,
|
436
|
-
:subscribers => check[:subscribers]
|
437
|
-
})
|
438
|
-
check[:subscribers].uniq.each do |exchange_name|
|
439
|
-
@amq.fanout(exchange_name).publish(payload.to_json)
|
440
|
-
end
|
449
|
+
publish_check_request(check)
|
441
450
|
end
|
442
451
|
end
|
443
452
|
end
|
data/lib/sensu/settings.rb
CHANGED
@@ -3,7 +3,7 @@ module Sensu
|
|
3
3
|
attr_reader :indifferent_access, :loaded_env, :loaded_files
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
@logger =
|
6
|
+
@logger = Sensu::Logger.get
|
7
7
|
@settings = Hash.new
|
8
8
|
[:checks, :handlers, :mutators].each do |key|
|
9
9
|
@settings[key] = Hash.new
|
@@ -224,12 +224,12 @@ module Sensu
|
|
224
224
|
:check => check
|
225
225
|
})
|
226
226
|
end
|
227
|
-
if check[:subdue].has_key?(:
|
227
|
+
if check[:subdue].has_key?(:begin) || check[:subdue].has_key?(:end)
|
228
228
|
begin
|
229
|
-
Time.parse(check[:subdue][:
|
229
|
+
Time.parse(check[:subdue][:begin])
|
230
230
|
Time.parse(check[:subdue][:end])
|
231
231
|
rescue
|
232
|
-
invalid('check subdue
|
232
|
+
invalid('check subdue begin & end times must be valid', {
|
233
233
|
:check => check
|
234
234
|
})
|
235
235
|
end
|
@@ -261,12 +261,12 @@ module Sensu
|
|
261
261
|
:check => check
|
262
262
|
})
|
263
263
|
end
|
264
|
-
if exception.has_key?(:
|
264
|
+
if exception.has_key?(:begin) || exception.has_key?(:end)
|
265
265
|
begin
|
266
|
-
Time.parse(exception[:
|
266
|
+
Time.parse(exception[:begin])
|
267
267
|
Time.parse(exception[:end])
|
268
268
|
rescue
|
269
|
-
invalid('check subdue exception
|
269
|
+
invalid('check subdue exception begin & end times must be valid', {
|
270
270
|
:check => check
|
271
271
|
})
|
272
272
|
end
|
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: 62196227
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
9
|
- 7
|
10
10
|
- beta
|
11
|
-
-
|
12
|
-
version: 0.9.7.beta.
|
11
|
+
- 4
|
12
|
+
version: 0.9.7.beta.4
|
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-
|
21
|
+
date: 2012-09-19 00:00:00 -07:00
|
22
22
|
default_executable:
|
23
23
|
dependencies:
|
24
24
|
- !ruby/object:Gem::Dependency
|
@@ -197,7 +197,6 @@ files:
|
|
197
197
|
- lib/sensu/client.rb
|
198
198
|
- lib/sensu/constants.rb
|
199
199
|
- lib/sensu/logger.rb
|
200
|
-
- lib/sensu/patches/ruby.rb
|
201
200
|
- lib/sensu/process.rb
|
202
201
|
- lib/sensu/redis.rb
|
203
202
|
- lib/sensu/server.rb
|