sensu 0.17.2 → 0.18.0.beta

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0a0fac0647fef9c4dad920c91d477e0aac3ccefe
4
- data.tar.gz: f0ba6869b8a2e76e9c9a673332a87af8f9b30262
3
+ metadata.gz: 3562490d63bf32fe403bb3395f673b9be6ffd4e4
4
+ data.tar.gz: ba043f59f239c29b9d8353d29ca892c6a3400384
5
5
  SHA512:
6
- metadata.gz: 10ccf9155bbda665fe9c8b590cb93bc413e1825324069d00187d58466dd9a86ad0a6d99608796aabeaa39b3c1daac6b49e3d6612c7b4bf875c1a88c5e61d5186
7
- data.tar.gz: 8ece96457154d1d64fab3516afc527c5690397e84ad2d3c412ae25c1c7b1c467eba9f374da2cde8c4daa9bef1625bdc17ac7ad6b99beb469d6504b7a6db31170
6
+ metadata.gz: 0aae29a7af64355686413c1a4d6f108a1c59276312f31755065a5901faf5a5c508a9514b04e98e9942a651877b1d375a8ab9e3a6ba75e461310dded889c35b50
7
+ data.tar.gz: d0cbbbd0000a734f411a4cdc5a396a40bb281cfcdbd77b009bc61365045de95eef0937a2ff169b25c76cea89b3371cb56a2779cfad31a817d04cccee0b2f57da
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.18.0 - TBD
2
+
3
+ ### Features
4
+
5
+ Dynamic (or JIT) client creation (in the registry) for check results for a
6
+ nonexistent client or a check source. Sensu clients can now monitor an
7
+ external resource on its behalf, using a check `source` to create a JIT
8
+ client for the resource, used to store the execution history and provide
9
+ context within event data. JIT client data in the registry can be
10
+ managed/updated via the Sensu API, POST `/clients`.
11
+
12
+ Storing the latest check result for every client/check pair. This data is
13
+ currently exposed via the API at `/clients/:client/history` and will be
14
+ used by several upcoming features.
15
+
1
16
  ## 0.17.2 - 2015-04-08
2
17
 
3
18
  ### Other
@@ -170,7 +170,9 @@ module Sensu
170
170
  begin
171
171
  data = MultiJson.load(env["rack.input"].read)
172
172
  valid = rules.all? do |key, rule|
173
- data[key].is_a?(rule[:type]) || (rule[:nil_ok] && data[key].nil?)
173
+ value = data[key]
174
+ (value.is_a?(rule[:type]) || (rule[:nil_ok] && value.nil?)) &&
175
+ rule[:regex].nil? || (rule[:regex] && (value =~ rule[:regex]) == 0)
174
176
  end
175
177
  if valid
176
178
  callback.call(data)
@@ -302,6 +304,23 @@ module Sensu
302
304
  end
303
305
  end
304
306
 
307
+ apost "/clients/?" do
308
+ rules = {
309
+ :name => {:type => String, :nil_ok => false, :regex => /^[\w\.-]+$/},
310
+ :address => {:type => String, :nil_ok => false},
311
+ :subscriptions => {:type => Array, :nil_ok => false}
312
+ }
313
+ read_data(rules) do |data|
314
+ data[:keepalives] = false
315
+ data[:timestamp] = Time.now.to_i
316
+ settings.redis.set("client:#{data[:name]}", MultiJson.dump(data)) do
317
+ settings.redis.sadd("clients", data[:name]) do
318
+ created!(MultiJson.dump(:name => data[:name]))
319
+ end
320
+ end
321
+ end
322
+ end
323
+
305
324
  aget "/clients/?" do
306
325
  response = Array.new
307
326
  settings.redis.smembers("clients") do |clients|
@@ -333,22 +352,25 @@ module Sensu
333
352
 
334
353
  aget %r{/clients/([\w\.-]+)/history/?$} do |client_name|
335
354
  response = Array.new
336
- settings.redis.smembers("history:#{client_name}") do |checks|
355
+ settings.redis.smembers("result:#{client_name}") do |checks|
337
356
  unless checks.empty?
338
357
  checks.each_with_index do |check_name, index|
339
- history_key = "history:#{client_name}:#{check_name}"
358
+ result_key = "#{client_name}:#{check_name}"
359
+ history_key = "history:#{result_key}"
340
360
  settings.redis.lrange(history_key, -21, -1) do |history|
