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 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 check results and events.
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 = Cabin::Channel.get
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(@options)
33
- logger.reopen
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
@@ -1,3 +1,5 @@
1
+ require 'optparse'
2
+
1
3
  module Sensu
2
4
  class CLI
3
5
  def self.read(arguments=ARGV)
data/lib/sensu/client.rb CHANGED
@@ -12,7 +12,7 @@ module Sensu
12
12
  end
13
13
 
14
14
  def initialize(options={})
15
- @logger = Cabin::Channel.get
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
- log_level = :info
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
- if @settings.check_exists?(check[:name])
82
- unless @checks_in_progress.include?(check[:name])
83
- @logger.debug('executing check', {
84
- :check => check
85
- })
86
- @checks_in_progress.push(check[:name])
87
- unmatched_tokens = Array.new
88
- command = @settings[:checks][check[:name]][:command].gsub(/:::(.*?):::/) do
89
- token = $1.to_s
90
- begin
91
- substitute = @settings[:client].instance_eval(token)
92
- rescue NameError, NoMethodError
93
- substitute = nil
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
- if unmatched_tokens.empty?
101
- execute = Proc.new do
102
- check = check.dup
103
- started = Time.now.to_f
104
- begin
105
- IO.popen(command + ' 2>&1') do |io|
106
- check[:output] = io.read
107
- end
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[:duration] = ('%.3f' % (Time.now.to_f - started)).to_f
117
- check
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
- publish = Proc.new do |check|
120
- unless check[:status].nil?
121
- publish_result(check)
122
- end
123
- @checks_in_progress.delete(check[:name])
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('previous check execution in progress', {
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('unknown check', {
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
- execute_check(check)
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,
@@ -1,6 +1,6 @@
1
1
  module Sensu
2
2
  unless defined?(Sensu::VERSION)
3
- VERSION = '0.9.7.beta.3'
3
+ VERSION = '0.9.7.beta.4'
4
4
  end
5
5
 
6
6
  unless defined?(Sensu::DEFAULT_OPTIONS)
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(options={})
5
+ def initialize
4
6
  @logger = Cabin::Channel.get
5
7
  STDOUT.sync = true
8
+ STDERR.reopen(STDOUT)
6
9
  @logger.subscribe(STDOUT)
7
- @logger.level = options[:verbose] ? :debug : options[:log_level] || :info
8
- @log_file = options[:log_file]
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
@@ -1,7 +1,7 @@
1
1
  module Sensu
2
2
  class Process
3
3
  def initialize
4
- @logger = Cabin::Channel.get
4
+ @logger = Sensu::Logger.get
5
5
  end
6
6
 
7
7
  def write_pid(file)
data/lib/sensu/redis.rb CHANGED
@@ -8,7 +8,7 @@ module Sensu
8
8
 
9
9
  def initialize(*arguments)
10
10
  super
11
- @logger = Cabin::Channel.get
11
+ @logger = Sensu::Logger.get
12
12
  @settings = Hash.new
13
13
  @connection_established = false
14
14
  @connected = false
data/lib/sensu/server.rb CHANGED
@@ -14,7 +14,7 @@ module Sensu
14
14
  end
15
15
 
16
16
  def initialize(options={})
17
- @logger = Cabin::Channel.get
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?(:start) && check[:subdue].has_key?(:end)
90
- start_time = Time.parse(check[:subdue][:start])
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 < start_time
96
+ if end_time < begin_time
93
97
  if Time.now < end_time
94
- start_time = Time.parse('12:00:00 AM')
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 >= start_time && Time.now <= end_time
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[:start]) && Time.now <= Time.parse(exception[:end])
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
- (!check[:subdue].has_key?(:at) && subdue_at == :handler) ||
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.error('unknown mutator', {
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
- @logger.send(event[:check][:type] == 'metric' ? :debug : :info, 'handling event', {
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
- payload = {
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
@@ -3,7 +3,7 @@ module Sensu
3
3
  attr_reader :indifferent_access, :loaded_env, :loaded_files
4
4
 
5
5
  def initialize
6
- @logger = Cabin::Channel.get
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?(:start) || check[:subdue].has_key?(:end)
227
+ if check[:subdue].has_key?(:begin) || check[:subdue].has_key?(:end)
228
228
  begin
229
- Time.parse(check[:subdue][:start])
229
+ Time.parse(check[:subdue][:begin])
230
230
  Time.parse(check[:subdue][:end])
231
231
  rescue
232
- invalid('check subdue start & end times must be valid', {
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?(:start) || exception.has_key?(:end)
264
+ if exception.has_key?(:begin) || exception.has_key?(:end)
265
265
  begin
266
- Time.parse(exception[:start])
266
+ Time.parse(exception[:begin])
267
267
  Time.parse(exception[:end])
268
268
  rescue
269
- invalid('check subdue exception start & end times must be valid', {
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: 62196237
4
+ hash: 62196227
5
5
  prerelease: true
6
6
  segments:
7
7
  - 0
8
8
  - 9
9
9
  - 7
10
10
  - beta
11
- - 3
12
- version: 0.9.7.beta.3
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-08-25 00:00:00 -07:00
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
@@ -1,9 +0,0 @@
1
- class Hash
2
- def method_missing(method, *arguments, &block)
3
- if has_key?(method)
4
- self[method]
5
- else
6
- super
7
- end
8
- end
9
- end