sensu 0.9.7.beta.3 → 0.9.7.beta.4

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/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