341
361
  history.map! do |status|
342
362
  status.to_i
343
363
  end
344
- execution_key = "execution:#{client_name}:#{check_name}"
345
- settings.redis.get(execution_key) do |last_execution|
364
+ settings.redis.get("result:#{result_key}") do |result_json|
365
+ result = MultiJson.load(result_json)
366
+ last_execution = result[:executed]
346
367
  unless history.empty? || last_execution.nil?
347
368
  item = {
348
369
  :check => check_name,
349
370
  :history => history,
350
371
  :last_execution => last_execution.to_i,
351
- :last_status => history.last
372
+ :last_status => history.last,
373
+ :last_result => result
352
374
  }
353
375
  response << item
354
376
  end
@@ -373,18 +395,17 @@ module Sensu
373
395
  end
374
396
  EM::Timer.new(5) do
375
397
  client = MultiJson.load(client_json)
376
- settings.logger.info("deleting client", {
377
- :client => client
378
- })
398
+ settings.logger.info("deleting client", :client => client)
379
399
  settings.redis.srem("clients", client_name) do
380
400
  settings.redis.del("client:#{client_name}")
381
401
  settings.redis.del("events:#{client_name}")
382
- settings.redis.smembers("history:#{client_name}") do |checks|
402
+ settings.redis.smembers("result:#{client_name}") do |checks|
383
403
  checks.each do |check_name|
384
- settings.redis.del("history:#{client_name}:#{check_name}")
385
- settings.redis.del("execution:#{client_name}:#{check_name}")
404
+ result_key = "#{client_name}:#{check_name}"
405
+ settings.redis.del("result:#{result_key}")
406
+ settings.redis.del("history:#{result_key}")
386
407
  end
387
- settings.redis.del("history:#{client_name}")
408
+ settings.redis.del("result:#{client_name}")
388
409
  end
389
410
  end
390
411
  end
@@ -428,7 +449,7 @@ module Sensu
428
449
  :subscribers => subscribers
429
450
  })
430
451
  subscribers.uniq.each do |exchange_name|
431
- settings.transport.publish(:fanout, exchange_name, MultiJson.dump(payload)) do |info|
452
+ settings.transport.publish(:fanout, exchange_name.to_s, MultiJson.dump(payload)) do |info|
432
453
  if info[:error]
