sensu 0.8.18 → 0.8.19

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