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.
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 LOG_LEVELS.include?(log_level)
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 File.join(File.dirname(__FILE__), 'base')
2
- require File.join(File.dirname(__FILE__), 'socket')
1
+ require 'sensu/daemon'
2
+ require 'sensu/socket'
3
3
 
4
4
  module Sensu
5
5
  class Client
6
- include Utilities
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.trap_signals
14
+ client.setup_signal_traps
15
15
  end
16
16
  end
17
17
 
18
18
  def initialize(options={})
19
- base = Base.new(options)
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
- end
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(:timestamp => Time.now.to_i)
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
- begin
57
- @amq.direct('keepalives').publish(Oj.dump(payload))
58
- rescue AMQ::Client::ConnectionClosedError => error
59
- @logger.error('failed to publish keepalive', {
60
- :payload => payload,
61
- :error => error.to_s
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
- if @rabbitmq.connected?
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
- begin
85
- @amq.direct('results').publish(Oj.dump(payload))
86
- rescue AMQ::Client::ConnectionClosedError => error
87
- @logger.error('failed to publish check result', {
88
- :payload => payload,
89
- :error => error.to_s
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(/:::(.*?):::/) do
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
- execute = Proc.new do
123
- @logger.debug('executing check command', {
124
- :check => check
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
- end
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
- @check_request_queue = @amq.queue('', :auto_delete => true) do |queue|
199
- @settings[:client][:subscriptions].each do |exchange_name|
200
- @logger.debug('binding queue to exchange', {
201
- :queue_name => queue.name,
202
- :exchange_name => exchange_name
203
- })
204
- queue.bind(@amq.fanout(exchange_name))
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
- if @rabbitmq.connected?
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.amq = @amq
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.amq = @amq
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
- setup_rabbitmq
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
- @extensions.stop_all do
304
- @rabbitmq.close
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
@@ -1,12 +1,6 @@
1
1
  module Sensu
2
2
  unless defined?(Sensu::VERSION)
3
- VERSION = '0.12.6'
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
 
@@ -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