433
454
  settings.logger.error("failed to publish check request", {
434
455
  :exchange_name => exchange_name,
@@ -1,7 +1,7 @@
1
1
  module Sensu
2
2
  unless defined?(Sensu::VERSION)
3
3
  # Sensu release version.
4
- VERSION = "0.17.2"
4
+ VERSION = "0.18.0.beta"
5
5
 
6
6
  # Sensu check severities.
7
7
  SEVERITIES = %w[ok warning critical unknown]
data/lib/sensu/daemon.rb CHANGED
@@ -4,7 +4,7 @@ gem "multi_json", "1.11.0"
4
4
 
5
5
  gem "sensu-em", "2.4.1"
6
6
  gem "sensu-logger", "1.0.0"
7
- gem "sensu-settings", "1.3.0"
7
+ gem "sensu-settings", "1.4.0"
8
8
  gem "sensu-extension", "1.1.2"
9
9
  gem "sensu-extensions", "1.2.0"
10
10
  gem "sensu-transport", "2.4.0"
@@ -49,7 +49,7 @@ module Sensu
49
49
  @logger.debug("updating client registry", :client => client)
50
50
  @redis.set("client:#{client[:name]}", MultiJson.dump(client)) do
51
51
  @redis.sadd("clients", client[:name]) do
52
- callback.call
52
+ callback.call(client)
53
53
  end
54
54
  end
55
55
  end
@@ -178,13 +178,16 @@ module Sensu
178
178
  # check execution across a number of Sensu clients. JSON
179
179
  # serialization is used for storing check result data.
180
180
  #
181
- # @param result [Hash]
182
- def aggregate_check_result(result)
183
- @logger.debug("adding check result to aggregate", :result => result)
184
- check = result[:check]
181
+ # @param client [Hash]
182
+ # @param check [Hash]
183
+ def aggregate_check_result(client, check)
184
+ @logger.debug("adding check result to aggregate", {
185
+ :client => client,
186
+ :check => check
187
+ })
185
188
  result_set = "#{check[:name]}:#{check[:issued]}"
186
189
  result_data = MultiJson.dump(:output => check[:output], :status => check[:status])
187
- @redis.hset("aggregation:#{result_set}", result[:client], result_data) do
190
+ @redis.hset("aggregation:#{result_set}", client[:name], result_data) do
188
191
  SEVERITIES.each do |severity|
189
192
  @redis.hsetnx("aggregate:#{result_set}", severity, 0)
190
193
  end
@@ -199,31 +202,34 @@ module Sensu
199
202
  end
200
203
  end
201
204
 
202
- # Store check result data. This method stores the 21 most recent
203
- # check result statuses for a client/check pair, this history
204
- # is used for event context and flap detection. The check
205
- # execution timestamp is also stored, to provide an indication
206
- # of how recent the data is.
205
+ # Store check result data. This method stores check result data
206
+ # and the 21 most recent check result statuses for a client/check
207
+ # pair, this history is used for event context and flap detection.
208
+ # The check execution timestamp is also stored, to provide an
209
+ # indication of how recent the data is.
207
210
  #
208
211
  # @param client [Hash]
209
212
  # @param check [Hash]
210
213
  # @param callback [Proc] to call when the check result data has
211
214
  # been stored (history, etc).
212
215
  def store_check_result(client, check, &callback)
213
- @redis.sadd("history:#{client[:name]}", check[:name])
216
+ @logger.debug("storing check result", :check => check)
217
+ @redis.sadd("result:#{client[:name]}", check[:name])
214
218
  result_key = "#{client[:name]}:#{check[:name]}"
215
- history_key = "history:#{result_key}"
216
- @redis.rpush(history_key, check[:status]) do
217
- @redis.set("execution:#{result_key}", check[:executed])
218
- @redis.ltrim(history_key, -21, -1)
219
- callback.call
219
+ check_truncated = check.merge(:output => check[:output][0..256])
220
+ @redis.set("result:#{result_key}", MultiJson.dump(check_truncated)) do
221
+ history_key = "history:#{result_key}"
222
+ @redis.rpush(history_key, check[:status]) do
223
+ @redis.ltrim(history_key, -21, -1)
224
+ callback.call
225
+ end
220
226
  end
221
227
  end
222
228
 
223
229
  # Fetch the execution history for a client/check pair, the 21
224
230
  # most recent check result statuses. This method also calculates
225
231
  # the total state change percentage for the history, this value
226
- # is use for check state flat detection, using a similar
232
+ # is use for check state flap detection, using a similar
227
233
  # algorithm to Nagios:
228
234
  # http://nagios.sourceforge.net/docs/3_0/flapping.html
229
235
  #
@@ -332,39 +338,73 @@ module Sensu
332
338
  end
333
339
  end
334
340
 
341
+ # Create a blank client (data) and add it to the client
342
+ # registry. Only the client name is known, the other client
343
+ # attributes must be updated via the API (POST /clients:client).
344
+ # Dynamically created clients and those updated via the API will
345
+ # have client keepalives disabled, `:keepalives` is set to
346
+ # `false`.
347
+ #
348
+ # @param name [Hash] to use for the client.
349
+ # @param callback [Proc] to be called with the dynamically
350
+ # created client data.
351
+ def create_client(name, &callback)
352
+ client = {
353
+ :name => name,
354
+ :address => "unknown",
355
+ :subscriptions => [],
356
+ :keepalives => false
357
+ }
358
+ update_client_registry(client, &callback)
359
+ end
360
+
361
+ # Retrieve a client (data) from Redis if it exists. If a client
362
+ # does not already exist, create one (a blank) using the
363
+ # `client_key` as the client name. Dynamically create client
364
+ # data can be updated using the API (POST /clients/:client).
365
+ #
366
+ # @param result [Hash] data.
367
+ # @param callback [Proc] to be called with client data, either
368
+ # retrieved from Redis, or dynamically created.
369
+ def retrieve_client(result, &callback)
370
+ client_key = result[:check][:source] || result[:client]
371
+ @redis.get("client:#{client_key}") do |client_json|
372
+ unless client_json.nil?
373
+ client = MultiJson.load(client_json)
374
+ callback.call(client)
375
+ else
376
+ create_client(client_key, &callback)
377
+ end
378
+ end
379
+ end
380
+
335
381
  # Process a check result, storing its data, inspecting its
336
382
  # contents, and taking the appropriate actions (eg. update the
337
383
  # event registry). A check result must have a valid client name,
338
- # associated with a client in the registry. Results without a
339
- # valid client are discarded, to keep the system "correct". If a
340
- # local check definition exists for the check name, and the
341
- # check result is not from a standalone check execution, it's
342
- # merged with the check result for more context.
384
+ # associated with a client in the registry or one will be
385
+ # created. If a local check definition exists for the check
386
+ # name, and the check result is not from a standalone check
387
+ # execution, it's merged with the check result for more context.
343
388
  #
344
389
  # @param result [Hash] data.
345
390
  def process_check_result(result)
346
391
  @logger.debug("processing result", :result => result)
347
- @redis.get("client:#{result[:client]}") do |client_json|
348
- unless client_json.nil?
349
- client = MultiJson.load(client_json)
350
- check = case
351
- when @settings.check_exists?(result[:check][:name]) && !result[:check][:standalone]
352
- @settings[:checks][result[:check][:name]].merge(result[:check])
353
- else
354
- result[:check]
355
- end
356
- aggregate_check_result(result) if check[:aggregate]
357
- store_check_result(client, check) do
358
- check_history(client, check) do |history, total_state_change|
359
- check[:history] = history
360
- check[:total_state_change] = total_state_change
361
- update_event_registry(client, check) do |event|
362
- process_event(event)
363
- end
392
+ retrieve_client(result) do |client|
393
+ check = case
394
+ when @settings.check_exists?(result[:check][:name]) && !result[:check][:standalone]
395
+ @settings[:checks][result[:check][:name]].merge(result[:check])
396
+ else
397
+ result[:check]
398
+ end
399
+ aggregate_check_result(client, check) if check[:aggregate]
400
+ store_check_result(client, check) do
401
+ check_history(client, check) do |history, total_state_change|
402
+ check[:history] = history
403
+ check[:total_state_change] = total_state_change
404
+ update_event_registry(client, check) do |event|
405
+ process_event(event)
364
406
  end
365
407
  end
366
- else
367
- @logger.warn("client not in registry", :client => result[:client])
368
408
  end
369
409
  end
370
410
  end
@@ -549,6 +589,7 @@ module Sensu
549
589
  @redis.get("client:#{client_name}") do |client_json|
550
590
  unless client_json.nil?
551
591
  client = MultiJson.load(client_json)
592
+ next if client[:keepalives] == false
552
593
  check = create_keepalive_check(client)
553
594
  time_since_last_keepalive = Time.now.to_i - client[:timestamp]
554
595
  check[:output] = "No keepalive sent from client for "
data/sensu.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.add_dependency "eventmachine", "1.0.3"
20
20
  s.add_dependency "sensu-em", "2.4.1"
21
21
  s.add_dependency "sensu-logger", "1.0.0"
22
- s.add_dependency "sensu-settings", "1.3.0"
22
+ s.add_dependency "sensu-settings", "1.4.0"
23
23
  s.add_dependency "sensu-extension", "1.1.2"
24
24
  s.add_dependency "sensu-extensions", "1.2.0"
25
25
  s.add_dependency "sensu-transport", "2.4.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.2
4
+ version: 0.18.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Porter
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-08 00:00:00.000000000 Z
12
+ date: 2015-04-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
@@ -87,14 +87,14 @@ dependencies:
87
87
  requirements:
88
88
  - - '='
89
89
  - !ruby/object:Gem::Version
90
- version: 1.3.0
90
+ version: 1.4.0
91
91
  type: :runtime
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - '='
96
96
  - !ruby/object:Gem::Version
97
- version: 1.3.0
97
+ version: 1.4.0
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: sensu-extension
100
100
  requirement: !ruby/object:Gem::Requirement
@@ -297,9 +297,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
297
297
  version: '0'
298
298
  required_rubygems_version: !ruby/object:Gem::Requirement
299
299
  requirements:
300
- - - ">="
300
+ - - ">"
301
301
  - !ruby/object:Gem::Version
302
- version: '0'
302
+ version: 1.3.1
303
303
  requirements: []
304
304
  rubyforge_project:
305
305
  rubygems_version: 2.2.2