sensu 0.21.0 → 0.22.0
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 +39 -0
- data/exe/sensu-install +44 -20
- data/lib/sensu/api/process.rb +1 -0
- data/lib/sensu/client/process.rb +4 -1
- data/lib/sensu/client/socket.rb +20 -10
- data/lib/sensu/constants.rb +1 -1
- data/lib/sensu/daemon.rb +1 -1
- data/lib/sensu/server/process.rb +124 -20
- data/sensu.gemspec +2 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc83c24129d23bc39b4f06d48b7cdba8abf0f851
|
4
|
+
data.tar.gz: 6aca4babe99fb2e63e610204532322af7714f726
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dae436f84c219b052231da1d79be00a829f312c823020fa9e6c535555c1995ed69fec6c051da467ec3f7a8633333f1365b068e13f68da007d82f34e56a43af93
|
7
|
+
data.tar.gz: a164bcfc4ce2673eb3fafd41276d7074659893864f634de39a2832435f01469a4a3e49424ccd25ab5dc5d82b57aed7d86ffe3d5deb4d11404a310ece5c7c43f5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,44 @@
|
|
1
|
+
## 0.22.0 - 2016-01-29
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
Client registration events are optionally created and processed (handled,
|
6
|
+
etc.) when a client is first added to the client registry. To enable this
|
7
|
+
functionality, configure a "registration" handler definition on Sensu
|
8
|
+
server(s), or define a client specific registration handler in the client
|
9
|
+
definition, e.g. `{"client": "registration": {"handler": "debug"}}`.
|
10
|
+
|
11
|
+
Client auto de-registration on sensu-client process stop is now supported
|
12
|
+
by the Sensu package init script. Setting `CLIENT_DEREGISTER_ON_STOP=true`
|
13
|
+
and `CLIENT_DEREGISTER_HANDLER=example` in `/etc/default/sensu` will cause
|
14
|
+
the Sensu client to publish a check result to trigger the event handler
|
15
|
+
named "example", before its process stops.
|
16
|
+
|
17
|
+
Added support for Sensu client signatures, used to sign client keepalive
|
18
|
+
and check result transport messages, for the purposes of source
|
19
|
+
(publisher) verification. The client definition attribute "signature" is
|
20
|
+
used to set the client signature, e.g. `"signature": "6zvyb8lm7fxcs7yw"`.
|
21
|
+
A client signature can only be set once, the client must be deleted from
|
22
|
+
the registry before its signature can be changed or removed. Client
|
23
|
+
keepalives and check results that are not signed with the correct
|
24
|
+
signature are logged (warn) and discarded. This feature is NOT a
|
25
|
+
replacement for existing and proven security measures.
|
26
|
+
|
27
|
+
The Sensu plugin installation tool, `sensu-install`, will no longer
|
28
|
+
install a plugin if a or specified version has already been installed.
|
29
|
+
|
30
|
+
The Sensu client socket now supports UTF-8 encoding.
|
31
|
+
|
1
32
|
## 0.21.0 - 2015-11-13
|
2
33
|
|
34
|
+
### Important
|
35
|
+
|
36
|
+
Using the Sensu embedded Ruby for Sensu checks, mutators, and handlers has
|
37
|
+
become a common practice. The Sensu 0.21 packages changed the default
|
38
|
+
value of `EMBEDDED_RUBY` from `false` to `true`, allowing Sensu plugins to
|
39
|
+
use the embedded Ruby by default. This change makes it easier to get
|
40
|
+
started with Sensu.
|
41
|
+
|
3
42
|
### Features
|
4
43
|
|
5
44
|
Added a Sensu plugin installation tool, `sensu-install`, making it easier
|
data/exe/sensu-install
CHANGED
@@ -36,36 +36,60 @@ module Sensu
|
|
36
36
|
puts "[SENSU-INSTALL] #{message}"
|
37
37
|
end
|
38
38
|
|
39
|
+
def plugin_gem_installed?(raw_gem, options={})
|
40
|
+
log "determining if Sensu plugin gem '#{raw_gem}' is already installed ..."
|
41
|
+
gem_name, gem_version = raw_gem.split(":")
|
42
|
+
gem_command = "gem list -i #{gem_name}"
|
43
|
+
gem_command << " --version '#{gem_version}'" if gem_version
|
44
|
+
log gem_command if options[:verbose]
|
45
|
+
if system(gem_command)
|
46
|
+
log "Sensu plugin gem '#{gem_name}' has already been installed"
|
47
|
+
true
|
48
|
+
else
|
49
|
+
log "Sensu plugin gem '#{gem_name}' has not been installed" if options[:verbose]
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def install_plugin_gem(raw_gem, options={})
|
55
|
+
log "installing Sensu plugin gem '#{raw_gem}'"
|
56
|
+
gem_name, gem_version = raw_gem.split(":")
|
57
|
+
gem_command = "gem install #{gem_name}"
|
58
|
+
gem_command << " --version '#{gem_version}'" if gem_version
|
59
|
+
gem_command << " --no-ri --no-rdoc"
|
60
|
+
gem_command << " --verbose" if options[:verbose]
|
61
|
+
gem_command << " --source #{options[:source]}" if options[:source]
|
62
|
+
log gem_command if options[:verbose]
|
63
|
+
unless system(gem_command)
|
64
|
+
log "failed to install Sensu plugin gem '#{gem_name}'"
|
65
|
+
log "you can run the sensu-install command again with --verbose for more info" unless options[:verbose]
|
66
|
+
log "please take note of any failure messages above"
|
67
|
+
log "make sure you have build tools installed (e.g. gcc)"
|
68
|
+
log "trying to determine the Sensu plugin homepage for #{gem_name} ..."
|
69
|
+
system("gem specification #{gem_name} -r | grep homepage")
|
70
|
+
exit 2
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
39
74
|
def install_plugins(plugins, options={})
|
40
75
|
log "installing Sensu plugins ..."
|
41
76
|
log "provided Sensu plugins: #{plugins}" if options[:verbose]
|
42
|
-
|
77
|
+
plugin_gems = plugins.map do |plugin|
|
43
78
|
if plugin.start_with?("sensu-plugins-")
|
44
79
|
plugin
|
45
80
|
else
|
46
81
|
"sensu-plugins-#{plugin}"
|
47
82
|
end
|
48
83
|
end
|
49
|
-
log "Sensu plugin gems
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
gems
|
54
|
-
|
55
|
-
|
56
|
-
log gem_command if options[:verbose]
|
57
|
-
unless system(gem_command)
|
58
|
-
log "failed to install Sensu plugin gem: #{gem}"
|
59
|
-
log "you can run the sensu-install command again with --verbose for more info" unless options[:verbose]
|
60
|
-
log "please take note of any failure messages above"
|
61
|
-
log "make sure you have build tools installed (e.g. gcc)"
|
62
|
-
log "trying to determine Sensu plugin homepage for #{gem} ..."
|
63
|
-
clean_gem = gem.split(":").first
|
64
|
-
system("gem specification #{clean_gem} -r | grep homepage")
|
65
|
-
exit 2
|
66
|
-
end
|
84
|
+
log "compiled Sensu plugin gems: #{plugin_gems}" if options[:verbose]
|
85
|
+
plugin_gems.reject! do |raw_gem|
|
86
|
+
plugin_gem_installed?(raw_gem, options)
|
87
|
+
end
|
88
|
+
log "Sensu plugin gems to be installed: #{plugin_gems}"
|
89
|
+
plugin_gems.each do |raw_gem|
|
90
|
+
install_plugin_gem(raw_gem, options)
|
67
91
|
end
|
68
|
-
log "successfully
|
92
|
+
log "successfully installed Sensu plugins: #{plugins}"
|
69
93
|
end
|
70
94
|
|
71
95
|
def run
|
data/lib/sensu/api/process.rb
CHANGED
@@ -449,6 +449,7 @@ module Sensu
|
|
449
449
|
settings.logger.info("deleting client from registry", :client_name => client_name)
|
450
450
|
settings.redis.srem("clients", client_name) do
|
451
451
|
settings.redis.del("client:#{client_name}")
|
452
|
+
settings.redis.del("client:#{client_name}:signature")
|
452
453
|
settings.redis.del("events:#{client_name}")
|
453
454
|
settings.redis.smembers("result:#{client_name}") do |checks|
|
454
455
|
checks.each do |check_name|
|
data/lib/sensu/client/process.rb
CHANGED
@@ -77,7 +77,9 @@ module Sensu
|
|
77
77
|
# check result is composed of a client (name) and a check
|
78
78
|
# definition, containing check `:output` and `:status`. JSON
|
79
79
|
# serialization is used when publishing the check result payload
|
80
|
-
# to the transport pipe.
|
80
|
+
# to the transport pipe. The check result is signed with the
|
81
|
+
# client signature if configured, for source validation.
|
82
|
+
# Transport errors are logged.
|
81
83
|
#
|
82
84
|
# @param check [Hash]
|
83
85
|
def publish_check_result(check)
|
@@ -85,6 +87,7 @@ module Sensu
|
|
85
87
|
:client => @settings[:client][:name],
|
86
88
|
:check => check
|
87
89
|
}
|
90
|
+
payload[:signature] = @settings[:client][:signature] if @settings[:client][:signature]
|
88
91
|
@logger.info("publishing check result", :payload => payload)
|
89
92
|
@transport.publish(:direct, "results", MultiJson.dump(payload)) do |info|
|
90
93
|
if info[:error]
|
data/lib/sensu/client/socket.rb
CHANGED
@@ -141,9 +141,7 @@ module Sensu
|
|
141
141
|
:client => @settings[:client][:name],
|
142
142
|
:check => check.merge(:issued => Time.now.to_i)
|
143
143
|
}
|
144
|
-
@logger.info("publishing check result",
|
145
|
-
:payload => payload
|
146
|
-
})
|
144
|
+
@logger.info("publishing check result", :payload => payload)
|
147
145
|
@transport.publish(:direct, "results", MultiJson.dump(payload))
|
148
146
|
end
|
149
147
|
|
@@ -186,16 +184,14 @@ module Sensu
|
|
186
184
|
#
|
187
185
|
# @param [String] data to be processed.
|
188
186
|
def process_data(data)
|
189
|
-
if data.
|
190
|
-
@logger.warn("socket received non-ascii characters")
|
191
|
-
respond("invalid")
|
192
|
-
elsif data.strip == "ping"
|
187
|
+
if data.strip == "ping"
|
193
188
|
@logger.debug("socket received ping")
|
194
189
|
respond("pong")
|
195
190
|
else
|
196
|
-
@logger.debug("socket received data",
|
197
|
-
|
198
|
-
|
191
|
+
@logger.debug("socket received data", :data => data)
|
192
|
+
unless valid_utf8?(data)
|
193
|
+
@logger.warn("data from socket is not a valid UTF-8 sequence, processing it anyways", :data => data)
|
194
|
+
end
|
199
195
|
begin
|
200
196
|
parse_check_result(data)
|
201
197
|
rescue => error
|
@@ -208,6 +204,20 @@ module Sensu
|
|
208
204
|
end
|
209
205
|
end
|
210
206
|
|
207
|
+
# Tests if the argument (data) is a valid UTF-8 sequence.
|
208
|
+
#
|
209
|
+
# @param [String] data to be tested.
|
210
|
+
def valid_utf8?(data)
|
211
|
+
utf8_string_pattern = /\A([\x00-\x7f]|
|
212
|
+
[\xc2-\xdf][\x80-\xbf]|
|
213
|
+
\xe0[\xa0-\xbf][\x80-\xbf]|
|
214
|
+
[\xe1-\xef][\x80-\xbf]{2}|
|
215
|
+
\xf0[\x90-\xbf][\x80-\xbf]{2}|
|
216
|
+
[\xf1-\xf7][\x80-\xbf]{3})*\z/nx
|
217
|
+
data = data.force_encoding('BINARY') if data.respond_to?(:force_encoding)
|
218
|
+
return data =~ utf8_string_pattern
|
219
|
+
end
|
220
|
+
|
211
221
|
# This method is called whenever data is received. For UDP, it
|
212
222
|
# will only be called once, the original data length can be
|
213
223
|
# expected. For TCP, this method may be called several times, data
|
data/lib/sensu/constants.rb
CHANGED
data/lib/sensu/daemon.rb
CHANGED
data/lib/sensu/server/process.rb
CHANGED
@@ -37,19 +37,102 @@ module Sensu
|
|
37
37
|
@handling_event_count = 0
|
38
38
|
end
|
39
39
|
|
40
|
+
# Create a registration check definition for a client. Client
|
41
|
+
# definitions may contain `:registration` configuration,
|
42
|
+
# containing custom attributes and handler information. By
|
43
|
+
# default, the registration check definition sets the `:handler`
|
44
|
+
# to `registration`. If the client provides its own
|
45
|
+
# `:registration` configuration, it's deep merged with the
|
46
|
+
# defaults. The check `:name`, `:output`, `:status`, `:issued`,
|
47
|
+
# and `:executed` values are always overridden to guard against
|
48
|
+
# an invalid definition.
|
49
|
+
def create_registration_check(client)
|
50
|
+
check = {:handler => "registration"}
|
51
|
+
if client.has_key?(:registration)
|
52
|
+
check = deep_merge(check, client[:registration])
|
53
|
+
end
|
54
|
+
timestamp = Time.now.to_i
|
55
|
+
overrides = {
|
56
|
+
:name => "registration",
|
57
|
+
:output => "new client registration",
|
58
|
+
:status => 1,
|
59
|
+
:issued => timestamp,
|
60
|
+
:executed => timestamp
|
61
|
+
}
|
62
|
+
check.merge(overrides)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Create and process a client registration event. A registration
|
66
|
+
# event is created when a Sensu client is first added to the
|
67
|
+
# client registry. The `create_registration_check()` method is
|
68
|
+
# called to create a registration check definition for the
|
69
|
+
# client.
|
70
|
+
#
|
71
|
+
# @param client [Hash] definition.
|
72
|
+
def create_client_registration_event(client)
|
73
|
+
event = {
|
74
|
+
:id => random_uuid,
|
75
|
+
:client => client,
|
76
|
+
:check => create_registration_check(client),
|
77
|
+
:occurrences => 1,
|
78
|
+
:action => :create,
|
79
|
+
:timestamp => Time.now.to_i
|
80
|
+
}
|
81
|
+
process_event(event)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Process an initial client registration, when it is first added
|
85
|
+
# to the client registry. If a registration handler is defined
|
86
|
+
# or the client specifies one, a client registration event is
|
87
|
+
# created and processed (handled, etc.) for the client
|
88
|
+
# (`create_client_registration_event()`).
|
89
|
+
#
|
90
|
+
# @param client [Hash] definition.
|
91
|
+
def process_client_registration(client)
|
92
|
+
if @settings.handler_exists?("registration") || client[:registration]
|
93
|
+
create_client_registration_event(client)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
40
97
|
# Update the Sensu client registry, stored in Redis. Sensu
|
41
98
|
# client data is used to provide additional event context and
|
42
|
-
# enable agent health monitoring.
|
43
|
-
#
|
99
|
+
# enable agent health monitoring. The client registry supports
|
100
|
+
# client signatures, unique string identifiers used for
|
101
|
+
# keepalive and result source verification. If a client has a
|
102
|
+
# signature, all further registry updates for the client must
|
103
|
+
# have the same signature. A client can begin to use a signature
|
104
|
+
# if one was not previously configured. JSON serialization is
|
105
|
+
# used for the stored client data.
|
44
106
|
#
|
45
107
|
# @param client [Hash]
|
46
|
-
# @param callback [Proc] to call
|
47
|
-
#
|
108
|
+
# @param callback [Proc] to call with the success status
|
109
|
+
# (true/false) indicating if the client data has been added to
|
110
|
+
# (or updated) the registry or discarded due to client signature
|
111
|
+
# mismatch.
|
48
112
|
def update_client_registry(client, &callback)
|
49
113
|
@logger.debug("updating client registry", :client => client)
|
50
|
-
|
51
|
-
|
52
|
-
|
114
|
+
client_key = "client:#{client[:name]}"
|
115
|
+
signature_key = "#{client_key}:signature"
|
116
|
+
@redis.setnx(signature_key, client[:signature]) do |created|
|
117
|
+
process_client_registration(client) if created
|
118
|
+
@redis.get(signature_key) do |signature|
|
119
|
+
if signature.empty? && client[:signature]
|
120
|
+
@redis.set(signature_key, client[:signature])
|
121
|
+
end
|
122
|
+
if signature.empty? || (client[:signature] == signature)
|
123
|
+
@redis.set(client_key, MultiJson.dump(client)) do
|
124
|
+
@redis.sadd("clients", client[:name]) do
|
125
|
+
callback.call(true) if callback
|
126
|
+
end
|
127
|
+
end
|
128
|
+
else
|
129
|
+
@logger.warn("invalid client signature", {
|
130
|
+
:client => client,
|
131
|
+
:signature => signature
|
132
|
+
})
|
133
|
+
@logger.warn("not updating client in the registry", :client => client)
|
134
|
+
callback.call(false) if callback
|
135
|
+
end
|
53
136
|
end
|
54
137
|
end
|
55
138
|
end
|
@@ -381,13 +464,17 @@ module Sensu
|
|
381
464
|
:keepalives => false,
|
382
465
|
:version => VERSION
|
383
466
|
}
|
384
|
-
update_client_registry(client
|
467
|
+
update_client_registry(client) do
|
468
|
+
callback.call(client)
|
469
|
+
end
|
385
470
|
end
|
386
471
|
|
387
472
|
# Retrieve a client (data) from Redis if it exists. If a client
|
388
473
|
# does not already exist, create one (a blank) using the
|
389
474
|
# `client_key` as the client name. Dynamically create client
|
390
|
-
# data can be updated using the API (POST /clients/:client).
|
475
|
+
# data can be updated using the API (POST /clients/:client). If
|
476
|
+
# a client does exist and it has a client signature, the check
|
477
|
+
# result must have a matching signature or it is discarded.
|
391
478
|
#
|
392
479
|
# @param result [Hash] data.
|
393
480
|
# @param callback [Proc] to be called with client data, either
|
@@ -397,7 +484,19 @@ module Sensu
|
|
397
484
|
@redis.get("client:#{client_key}") do |client_json|
|
398
485
|
unless client_json.nil?
|
399
486
|
client = MultiJson.load(client_json)
|
400
|
-
|
487
|
+
if client[:signature]
|
488
|
+
if client[:signature] == result[:signature]
|
489
|
+
callback.call(client)
|
490
|
+
else
|
491
|
+
@logger.warn("invalid check result signature", {
|
492
|
+
:result => result,
|
493
|
+
:client => client
|
494
|
+
})
|
495
|
+
@logger.warn("not retrieving client from the registry", :result => result)
|
496
|
+
end
|
497
|
+
else
|
498
|
+
callback.call(client)
|
499
|
+
end
|
401
500
|
else
|
402
501
|
create_client(client_key, &callback)
|
403
502
|
end
|
@@ -572,9 +671,11 @@ module Sensu
|
|
572
671
|
|
573
672
|
# Publish a check result to the transport for processing. A
|
574
673
|
# check result is composed of a client name and a check
|
575
|
-
# definition, containing check `:output` and `:status`.
|
576
|
-
#
|
577
|
-
#
|
674
|
+
# definition, containing check `:output` and `:status`. A client
|
675
|
+
# signature is added to the check result payload if one is
|
676
|
+
# registered for the client. JSON serialization is used when
|
677
|
+
# publishing the check result payload to the transport pipe.
|
678
|
+
# Transport errors are logged.
|
578
679
|
#
|
579
680
|
# @param client_name [String]
|
580
681
|
# @param check [Hash]
|
@@ -583,13 +684,16 @@ module Sensu
|
|
583
684
|
:client => client_name,
|
584
685
|
:check => check
|
585
686
|
}
|
586
|
-
@
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
687
|
+
@redis.get("client:#{client_name}:signature") do |signature|
|
688
|
+
payload[:signature] = signature if signature
|
689
|
+
@logger.debug("publishing check result", :payload => payload)
|
690
|
+
@transport.publish(:direct, "results", MultiJson.dump(payload)) do |info|
|
691
|
+
if info[:error]
|
692
|
+
@logger.error("failed to publish check result", {
|
693
|
+
:payload => payload,
|
694
|
+
:error => info[:error].to_s
|
695
|
+
})
|
696
|
+
end
|
593
697
|
end
|
594
698
|
end
|
595
699
|
end
|
data/sensu.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.add_dependency "uuidtools", "2.1.5"
|
19
19
|
s.add_dependency "eventmachine", "1.0.8"
|
20
20
|
s.add_dependency "sensu-logger", "1.1.0"
|
21
|
-
s.add_dependency "sensu-settings", "3.
|
21
|
+
s.add_dependency "sensu-settings", "3.3.0"
|
22
22
|
s.add_dependency "sensu-extension", "1.3.0"
|
23
23
|
s.add_dependency "sensu-extensions", "1.4.0"
|
24
24
|
s.add_dependency "sensu-transport", "3.3.0"
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_development_dependency "rake", "~> 10.3"
|
32
32
|
s.add_development_dependency "rspec", "~> 3.0.0"
|
33
33
|
s.add_development_dependency "em-http-request", "~> 1.1"
|
34
|
+
s.add_development_dependency "addressable", "2.3.8"
|
34
35
|
|
35
36
|
s.files = Dir.glob("{exe,lib}/**/*") + %w[sensu.gemspec README.md CHANGELOG.md MIT-LICENSE.txt]
|
36
37
|
s.executables = s.files.grep(%r{^exe/}) { |file| File.basename(file) }
|
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.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Porter
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-01-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -73,14 +73,14 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - '='
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 3.
|
76
|
+
version: 3.3.0
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - '='
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: 3.
|
83
|
+
version: 3.3.0
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: sensu-extension
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -235,6 +235,20 @@ dependencies:
|
|
235
235
|
- - "~>"
|
236
236
|
- !ruby/object:Gem::Version
|
237
237
|
version: '1.1'
|
238
|
+
- !ruby/object:Gem::Dependency
|
239
|
+
name: addressable
|
240
|
+
requirement: !ruby/object:Gem::Requirement
|
241
|
+
requirements:
|
242
|
+
- - '='
|
243
|
+
- !ruby/object:Gem::Version
|
244
|
+
version: 2.3.8
|
245
|
+
type: :development
|
246
|
+
prerelease: false
|
247
|
+
version_requirements: !ruby/object:Gem::Requirement
|
248
|
+
requirements:
|
249
|
+
- - '='
|
250
|
+
- !ruby/object:Gem::Version
|
251
|
+
version: 2.3.8
|
238
252
|
description: A monitoring framework that aims to be simple, malleable, and scalable.
|
239
253
|
email:
|
240
254
|
- portertech@gmail.com
|