sensu 0.18.1 → 0.19.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 +4 -4
- data/CHANGELOG.md +26 -0
- data/lib/sensu/api/process.rb +61 -0
- data/lib/sensu/client/process.rb +30 -8
- data/lib/sensu/constants.rb +1 -1
- data/lib/sensu/daemon.rb +9 -6
- data/lib/sensu/redis.rb +2 -2
- data/lib/sensu/server/process.rb +71 -5
- data/sensu.gemspec +3 -3
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b4319c7b86de73fef4f4649e98a5d44639d195b
|
4
|
+
data.tar.gz: 5bbd3e47ec44b43845edfdd0fd4eac1c07b3b4d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aad30b0391244ae28bab870fda5fd5f830fba3765eed6eb74648a504a2cb0317b195c427ebe4a191b73f7b54cabbb7c10331ffb17b5ff5356ac31a961b17ed3
|
7
|
+
data.tar.gz: 9a870dcc2e466b4c0865c72c78552115dbd71059812ec4d8026461adfb7635d027de16ad297fe5d175791e990c41304e7ac569b4a504b5c60a8f11ea1d7e6a2b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## 0.19.0 - TBD
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
Redis Sensu transport, a built-in alternative to the default RabbitMQ
|
6
|
+
transport. The Redis transport is currently considered experimental.
|
7
|
+
Configuring the transport name to be `redis` will enable the Redis
|
8
|
+
transport instead of RabbitMQ, e.g. `{"transport": {"name": "redis"}}`.
|
9
|
+
|
10
|
+
Round-robin client subscriptions, allowing check requests to be sent to a
|
11
|
+
single client in a subscription in a round-robin fashion. To create a
|
12
|
+
round-robin subscription, start its name with `roundrobin:` to specify the
|
13
|
+
type, e.g. "roundrobin:elasticsearch". Any check that targets the
|
14
|
+
"roundrobin:elasticsearch" subscription will have its check requests sent
|
15
|
+
to clients in a round-robin fashion.
|
16
|
+
|
17
|
+
Stale check result detection, using a defined check `ttl` and stored check
|
18
|
+
results. Sensu is now able to monitor check results, ensuring that checks
|
19
|
+
with a defined TTL (time to live) continue to be executed by clients. For
|
20
|
+
example, a standalone check could have an interval of 30 seconds and a ttl
|
21
|
+
of 50 seconds, Sensu would expect a result at least once every 50 seconds.
|
22
|
+
|
23
|
+
Check results API routes/endpoints: `/results`, `/results/:client`, and
|
24
|
+
`/results/:client/:check`. These new check result API routes/endpoints
|
25
|
+
enable new tooling, such as green light dashboards.
|
26
|
+
|
1
27
|
## 0.18.1 - 2015-05-11
|
2
28
|
|
3
29
|
### Other
|
data/lib/sensu/api/process.rb
CHANGED
@@ -725,6 +725,67 @@ module Sensu
|
|
725
725
|
end
|
726
726
|
end
|
727
727
|
end
|
728
|
+
|
729
|
+
aget "/results/?" do
|
730
|
+
response = Array.new
|
731
|
+
settings.redis.smembers("clients") do |clients|
|
732
|
+
unless clients.empty?
|
733
|
+
clients.each_with_index do |client_name, client_index|
|
734
|
+
settings.redis.smembers("result:#{client_name}") do |checks|
|
735
|
+
unless checks.empty?
|
736
|
+
checks.each_with_index do |check_name, check_index|
|
737
|
+
result_key = "result:#{client_name}:#{check_name}"
|
738
|
+
settings.redis.get(result_key) do |result_json|
|
739
|
+
check = MultiJson.load(result_json)
|
740
|
+
response << {:client => client_name, :check => check}
|
741
|
+
if client_index == clients.size - 1 && check_index == checks.size - 1
|
742
|
+
body MultiJson.dump(response)
|
743
|
+
end
|
744
|
+
end
|
745
|
+
end
|
746
|
+
else
|
747
|
+
body MultiJson.dump(response)
|
748
|
+
end
|
749
|
+
end
|
750
|
+
end
|
751
|
+
else
|
752
|
+
body MultiJson.dump(response)
|
753
|
+
end
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
aget %r{^/results?/([\w\.-]+)/?$} do |client_name|
|
758
|
+
response = Array.new
|
759
|
+
settings.redis.smembers("result:#{client_name}") do |checks|
|
760
|
+
unless checks.empty?
|
761
|
+
checks.each_with_index do |check_name, check_index|
|
762
|
+
result_key = "result:#{client_name}:#{check_name}"
|
763
|
+
settings.redis.get(result_key) do |result_json|
|
764
|
+
check = MultiJson.load(result_json)
|
765
|
+
response << {:client => client_name, :check => check}
|
766
|
+
if check_index == checks.size - 1
|
767
|
+
body MultiJson.dump(response)
|
768
|
+
end
|
769
|
+
end
|
770
|
+
end
|
771
|
+
else
|
772
|
+
not_found!
|
773
|
+
end
|
774
|
+
end
|
775
|
+
end
|
776
|
+
|
777
|
+
aget %r{^/results?/([\w\.-]+)/([\w\.-]+)/?$} do |client_name, check_name|
|
778
|
+
result_key = "result:#{client_name}:#{check_name}"
|
779
|
+
settings.redis.get(result_key) do |result_json|
|
780
|
+
unless result_json.nil?
|
781
|
+
check = MultiJson.load(result_json)
|
782
|
+
response = {:client => client_name, :check => check}
|
783
|
+
body MultiJson.dump(response)
|
784
|
+
else
|
785
|
+
not_found!
|
786
|
+
end
|
787
|
+
end
|
788
|
+
end
|
728
789
|
end
|
729
790
|
end
|
730
791
|
end
|
data/lib/sensu/client/process.rb
CHANGED
@@ -233,20 +233,42 @@ module Sensu
|
|
233
233
|
end
|
234
234
|
end
|
235
235
|
|
236
|
+
# Determine the Sensu transport subscribe options for a
|
237
|
+
# subscription. If a subscription begins with a transport pipe
|
238
|
+
# type, either "direct:" or "roundrobin:", the subscription uses
|
239
|
+
# a direct transport pipe, and the subscription name is used for
|
240
|
+
# both the pipe and the funnel names. If a subscription does not
|
241
|
+
# specify a transport pipe type, a fanout transport pipe is
|
242
|
+
# used, the subscription name is used for the pipe, and a unique
|
243
|
+
# funnel is created for the Sensu client. The unique funnel name
|
244
|
+
# for the Sensu client is created using a combination of the
|
245
|
+
# client name, the Sensu version, and the process start time
|
246
|
+
# (epoch).
|
247
|
+
#
|
248
|
+
# @param subscription [String]
|
249
|
+
# @return [Array] containing the transport subscribe options:
|
250
|
+
# the transport pipe type, pipe, and funnel.
|
251
|
+
def transport_subscribe_options(subscription)
|
252
|
+
_, raw_type = subscription.split(":", 2).reverse
|
253
|
+
case raw_type
|
254
|
+
when "direct", "roundrobin"
|
255
|
+
[:direct, subscription, subscription]
|
256
|
+
else
|
257
|
+
funnel = [@settings[:client][:name], VERSION, start_time].join("-")
|
258
|
+
[:fanout, subscription, funnel]
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
236
262
|
# Set up Sensu client subscriptions. Subscriptions determine the
|
237
|
-
# kinds of check requests the client will receive.
|
238
|
-
# transport funnel is created for the Sensu client, using a
|
239
|
-
# combination of it's name, the Sensu version, and the current
|
240
|
-
# timestamp (epoch). The unique funnel is bound to each
|
241
|
-
# transport pipe, named after the client subscription. The Sensu
|
263
|
+
# kinds of check requests the client will receive. The Sensu
|
242
264
|
# client will receive JSON serialized check requests from its
|
243
|
-
#
|
265
|
+
# subscriptions, that get parsed and processed.
|
244
266
|
def setup_subscriptions
|
245
267
|
@logger.debug("subscribing to client subscriptions")
|
246
268
|
@settings[:client][:subscriptions].each do |subscription|
|
247
269
|
@logger.debug("subscribing to a subscription", :subscription => subscription)
|
248
|
-
|
249
|
-
@transport.subscribe(
|
270
|
+
options = transport_subscribe_options(subscription)
|
271
|
+
@transport.subscribe(*options) do |message_info, message|
|
250
272
|
begin
|
251
273
|
check = MultiJson.load(message)
|
252
274
|
@logger.info("received check request", :check => check)
|
data/lib/sensu/constants.rb
CHANGED
data/lib/sensu/daemon.rb
CHANGED
@@ -4,10 +4,10 @@ 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.
|
7
|
+
gem "sensu-settings", "1.9.0"
|
8
8
|
gem "sensu-extension", "1.1.2"
|
9
9
|
gem "sensu-extensions", "1.2.0"
|
10
|
-
gem "sensu-transport", "
|
10
|
+
gem "sensu-transport", "3.0.0"
|
11
11
|
gem "sensu-spawn", "1.1.0"
|
12
12
|
|
13
13
|
require "time"
|
@@ -31,13 +31,16 @@ module Sensu
|
|
31
31
|
module Daemon
|
32
32
|
include Utilities
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
#
|
37
|
-
#
|
34
|
+
attr_reader :start_time
|
35
|
+
|
36
|
+
# Initialize the Sensu process. Set the start time, initial
|
37
|
+
# service state, set up the logger, load settings, load
|
38
|
+
# extensions, and optionally daemonize the process and/or create a
|
39
|
+
# PID file. A subclass may override this method.
|
38
40
|
#
|
39
41
|
# @param options [Hash]
|
40
42
|
def initialize(options={})
|
43
|
+
@start_time = Time.now.to_i
|
41
44
|
@state = :initializing
|
42
45
|
@timers = {:run => []}
|
43
46
|
setup_logger(options)
|
data/lib/sensu/redis.rb
CHANGED
data/lib/sensu/server/process.rb
CHANGED
@@ -436,6 +436,26 @@ module Sensu
|
|
436
436
|
end
|
437
437
|
end
|
438
438
|
|
439
|
+
# Determine the Sensu transport publish options for a
|
440
|
+
# subscription. If a subscription begins with a transport pipe
|
441
|
+
# type, either "direct:" or "roundrobin:", the subscription uses
|
442
|
+
# a direct transport pipe. If a subscription does not specify a
|
443
|
+
# transport pipe type, a fanout transport pipe is used.
|
444
|
+
#
|
445
|
+
# @param subscription [String]
|
446
|
+
# @return [Array] containing the transport publish options:
|
447
|
+
# the transport pipe type, pipe, and the message to be
|
448
|
+
# published.
|
449
|
+
def transport_publish_options(subscription, message)
|
450
|
+
_, raw_type = subscription.split(":", 2).reverse
|
451
|
+
case raw_type
|
452
|
+
when "direct", "roundrobin"
|
453
|
+
[:direct, subscription, message]
|
454
|
+
else
|
455
|
+
[:fanout, subscription, message]
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
439
459
|
# Publish a check request to the transport. A check request is
|
440
460
|
# composted of a check `:name`, an `:issued` timestamp, and a
|
441
461
|
# check `:command` if available. The check request is published
|
@@ -456,7 +476,8 @@ module Sensu
|
|
456
476
|
:subscribers => check[:subscribers]
|
457
477
|
})
|
458
478
|
check[:subscribers].each do |subscription|
|
459
|
-
|
479
|
+
options = transport_publish_options(subscription, MultiJson.dump(payload))
|
480
|
+
@transport.publish(*options) do |info|
|
460
481
|
if info[:error]
|
461
482
|
@logger.error("failed to publish check request", {
|
462
483
|
:subscription => subscription,
|
@@ -527,11 +548,11 @@ module Sensu
|
|
527
548
|
# serialization is used when publishing the check result payload
|
528
549
|
# to the transport pipe. Transport errors are logged.
|
529
550
|
#
|
530
|
-
# @param
|
551
|
+
# @param client_name [String]
|
531
552
|
# @param check [Hash]
|
532
|
-
def publish_check_result(
|
553
|
+
def publish_check_result(client_name, check)
|
533
554
|
payload = {
|
534
|
-
:client =>
|
555
|
+
:client => client_name,
|
535
556
|
:check => check
|
536
557
|
}
|
537
558
|
@logger.debug("publishing check result", :payload => payload)
|
@@ -606,7 +627,7 @@ module Sensu
|
|
606
627
|
check[:output] << "#{time_since_last_keepalive} seconds ago"
|
607
628
|
check[:status] = 0
|
608
629
|
end
|
609
|
-
publish_check_result(client, check)
|
630
|
+
publish_check_result(client[:name], check)
|
610
631
|
end
|
611
632
|
end
|
612
633
|
end
|
@@ -623,6 +644,50 @@ module Sensu
|
|
623
644
|
end
|
624
645
|
end
|
625
646
|
|
647
|
+
# Determine stale check results, those that have not executed in
|
648
|
+
# a specified amount of time (check TTL). This method iterates
|
649
|
+
# through the client registry and check results for checks with
|
650
|
+
# a defined TTL value (in seconds). If a check result has a
|
651
|
+
# defined TTL, the time since last check execution (in seconds)
|
652
|
+
# is calculated. If the time since last execution is equal to or
|
653
|
+
# greater than the check TTL, a warning check result is
|
654
|
+
# published with the appropriate check output.
|
655
|
+
def determine_stale_check_results
|
656
|
+
@logger.info("determining stale check results")
|
657
|
+
@redis.smembers("clients") do |clients|
|
658
|
+
clients.each do |client_name|
|
659
|
+
@redis.smembers("result:#{client_name}") do |checks|
|
660
|
+
checks.each do |check_name|
|
661
|
+
result_key = "#{client_name}:#{check_name}"
|
662
|
+
@redis.get("result:#{result_key}") do |result_json|
|
663
|
+
unless result_json.nil?
|
664
|
+
check = MultiJson.load(result_json)
|
665
|
+
next unless check[:ttl] && check[:executed]
|
666
|
+
time_since_last_execution = Time.now.to_i - check[:executed]
|
667
|
+
if time_since_last_execution >= check[:ttl]
|
668
|
+
check[:output] = "Last check execution was "
|
669
|
+
check[:output] << "#{time_since_last_execution} seconds ago"
|
670
|
+
check[:status] = 1
|
671
|
+
publish_check_result(client_name, check)
|
672
|
+
end
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
# Set up the check result monitor, a periodic timer to run
|
682
|
+
# `determine_stale_check_results()` every 30 seconds. The timer
|
683
|
+
# is stored in the timers hash under `:leader`.
|
684
|
+
def setup_check_result_monitor
|
685
|
+
@logger.debug("monitoring check results")
|
686
|
+
@timers[:leader] << EM::PeriodicTimer.new(30) do
|
687
|
+
determine_stale_check_results
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
626
691
|
# Prune check result aggregations (aggregates). Sensu only
|
627
692
|
# stores the 20 latest aggregations for a check, to keep the
|
628
693
|
# amount of data stored to a minimum.
|
@@ -672,6 +737,7 @@ module Sensu
|
|
672
737
|
def leader_duties
|
673
738
|
setup_check_request_publisher
|
674
739
|
setup_client_monitor
|
740
|
+
setup_check_result_monitor
|
675
741
|
setup_check_result_aggregation_pruner
|
676
742
|
end
|
677
743
|
|
data/sensu.gemspec
CHANGED
@@ -19,12 +19,12 @@ 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.
|
22
|
+
s.add_dependency "sensu-settings", "1.9.0"
|
23
23
|
s.add_dependency "sensu-extension", "1.1.2"
|
24
24
|
s.add_dependency "sensu-extensions", "1.2.0"
|
25
|
-
s.add_dependency "sensu-transport", "
|
25
|
+
s.add_dependency "sensu-transport", "3.0.0"
|
26
26
|
s.add_dependency "sensu-spawn", "1.1.0"
|
27
|
-
s.add_dependency "em-redis-unified", "0.
|
27
|
+
s.add_dependency "em-redis-unified", "1.0.0"
|
28
28
|
s.add_dependency "sinatra", "1.4.6"
|
29
29
|
s.add_dependency "async_sinatra", "1.2.0"
|
30
30
|
s.add_dependency "thin", "1.5.0" unless RUBY_PLATFORM =~ /java/
|
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.
|
4
|
+
version: 0.19.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-05-
|
12
|
+
date: 2015-05-20 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.
|
90
|
+
version: 1.9.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.
|
97
|
+
version: 1.9.0
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: sensu-extension
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,14 +129,14 @@ dependencies:
|
|
129
129
|
requirements:
|
130
130
|
- - '='
|
131
131
|
- !ruby/object:Gem::Version
|
132
|
-
version:
|
132
|
+
version: 3.0.0
|
133
133
|
type: :runtime
|
134
134
|
prerelease: false
|
135
135
|
version_requirements: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
137
|
- - '='
|
138
138
|
- !ruby/object:Gem::Version
|
139
|
-
version:
|
139
|
+
version: 3.0.0
|
140
140
|
- !ruby/object:Gem::Dependency
|
141
141
|
name: sensu-spawn
|
142
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -157,14 +157,14 @@ dependencies:
|
|
157
157
|
requirements:
|
158
158
|
- - '='
|
159
159
|
- !ruby/object:Gem::Version
|
160
|
-
version: 0.
|
160
|
+
version: 1.0.0
|
161
161
|
type: :runtime
|
162
162
|
prerelease: false
|
163
163
|
version_requirements: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
165
|
- - '='
|
166
166
|
- !ruby/object:Gem::Version
|
167
|
-
version: 0.
|
167
|
+
version: 1.0.0
|
168
168
|
- !ruby/object:Gem::Dependency
|
169
169
|
name: sinatra
|
170
170
|
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:
|
302
|
+
version: 1.3.1
|
303
303
|
requirements: []
|
304
304
|
rubyforge_project:
|
305
305
|
rubygems_version: 2.2.2
|