sensu 0.12.6 → 0.13.0.alpha
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 +41 -0
- data/lib/sensu/api.rb +145 -205
- data/lib/sensu/cli.rb +2 -1
- data/lib/sensu/client.rb +51 -119
- data/lib/sensu/constants.rb +1 -7
- data/lib/sensu/daemon.rb +221 -0
- data/lib/sensu/server.rb +105 -202
- data/lib/sensu/socket.rb +4 -4
- data/lib/sensu/utilities.rb +6 -29
- data/sensu.gemspec +10 -6
- metadata +223 -228
- data/lib/sensu/base.rb +0 -75
- data/lib/sensu/extensions.rb +0 -162
- data/lib/sensu/extensions/handlers/debug.rb +0 -17
- data/lib/sensu/extensions/mutators/only_check_output.rb +0 -17
- data/lib/sensu/io.rb +0 -98
- data/lib/sensu/logstream.rb +0 -93
- data/lib/sensu/process.rb +0 -48
- data/lib/sensu/rabbitmq.rb +0 -106
- data/lib/sensu/settings.rb +0 -483
data/lib/sensu/cli.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'optparse'
|
2
|
+
require 'sensu/logger/constants'
|
2
3
|
|
3
4
|
module Sensu
|
4
5
|
class CLI
|
@@ -27,7 +28,7 @@ module Sensu
|
|
27
28
|
end
|
28
29
|
opts.on('-L', '--log_level LEVEL', 'Log severity LEVEL') do |level|
|
29
30
|
log_level = level.to_s.downcase.to_sym
|
30
|
-
unless
|
31
|
+
unless Logger::LEVELS.include?(log_level)
|
31
32
|
puts 'Unknown log level: ' + level.to_s
|
32
33
|
exit 1
|
33
34
|
end
|
data/lib/sensu/client.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'sensu/daemon'
|
2
|
+
require 'sensu/socket'
|
3
3
|
|
4
4
|
module Sensu
|
5
5
|
class Client
|
6
|
-
include
|
6
|
+
include Daemon
|
7
7
|
|
8
8
|
attr_accessor :safe_mode
|
9
9
|
|
@@ -11,63 +11,40 @@ module Sensu
|
|
11
11
|
client = self.new(options)
|
12
12
|
EM::run do
|
13
13
|
client.start
|
14
|
-
client.
|
14
|
+
client.setup_signal_traps
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
def initialize(options={})
|
19
|
-
|
20
|
-
@logger = base.logger
|
21
|
-
@settings = base.settings
|
22
|
-
@extensions = base.extensions
|
23
|
-
base.setup_process
|
24
|
-
@extensions.load_settings(@settings.to_hash)
|
25
|
-
@timers = Array.new
|
26
|
-
@checks_in_progress = Array.new
|
19
|
+
super
|
27
20
|
@safe_mode = @settings[:client][:safe_mode] || false
|
28
|
-
|
29
|
-
|
30
|
-
def setup_rabbitmq
|
31
|
-
@logger.debug('connecting to rabbitmq', {
|
32
|
-
:settings => @settings[:rabbitmq]
|
33
|
-
})
|
34
|
-
@rabbitmq = RabbitMQ.connect(@settings[:rabbitmq])
|
35
|
-
@rabbitmq.on_error do |error|
|
36
|
-
@logger.fatal('rabbitmq connection error', {
|
37
|
-
:error => error.to_s
|
38
|
-
})
|
39
|
-
stop
|
40
|
-
end
|
41
|
-
@rabbitmq.before_reconnect do
|
42
|
-
@logger.warn('reconnecting to rabbitmq')
|
43
|
-
end
|
44
|
-
@rabbitmq.after_reconnect do
|
45
|
-
@logger.info('reconnected to rabbitmq')
|
46
|
-
end
|
47
|
-
@amq = @rabbitmq.channel
|
21
|
+
@checks_in_progress = Array.new
|
48
22
|
end
|
49
23
|
|
50
24
|
def publish_keepalive
|
51
|
-
keepalive = @settings[:client].merge(
|
25
|
+
keepalive = @settings[:client].merge({
|
26
|
+
:version => VERSION,
|
27
|
+
:timestamp => Time.now.to_i
|
28
|
+
})
|
52
29
|
payload = redact_sensitive(keepalive, @settings[:client][:redact])
|
53
30
|
@logger.debug('publishing keepalive', {
|
54
31
|
:payload => payload
|
55
32
|
})
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
33
|
+
@transport.publish(:direct, 'keepalives', MultiJson.dump(payload)) do |info|
|
34
|
+
if info[:error]
|
35
|
+
@logger.error('failed to publish keepalive', {
|
36
|
+
:payload => payload,
|
37
|
+
:error => info[:error].to_s
|
38
|
+
})
|
39
|
+
end
|
63
40
|
end
|
64
41
|
end
|
65
42
|
|
66
43
|
def setup_keepalives
|
67
44
|
@logger.debug('scheduling keepalives')
|
68
45
|
publish_keepalive
|
69
|
-
@timers << EM::PeriodicTimer.new(20) do
|
70
|
-
|
46
|
+
@timers[:run] << EM::PeriodicTimer.new(20) do
|
47
|
+
unless @state == :paused
|
71
48
|
publish_keepalive
|
72
49
|
end
|
73
50
|
end
|
@@ -81,19 +58,19 @@ module Sensu
|
|
81
58
|
@logger.info('publishing check result', {
|
82
59
|
:payload => payload
|
83
60
|
})
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
61
|
+
@transport.publish(:direct, 'results', MultiJson.dump(payload)) do |info|
|
62
|
+
if info[:error]
|
63
|
+
@logger.error('failed to publish check result', {
|
64
|
+
:payload => payload,
|
65
|
+
:error => info[:error].to_s
|
66
|
+
})
|
67
|
+
end
|
91
68
|
end
|
92
69
|
end
|
93
70
|
|
94
71
|
def substitute_command_tokens(check)
|
95
72
|
unmatched_tokens = Array.new
|
96
|
-
substituted = check[:command].gsub(/:::(
|
73
|
+
substituted = check[:command].gsub(/:::([^:]*?):::/) do
|
97
74
|
token, default = $1.to_s.split('|', -1)
|
98
75
|
matched = token.split('.').inject(@settings[:client]) do |client, attribute|
|
99
76
|
if client[attribute].nil?
|
@@ -117,27 +94,16 @@ module Sensu
|
|
117
94
|
unless @checks_in_progress.include?(check[:name])
|
118
95
|
@checks_in_progress << check[:name]
|
119
96
|
command, unmatched_tokens = substitute_command_tokens(check)
|
120
|
-
check[:executed] = Time.now.to_i
|
121
97
|
if unmatched_tokens.empty?
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
})
|
126
|
-
started = Time.now.to_f
|
127
|
-
begin
|
128
|
-
check[:output], check[:status] = IO.popen(command, 'r', check[:timeout])
|
129
|
-
rescue => error
|
130
|
-
check[:output] = 'Unexpected error: ' + error.to_s
|
131
|
-
check[:status] = 2
|
132
|
-
end
|
98
|
+
check[:executed] = Time.now.to_i
|
99
|
+
started = Time.now.to_f
|
100
|
+
Spawn.process(command, :timeout => check[:timeout]) do |output, status|
|
133
101
|
check[:duration] = ('%.3f' % (Time.now.to_f - started)).to_f
|
134
|
-
check
|
135
|
-
|
136
|
-
publish = Proc.new do |check|
|
102
|
+
check[:output] = output
|
103
|
+
check[:status] = status
|
137
104
|
publish_result(check)
|
138
105
|
@checks_in_progress.delete(check[:name])
|
139
106
|
end
|
140
|
-
EM::defer(execute, publish)
|
141
107
|
else
|
142
108
|
check[:output] = 'Unmatched command tokens: ' + unmatched_tokens.join(', ')
|
143
109
|
check[:status] = 3
|
@@ -195,16 +161,13 @@ module Sensu
|
|
195
161
|
|
196
162
|
def setup_subscriptions
|
197
163
|
@logger.debug('subscribing to client subscriptions')
|
198
|
-
@
|
199
|
-
@
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
end
|
206
|
-
queue.subscribe do |payload|
|
207
|
-
check = Oj.load(payload)
|
164
|
+
@settings[:client][:subscriptions].each do |subscription|
|
165
|
+
@logger.debug('subscribing to a subscription', {
|
166
|
+
:subscription => subscription
|
167
|
+
})
|
168
|
+
funnel = [@settings[:client][:name], VERSION, Time.now.to_i].join('-')
|
169
|
+
@transport.subscribe(:fanout, subscription, funnel) do |message_info, message|
|
170
|
+
check = MultiJson.load(message)
|
208
171
|
@logger.info('received check request', {
|
209
172
|
:check => check
|
210
173
|
})
|
@@ -219,12 +182,12 @@ module Sensu
|
|
219
182
|
checks.each do |check|
|
220
183
|
check_count += 1
|
221
184
|
scheduling_delay = stagger * check_count % 30
|
222
|
-
@timers << EM::Timer.new(scheduling_delay) do
|
185
|
+
@timers[:run] << EM::Timer.new(scheduling_delay) do
|
223
186
|
interval = testing? ? 0.5 : check[:interval]
|
224
|
-
@timers << EM::PeriodicTimer.new(interval) do
|
225
|
-
|
187
|
+
@timers[:run] << EM::PeriodicTimer.new(interval) do
|
188
|
+
unless @state == :paused
|
226
189
|
check[:issued] = Time.now.to_i
|
227
|
-
process_check(check)
|
190
|
+
process_check(check.dup)
|
228
191
|
end
|
229
192
|
end
|
230
193
|
end
|
@@ -252,27 +215,16 @@ module Sensu
|
|
252
215
|
EM::start_server(options[:bind], options[:port], Socket) do |socket|
|
253
216
|
socket.logger = @logger
|
254
217
|
socket.settings = @settings
|
255
|
-
socket.
|
218
|
+
socket.transport = @transport
|
256
219
|
end
|
257
220
|
EM::open_datagram_socket(options[:bind], options[:port], Socket) do |socket|
|
258
221
|
socket.logger = @logger
|
259
222
|
socket.settings = @settings
|
260
|
-
socket.
|
223
|
+
socket.transport = @transport
|
261
224
|
socket.reply = false
|
262
225
|
end
|
263
226
|
end
|
264
227
|
|
265
|
-
def unsubscribe
|
266
|
-
@logger.warn('unsubscribing from client subscriptions')
|
267
|
-
if @rabbitmq.connected?
|
268
|
-
@check_request_queue.unsubscribe
|
269
|
-
else
|
270
|
-
@check_request_queue.before_recovery do
|
271
|
-
@check_request_queue.unsubscribe
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
228
|
def complete_checks_in_progress(&block)
|
277
229
|
@logger.info('completing checks in progress', {
|
278
230
|
:checks_in_progress => @checks_in_progress
|
@@ -286,43 +238,23 @@ module Sensu
|
|
286
238
|
end
|
287
239
|
|
288
240
|
def start
|
289
|
-
|
241
|
+
setup_transport
|
290
242
|
setup_keepalives
|
291
243
|
setup_subscriptions
|
292
244
|
setup_standalone
|
293
245
|
setup_sockets
|
246
|
+
super
|
294
247
|
end
|
295
248
|
|
296
249
|
def stop
|
297
250
|
@logger.warn('stopping')
|
298
|
-
@timers.each do |timer|
|
251
|
+
@timers[:run].each do |timer|
|
299
252
|
timer.cancel
|
300
253
|
end
|
301
|
-
unsubscribe
|
254
|
+
@transport.unsubscribe
|
302
255
|
complete_checks_in_progress do
|
303
|
-
@
|
304
|
-
|
305
|
-
@logger.warn('stopping reactor')
|
306
|
-
EM::stop_event_loop
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
def trap_signals
|
312
|
-
@signals = Array.new
|
313
|
-
STOP_SIGNALS.each do |signal|
|
314
|
-
Signal.trap(signal) do
|
315
|
-
@signals << signal
|
316
|
-
end
|
317
|
-
end
|
318
|
-
EM::PeriodicTimer.new(1) do
|
319
|
-
signal = @signals.shift
|
320
|
-
if STOP_SIGNALS.include?(signal)
|
321
|
-
@logger.warn('received signal', {
|
322
|
-
:signal => signal
|
323
|
-
})
|
324
|
-
stop
|
325
|
-
end
|
256
|
+
@transport.close
|
257
|
+
super
|
326
258
|
end
|
327
259
|
end
|
328
260
|
end
|
data/lib/sensu/constants.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
1
|
module Sensu
|
2
2
|
unless defined?(Sensu::VERSION)
|
3
|
-
VERSION = '0.
|
4
|
-
|
5
|
-
LOG_LEVELS = [:debug, :info, :warn, :error, :fatal]
|
6
|
-
|
7
|
-
SETTINGS_CATEGORIES = [:checks, :filters, :mutators, :handlers]
|
8
|
-
|
9
|
-
EXTENSION_CATEGORIES = [:generics, :checks, :mutators, :handlers]
|
3
|
+
VERSION = '0.13.0.alpha'
|
10
4
|
|
11
5
|
SEVERITIES = %w[ok warning critical unknown]
|
12
6
|
|
data/lib/sensu/daemon.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
gem 'multi_json', '1.10.1'
|
4
|
+
|
5
|
+
gem 'sensu-em', '2.0.0'
|
6
|
+
gem 'sensu-logger', '0.0.1'
|
7
|
+
gem 'sensu-settings', '0.0.4'
|
8
|
+
gem 'sensu-extension', '0.0.3'
|
9
|
+
gem 'sensu-extensions', '0.0.4'
|
10
|
+
gem 'sensu-transport', '0.0.2'
|
11
|
+
gem 'sensu-spawn', '0.0.3'
|
12
|
+
|
13
|
+
require 'time'
|
14
|
+
require 'uri'
|
15
|
+
|
16
|
+
require 'sensu/logger'
|
17
|
+
require 'sensu/settings'
|
18
|
+
require 'sensu/extensions'
|
19
|
+
require 'sensu/transport'
|
20
|
+
require 'sensu/spawn'
|
21
|
+
|
22
|
+
require 'sensu/constants'
|
23
|
+
require 'sensu/utilities'
|
24
|
+
require 'sensu/cli'
|
25
|
+
require 'sensu/redis'
|
26
|
+
|
27
|
+
MultiJson.load_options = {:symbolize_keys => true}
|
28
|
+
|
29
|
+
module Sensu
|
30
|
+
module Daemon
|
31
|
+
include Utilities
|
32
|
+
|
33
|
+
attr_reader :state
|
34
|
+
|
35
|
+
def initialize(options={})
|
36
|
+
@state = :initializing
|
37
|
+
@timers = {
|
38
|
+
:run => Array.new
|
39
|
+
}
|
40
|
+
setup_logger(options)
|
41
|
+
load_settings(options)
|
42
|
+
load_extensions(options)
|
43
|
+
setup_process(options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def setup_logger(options={})
|
47
|
+
@logger = Logger.get(options)
|
48
|
+
@logger.setup_signal_traps
|
49
|
+
end
|
50
|
+
|
51
|
+
def log_concerns(concerns=[], level=:warn)
|
52
|
+
concerns.each do |concern|
|
53
|
+
message = concern.delete(:message)
|
54
|
+
@logger.send(level, message, redact_sensitive(concern))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def load_settings(options={})
|
59
|
+
@settings = Settings.load(options)
|
60
|
+
log_concerns(@settings.warnings)
|
61
|
+
failures = @settings.validate
|
62
|
+
unless failures.empty?
|
63
|
+
@logger.fatal('invalid settings')
|
64
|
+
log_concerns(failures, :fatal)
|
65
|
+
@logger.fatal('SENSU NOT RUNNING!')
|
66
|
+
exit 2
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_extensions(options={})
|
71
|
+
@extensions = Extensions.load(options)
|
72
|
+
log_concerns(@extensions.warnings)
|
73
|
+
extension_settings = @settings.to_hash.dup
|
74
|
+
@extensions.all.each do |extension|
|
75
|
+
extension.logger = @logger
|
76
|
+
extension.settings = extension_settings
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def setup_process(options)
|
81
|
+
if options[:daemonize]
|
82
|
+
daemonize
|
83
|
+
end
|
84
|
+
if options[:pid_file]
|
85
|
+
write_pid(options[:pid_file])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def start
|
90
|
+
@state = :running
|
91
|
+
end
|
92
|
+
|
93
|
+
def pause
|
94
|
+
@state = :paused
|
95
|
+
end
|
96
|
+
|
97
|
+
def resume
|
98
|
+
@state = :running
|
99
|
+
end
|
100
|
+
|
101
|
+
def stop
|
102
|
+
@state = :stopped
|
103
|
+
@logger.warn('stopping reactor')
|
104
|
+
EM::stop_event_loop
|
105
|
+
end
|
106
|
+
|
107
|
+
def setup_signal_traps
|
108
|
+
@signals = Array.new
|
109
|
+
STOP_SIGNALS.each do |signal|
|
110
|
+
Signal.trap(signal) do
|
111
|
+
@signals << signal
|
112
|
+
end
|
113
|
+
end
|
114
|
+
EM::PeriodicTimer.new(1) do
|
115
|
+
signal = @signals.shift
|
116
|
+
if STOP_SIGNALS.include?(signal)
|
117
|
+
@logger.warn('received signal', {
|
118
|
+
:signal => signal
|
119
|
+
})
|
120
|
+
stop
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def setup_transport
|
126
|
+
if @settings[:transport].is_a?(Hash)
|
127
|
+
transport_name = @settings[:transport][:name]
|
128
|
+
end
|
129
|
+
transport_name ||= 'rabbitmq'
|
130
|
+
transport_settings = @settings[transport_name.to_sym]
|
131
|
+
@logger.debug('connecting to transport', {
|
132
|
+
:name => transport_name,
|
133
|
+
:settings => transport_settings
|
134
|
+
})
|
135
|
+
@transport = Transport.connect(transport_name, transport_settings)
|
136
|
+
@transport.logger = @logger
|
137
|
+
@transport.on_error do |error|
|
138
|
+
@logger.fatal('transport connection error', {
|
139
|
+
:error => error.to_s
|
140
|
+
})
|
141
|
+
stop
|
142
|
+
end
|
143
|
+
@transport.before_reconnect do
|
144
|
+
unless testing?
|
145
|
+
@logger.warn('reconnecting to transport')
|
146
|
+
pause
|
147
|
+
end
|
148
|
+
end
|
149
|
+
@transport.after_reconnect do
|
150
|
+
@logger.info('reconnected to transport')
|
151
|
+
resume
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def setup_redis
|
156
|
+
@logger.debug('connecting to redis', {
|
157
|
+
:settings => @settings[:redis]
|
158
|
+
})
|
159
|
+
@redis = Redis.connect(@settings[:redis])
|
160
|
+
@redis.on_error do |error|
|
161
|
+
@logger.fatal('redis connection error', {
|
162
|
+
:error => error.to_s
|
163
|
+
})
|
164
|
+
stop
|
165
|
+
end
|
166
|
+
@redis.before_reconnect do
|
167
|
+
unless testing?
|
168
|
+
@logger.warn('reconnecting to redis')
|
169
|
+
pause
|
170
|
+
end
|
171
|
+
end
|
172
|
+
@redis.after_reconnect do
|
173
|
+
@logger.info('reconnected to redis')
|
174
|
+
resume
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
def write_pid(file)
|
181
|
+
begin
|
182
|
+
File.open(file, 'w') do |pid_file|
|
183
|
+
pid_file.puts(Process.pid)
|
184
|
+
end
|
185
|
+
rescue
|
186
|
+
@logger.fatal('could not write to pid file', {
|
187
|
+
:pid_file => file
|
188
|
+
})
|
189
|
+
@logger.fatal('SENSU NOT RUNNING!')
|
190
|
+
exit 2
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def daemonize
|
195
|
+
Kernel.srand
|
196
|
+
if Kernel.fork
|
197
|
+
exit
|
198
|
+
end
|
199
|
+
unless Process.setsid
|
200
|
+
@logger.fatal('cannot detach from controlling terminal')
|
201
|
+
@logger.fatal('SENSU NOT RUNNING!')
|
202
|
+
exit 2
|
203
|
+
end
|
204
|
+
Signal.trap('SIGHUP', 'IGNORE')
|
205
|
+
if Kernel.fork
|
206
|
+
exit
|
207
|
+
end
|
208
|
+
Dir.chdir('/')
|
209
|
+
ObjectSpace.each_object(IO) do |io|
|
210
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
211
|
+
begin
|
212
|
+
unless io.closed?
|
213
|
+
io.close
|
214
|
+
end
|
215
|
+
rescue
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|