sensu 0.8.18 → 0.8.19

Sign up to get free protection for your applications and to get access to all the features.
data/README.org CHANGED
@@ -36,3 +36,4 @@
36
36
  - [[http://twitter.com/joshpasqualetto][Josh Pasqualetto]]
37
37
  - Steve Lum
38
38
  - [[http://twitter.com/miller_joe][Joe Miller]]
39
+ - [[http://twitter.com/decklin][Decklin Foster]]
data/lib/sensu.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sensu
2
- VERSION = "0.8.18"
2
+ VERSION = "0.8.19"
3
3
  end
data/lib/sensu/api.rb CHANGED
@@ -25,7 +25,7 @@ module Sensu
25
25
  def self.setup(options={})
26
26
  config = Sensu::Config.new(options)
27
27
  $settings = config.settings
28
- $logger = config.logger
28
+ $logger = config.open_log
29
29
  $logger.debug('[setup] -- connecting to redis')
30
30
  $redis = EM.connect($settings.redis.host, $settings.redis.port, Redis::Reconnect)
31
31
  $logger.debug('[setup] -- connecting to rabbitmq')
@@ -102,6 +102,21 @@ module Sensu
102
102
  end
103
103
  end
104
104
 
105
+ aget '/checks' do
106
+ $logger.debug('[checks] -- ' + request.ip + ' -- GET -- request for check list')
107
+ body $settings.checks.to_json
108
+ end
109
+
110
+ aget '/check/:name' do |check|
111
+ $logger.debug('[check] -- ' + request.ip + ' -- GET -- request for check -- ' + check)
112
+ if $settings.checks.key?(check)
113
+ body $settings.checks[check].to_json
114
+ else
115
+ status 404
116
+ body nil
117
+ end
118
+ end
119
+
105
120
  aget '/events' do
106
121
  $logger.debug('[events] -- ' + request.ip + ' -- GET -- request for event list')
107
122
  response = Hash.new
data/lib/sensu/client.rb CHANGED
@@ -22,7 +22,7 @@ module Sensu
22
22
  def initialize(options={})
23
23
  config = Sensu::Config.new(options)
24
24
  @settings = config.settings
25
- @logger = config.logger
25
+ @logger = config.open_log
26
26
  end
27
27
 
28
28
  def stop(signal)
@@ -97,7 +97,7 @@ module Sensu
97
97
  @logger.warn('[execute] -- missing client attributes -- ' + unmatched_tokens.join(', ') + ' -- ' + check.name)
98
98
  check.status = 3
99
99
  check.output = 'Missing client attributes: ' + unmatched_tokens.join(', ')
100
- check.internal = true
100
+ check.handle = false
101
101
  publish_result(check)
102
102
  @checks_in_progress.delete(check.name)
103
103
  end
@@ -106,7 +106,7 @@ module Sensu
106
106
  @logger.warn('[execute] -- unkown check -- ' + check.name)
107
107
  check.status = 3
108
108
  check.output = 'Unknown check'
109
- check.internal = true
109
+ check.handle = false
110
110
  publish_result(check)
111
111
  @checks_in_progress.delete(check.name)
112
112
  end
@@ -126,11 +126,22 @@ module Sensu
126
126
  if check.key?('matching')
127
127
  @logger.info('[subscribe] -- check requires matching -- ' + check.name)
128
128
  matches = check.matching.all? do |key, value|
129
- if key == 'subscribes'
130
- @settings.client.subscriptions.include?(value)
129
+ desired = case key
130
+ when /^!/
131
+ key = key.slice(1..-1)
132
+ false
133
+ else
134
+ true
135
+ end
136
+ matched = case key
137
+ when 'subscribes'
138
+ value.all? do |subscription|
139
+ @settings.client.subscriptions.include?(subscription)
140
+ end
131
141
  else
132
142
  @settings.client[key] == value
133
143
  end
144
+ desired == matched
134
145
  end
135
146
  if matches
136
147
  @logger.info('[subscribe] -- client matches -- ' + check.name)
data/lib/sensu/config.rb CHANGED
@@ -17,49 +17,62 @@ module Sensu
17
17
  class Config
18
18
  attr_accessor :settings, :logger
19
19
 
20
+ DEFAULT_OPTIONS = {
21
+ :log_file => '/tmp/sensu.log',
22
+ :config_file => '/etc/sensu/config.json',
23
+ :config_dir => '/etc/sensu/conf.d',
24
+ :validate => true,
25
+ }
26
+
20
27
  def initialize(options={})
28
+ @options = DEFAULT_OPTIONS.merge(options)
29
+ read_config
30
+ validate_config if @options[:validate]
31
+ end
32
+
33
+ def open_log
21
34
  @logger = Cabin::Channel.new
22
- log_file = options[:log_file] || '/tmp/sensu.log'
23
- if File.writable?(log_file) || !File.exist?(log_file) && File.writable?(File.dirname(log_file))
24
- ruby_logger = Logger.new(log_file)
35
+ if File.writable?(@options[:log_file]) || !File.exist?(@options[:log_file]) && File.writable?(File.dirname(@options[:log_file]))
36
+ ruby_logger = Logger.new(@options[:log_file])
25
37
  else
26
- invalid_config('log file is not writable: ' + log_file)
38
+ invalid_config('log file is not writable: ' + @options[:log_file])
27
39
  end
28
40
  @logger.subscribe(Cabin::Outputs::EmStdlibLogger.new(ruby_logger))
29
- @logger.level = options[:verbose] ? :debug : :info
41
+ @logger.level = @options[:verbose] ? :debug : :info
30
42
  Signal.trap('USR1') do
31
43
  @logger.level = @logger.level == :info ? :debug : :info
32
44
  end
33
- config_file = options[:config_file] || '/etc/sensu/config.json'
34
- if File.readable?(config_file)
45
+ @logger
46
+ end
47
+
48
+ def read_config
49
+ if File.readable?(@options[:config_file])
35
50
  begin
36
- @settings = Hashie::Mash.new(JSON.parse(File.open(config_file, 'r').read))
51
+ @settings = Hashie::Mash.new(JSON.parse(File.open(@options[:config_file], 'r').read))
37
52
  rescue JSON::ParserError => error
38
- invalid_config('configuration file (' + config_file + ') must be valid JSON: ' + error)
53
+ invalid_config('configuration file (' + @options[:config_file] + ') must be valid JSON: ' + error.to_s)
39
54
  end
40
55
  else
41
- invalid_config('configuration file does not exist or is not readable: ' + config_file)
56
+ invalid_config('configuration file does not exist or is not readable: ' + @options[:config_file])
42
57
  end
43
- config_dir = options[:config_dir] || '/etc/sensu/conf.d'
44
- if File.exists?(config_dir)
45
- Dir[config_dir + '/**/*.json'].each do |snippet_file|
58
+ if File.exists?(@options[:config_dir])
59
+ Dir[@options[:config_dir] + '/**/*.json'].each do |snippet_file|
46
60
  begin
47
61
  snippet_hash = JSON.parse(File.open(snippet_file, 'r').read)
48
62
  rescue JSON::ParserError => error
49
- invalid_config('configuration snippet file (' + snippet_file + ') must be valid JSON: ' + error)
63
+ invalid_config('configuration snippet file (' + snippet_file + ') must be valid JSON: ' + error.to_s)
50
64
  end
51
65
  merged_settings = @settings.to_hash.deep_merge(snippet_hash)
52
- @logger.warn('[settings] configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json)
66
+ @logger.warn('[settings] configuration snippet (' + snippet_file + ') applied changes: ' + @settings.deep_diff(merged_settings).to_json) if @logger
53
67
  @settings = Hashie::Mash.new(merged_settings)
54
68
  end
55
69
  end
56
- validate_config(options['type'])
57
70
  end
58
71
 
59
- def validate_config(type)
60
- @logger.debug('[config] -- validating configuration')
72
+ def validate_config
73
+ @logger.debug('[config] -- validating configuration') if @logger
61
74
  has_keys(%w[rabbitmq])
62
- case type
75
+ case @options['type']
63
76
  when 'server'
64
77
  has_keys(%w[redis handlers checks])
65
78
  unless @settings.handlers.include?('default')
@@ -100,9 +113,9 @@ module Sensu
100
113
  end
101
114
  end
102
115
  end
103
- if type
104
- @logger.debug('[config] -- configuration valid -- running ' + type)
105
- puts 'configuration valid -- running ' + type
116
+ if @options['type']
117
+ @logger.debug('[config] -- configuration valid -- running ' + @options['type']) if @logger
118
+ puts 'configuration valid -- running ' + @options['type']
106
119
  end
107
120
  end
108
121
 
@@ -115,7 +128,7 @@ module Sensu
115
128
  end
116
129
 
117
130
  def invalid_config(message)
118
- @logger.error('[config] -- configuration invalid -- ' + message)
131
+ @logger.error('[config] -- configuration invalid -- ' + message) if @logger
119
132
  raise 'configuration invalid, ' + message
120
133
  end
121
134
 
data/lib/sensu/server.rb CHANGED
@@ -6,7 +6,7 @@ require File.join(File.dirname(__FILE__), 'helpers', 'redis')
6
6
 
7
7
  module Sensu
8
8
  class Server
9
- attr_accessor :redis, :is_worker
9
+ attr_accessor :redis, :amq, :is_worker
10
10
 
11
11
  def self.run(options={})
12
12
  EM.threadpool_size = 16
@@ -33,7 +33,7 @@ module Sensu
33
33
  def initialize(options={})
34
34
  config = Sensu::Config.new(options)
35
35
  @settings = config.settings
36
- @logger = config.logger
36
+ @logger = config.open_log
37
37
  @is_worker = options[:worker]
38
38
  end
39
39
 
@@ -84,22 +84,35 @@ module Sensu
84
84
  handlers.each do |handler|
85
85
  if @settings.handlers.key?(handler)
86
86
  @logger.debug('[event] -- handling event -- ' + [handler, event.client.name, event.check.name].join(' -- '))
87
- handle = proc do
88
- output = ''
89
- Bundler.with_clean_env do
90
- begin
91
- IO.popen(@settings.handlers[handler] + ' 2>&1', 'r+') do |io|
92
- io.write(event.to_json)
93
- io.close_write
94
- output = io.read
87
+ if @settings.handlers[handler].is_a?(Hash)
88
+ details = @settings.handlers[handler]
89
+ case details.type
90
+ when "amqp"
91
+ exchange = details.exchange || 'events'
92
+ @logger.debug('[event] -- publishing event to amqp exchange -- ' + [exchange, event.client.name, event.check.name].join(' -- '))
93
+ message = details.send_only_check_output ? event.check.output : event.to_json
94
+ @amq.direct(exchange).publish(message)
95
+ else
96
+ @logger.warn('[event] -- unknown handler type -- ' + details.type)
97
+ end
98
+ else
99
+ handle = proc do
100
+ output = ''
101
+ Bundler.with_clean_env do
102
+ begin
103
+ IO.popen(@settings.handlers[handler] + ' 2>&1', 'r+') do |io|
104
+ io.write(event.to_json)
105
+ io.close_write
106
+ output = io.read
107
+ end
108
+ rescue Errno::EPIPE => error
109
+ output = handler + ' -- broken pipe: ' + error
95
110
  end
96
- rescue Errno::EPIPE => error
97
- output = handler + ' -- broken pipe: ' + error
98
111
  end
112
+ output
99
113
  end
100
- output
114
+ EM.defer(handle, report)
101
115
  end
102
- EM.defer(handle, report)
103
116
  else
104
117
  @logger.warn('[event] -- handler does not exist -- ' + handler)
105
118
  end
@@ -123,6 +136,7 @@ module Sensu
123
136
  history_key = 'history:' + client.name + ':' + check.name
124
137
  @redis.rpush(history_key, check.status).callback do
125
138
  @redis.lrange(history_key, -21, -1).callback do |history|
139
+ event.check.history = history
126
140
  total_state_change = 0
127
141
  unless history.count < 21
128
142
  state_changes = 0
@@ -156,7 +170,7 @@ module Sensu
156
170
  unless is_flapping
157
171
  unless check.auto_resolve == false && !check.force_resolve
158
172
  @redis.hdel('events:' + client.name, check.name).callback do
159
- unless check.internal
173
+ unless check.handle == false
160
174
  event.action = 'resolve'
161
175
  handle_event(event)
162
176
  end
@@ -166,7 +180,7 @@ module Sensu
166
180
  @logger.debug('[result] -- check is flapping -- ' + client.name + ' -- ' + check.name)
167
181
  @redis.hset('events:' + client.name, check.name, previous_occurrence.merge({'flapping' => true}).to_json)
168
182
  end
169
- elsif check['status'] != 0
183
+ elsif check.status != 0
170
184
  if previous_occurrence && check.status == previous_occurrence.status
171
185
  event.occurrences = previous_occurrence.occurrences += 1
172
186
  end
@@ -176,7 +190,7 @@ module Sensu
176
190
  :flapping => is_flapping,
177
191
  :occurrences => event.occurrences
178
192
  }.to_json).callback do
179
- unless check.internal
193
+ unless check.handle == false
180
194
  event.check.flapping = is_flapping
181
195
  event.action = 'create'
182
196
  handle_event(event)
@@ -206,24 +220,23 @@ module Sensu
206
220
  exchanges = Hash.new
207
221
  stagger = options[:test] ? 0 : 7
208
222
  @settings.checks.each_with_index do |(name, details), index|
209
- check = Hashie::Mash.new
210
- check.name = name
223
+ check_request = Hashie::Mash.new({:name => name})
211
224
  unless details.publish == false
212
225
  EM.add_timer(stagger*index) do
213
- details.subscribers.each do |subscriber|
214
- if subscriber.is_a?(Hash)
215
- @logger.debug('[publisher] -- check requires matching -- ' + subscriber.to_hash.to_s + ' -- ' + name)
216
- check.matching = subscriber
226
+ details.subscribers.each do |target|
227
+ if target.is_a?(Hash)
228
+ @logger.debug('[publisher] -- check requires matching -- ' + target.to_hash.to_s + ' -- ' + name)
229
+ check_request.matching = target
217
230
  exchange = 'uchiwa'
218
231
  else
219
- exchange = subscriber
232
+ exchange = target
220
233
  end
221
234
  exchanges[exchange] ||= @amq.fanout(exchange)
222
235
  interval = options[:test] ? 0.5 : details.interval
223
236
  EM.add_periodic_timer(interval) do
224
- check.issued = Time.now.to_i
237
+ check_request.issued = Time.now.to_i
225
238
  @logger.info('[publisher] -- publishing check -- ' + name + ' -- ' + exchange)
226
- exchanges[exchange].publish(check.to_json)
239
+ exchanges[exchange].publish(check_request.to_json)
227
240
  end
228
241
  end
229
242
  end
@@ -239,7 +252,7 @@ module Sensu
239
252
  clients.each do |client_id|
240
253
  @redis.get('client:' + client_id).callback do |client_json|
241
254
  client = Hashie::Mash.new(JSON.parse(client_json))
242
- time_since_last_check = Time.now.to_i - client.timestamp
255
+ time_since_last_keepalive = Time.now.to_i - client.timestamp
243
256
  result = Hashie::Mash.new({
244
257
  :client => client.name,
245
258
  :check => {
@@ -248,11 +261,11 @@ module Sensu
248
261
  }
249
262
  })
250
263
  case
251
- when time_since_last_check >= 180
264
+ when time_since_last_keepalive >= 180
252
265
  result.check.status = 2
253
266
  result.check.output = 'No keep-alive sent from host in over 180 seconds'
254
267
  @result_queue.publish(result.to_json)
255
- when time_since_last_check >= 120
268
+ when time_since_last_keepalive >= 120
256
269
  result.check.status = 1
257
270
  result.check.output = 'No keep-alive sent from host in over 120 seconds'
258
271
  @result_queue.publish(result.to_json)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 8
9
- - 18
10
- version: 0.8.18
9
+ - 19
10
+ version: 0.8.19
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sean Porter
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-12-13 00:00:00 -08:00
19
+ date: 2011-12-16 00:00:00 -08:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency