sensu 0.13.1-java → 0.14.0.beta-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/sensu/api.rb +35 -5
- data/lib/sensu/client.rb +13 -6
- data/lib/sensu/constants.rb +1 -1
- data/lib/sensu/daemon.rb +1 -1
- data/lib/sensu/server.rb +28 -14
- data/lib/sensu/socket.rb +197 -30
- data/sensu.gemspec +4 -4
- metadata +18 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4579594b99d018ca7ec1fe9c2d82d8c3a1796dc6
|
4
|
+
data.tar.gz: 95def4eb9ebce9a3851c3571dfb06a23a126a639
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b185dc5176bb716b33537424da4cbfd81155dcee418911bc6beb980238781fd6b15e1080530294ade66d4666d368f3cd31d43dac7bc85c32178a28c8dabeb642
|
7
|
+
data.tar.gz: 594bddf91fb61f1e97a4ebf4867b967e0457c8eed61a5d24887a3ac2083d2fd9ddc6b03c1a180fbb69aed970546d370dcd51f6eb00587431afe31f73531aa5b5
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## 0.14.0 - TBD
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
Client socket now supports sending a result via a TCP stream. This feature
|
6
|
+
allows check results to have larger output (metrics, backtraces, etc).
|
7
|
+
|
8
|
+
API now supports CORS (configurable).
|
9
|
+
|
10
|
+
### Other
|
11
|
+
|
12
|
+
Child process manager now supports check output larger than the max OS
|
13
|
+
buffer size. The parent process was waiting on the child to exit before
|
14
|
+
closing its write end of the pipe.
|
15
|
+
|
16
|
+
Client & server are now guarding against invalid JSON transport payloads.
|
17
|
+
|
1
18
|
## 0.13.1 - 2014-07-28
|
2
19
|
|
3
20
|
### Other
|
data/lib/sensu/api.rb
CHANGED
@@ -39,13 +39,15 @@ module Sensu
|
|
39
39
|
setup_logger(options)
|
40
40
|
set :logger, @logger
|
41
41
|
load_settings(options)
|
42
|
+
set :api, @settings[:api]
|
42
43
|
set :checks, @settings[:checks]
|
43
44
|
set :all_checks, @settings.checks
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
set :cors, @settings[:cors] || {
|
46
|
+
'Origin' => '*',
|
47
|
+
'Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
|
48
|
+
'Credentials' => 'true',
|
49
|
+
'Headers' => 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
|
50
|
+
}
|
49
51
|
on_reactor_run
|
50
52
|
self
|
51
53
|
end
|
@@ -112,10 +114,30 @@ module Sensu
|
|
112
114
|
env['rack.input'].rewind
|
113
115
|
end
|
114
116
|
|
117
|
+
def protected!
|
118
|
+
if settings.api[:user] && settings.api[:password]
|
119
|
+
return if !(settings.api[:user] && settings.api[:password]) || authorized?
|
120
|
+
headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
|
121
|
+
unauthorized!
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def authorized?
|
126
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
127
|
+
@auth.provided? &&
|
128
|
+
@auth.basic? &&
|
129
|
+
@auth.credentials &&
|
130
|
+
@auth.credentials == [settings.api[:user], settings.api[:password]]
|
131
|
+
end
|
132
|
+
|
115
133
|
def bad_request!
|
116
134
|
ahalt 400
|
117
135
|
end
|
118
136
|
|
137
|
+
def unauthorized!
|
138
|
+
ahalt 401
|
139
|
+
end
|
140
|
+
|
119
141
|
def not_found!
|
120
142
|
ahalt 404
|
121
143
|
end
|
@@ -235,6 +257,14 @@ module Sensu
|
|
235
257
|
before do
|
236
258
|
request_log_line
|
237
259
|
content_type 'application/json'
|
260
|
+
settings.cors.each do |header, value|
|
261
|
+
headers['Access-Control-Allow-' + header] = value
|
262
|
+
end
|
263
|
+
protected! unless env['REQUEST_METHOD'] == 'OPTIONS'
|
264
|
+
end
|
265
|
+
|
266
|
+
aoptions '/*' do
|
267
|
+
body ''
|
238
268
|
end
|
239
269
|
|
240
270
|
aget '/info/?' do
|
data/lib/sensu/client.rb
CHANGED
@@ -170,11 +170,18 @@ module Sensu
|
|
170
170
|
})
|
171
171
|
funnel = [@settings[:client][:name], VERSION, Time.now.to_i].join('-')
|
172
172
|
@transport.subscribe(:fanout, subscription, funnel) do |message_info, message|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
173
|
+
begin
|
174
|
+
check = MultiJson.load(message)
|
175
|
+
@logger.info('received check request', {
|
176
|
+
:check => check
|
177
|
+
})
|
178
|
+
process_check(check)
|
179
|
+
rescue MultiJson::ParseError => error
|
180
|
+
@logger.error('failed to parse the check request payload', {
|
181
|
+
:message => message,
|
182
|
+
:error => error.to_s
|
183
|
+
})
|
184
|
+
end
|
178
185
|
end
|
179
186
|
end
|
180
187
|
end
|
@@ -224,7 +231,7 @@ module Sensu
|
|
224
231
|
socket.logger = @logger
|
225
232
|
socket.settings = @settings
|
226
233
|
socket.transport = @transport
|
227
|
-
socket.
|
234
|
+
socket.protocol = :udp
|
228
235
|
end
|
229
236
|
end
|
230
237
|
|
data/lib/sensu/constants.rb
CHANGED
data/lib/sensu/daemon.rb
CHANGED
data/lib/sensu/server.rb
CHANGED
@@ -26,14 +26,21 @@ module Sensu
|
|
26
26
|
def setup_keepalives
|
27
27
|
@logger.debug('subscribing to keepalives')
|
28
28
|
@transport.subscribe(:direct, 'keepalives', 'keepalives', :ack => true) do |message_info, message|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@redis.
|
35
|
-
@
|
29
|
+
begin
|
30
|
+
client = MultiJson.load(message)
|
31
|
+
@logger.debug('received keepalive', {
|
32
|
+
:client => client
|
33
|
+
})
|
34
|
+
@redis.set('client:' + client[:name], MultiJson.dump(client)) do
|
35
|
+
@redis.sadd('clients', client[:name]) do
|
36
|
+
@transport.ack(message_info)
|
37
|
+
end
|
36
38
|
end
|
39
|
+
rescue MultiJson::ParseError => error
|
40
|
+
@logger.error('failed to parse keepalive payload', {
|
41
|
+
:message => message,
|
42
|
+
:error => error.to_s
|
43
|
+
})
|
37
44
|
end
|
38
45
|
end
|
39
46
|
end
|
@@ -447,13 +454,20 @@ module Sensu
|
|
447
454
|
def setup_results
|
448
455
|
@logger.debug('subscribing to results')
|
449
456
|
@transport.subscribe(:direct, 'results', 'results', :ack => true) do |message_info, message|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
+
begin
|
458
|
+
result = MultiJson.load(message)
|
459
|
+
@logger.debug('received result', {
|
460
|
+
:result => result
|
461
|
+
})
|
462
|
+
process_result(result)
|
463
|
+
EM::next_tick do
|
464
|
+
@transport.ack(message_info)
|
465
|
+
end
|
466
|
+
rescue MultiJson::ParseError => error
|
467
|
+
@logger.error('failed to parse result payload', {
|
468
|
+
:message => message,
|
469
|
+
:error => error.to_s
|
470
|
+
})
|
457
471
|
end
|
458
472
|
end
|
459
473
|
end
|
data/lib/sensu/socket.rb
CHANGED
@@ -1,15 +1,184 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
1
3
|
module Sensu
|
4
|
+
# EventMachine connection handler for the Sensu client's socket.
|
5
|
+
#
|
6
|
+
# The Sensu client listens on localhost, port 3030 (by default), for
|
7
|
+
# UDP and TCP traffic. This allows software running on the host to
|
8
|
+
# push check results (that may contain metrics) into Sensu, without
|
9
|
+
# needing to know anything about Sensu's internal implementation.
|
10
|
+
#
|
11
|
+
# The socket only accepts 7-bit ASCII-encoded data.
|
12
|
+
#
|
13
|
+
# Although the Sensu client accepts UDP and TCP traffic, you must be
|
14
|
+
# aware of the UDP protocol limitations. Any data you send over UDP
|
15
|
+
# must fit in a single datagram and you will not receive a response
|
16
|
+
# (no confirmation).
|
17
|
+
#
|
18
|
+
# == UDP Protocol ==
|
19
|
+
#
|
20
|
+
# If the socket receives a message containing whitespace and the
|
21
|
+
# string +'ping'+, it will ignore it.
|
22
|
+
#
|
23
|
+
# The socket assumes all other messages will contain a single,
|
24
|
+
# complete, JSON hash. The hash must be a valid JSON check result.
|
25
|
+
# Deserialization failures will be logged at the ERROR level by the
|
26
|
+
# Sensu client, but the sender of the invalid data will not be
|
27
|
+
# notified.
|
28
|
+
#
|
29
|
+
# == TCP Protocol ==
|
30
|
+
#
|
31
|
+
# If the socket receives a message containing whitespace and the
|
32
|
+
# string +'ping'+, it will respond with the message +'pong'+.
|
33
|
+
#
|
34
|
+
# The socket assumes any other stream will be a single, complete,
|
35
|
+
# JSON hash. A deserialization failure will be logged at the WARN
|
36
|
+
# level by the Sensu client and respond with the message
|
37
|
+
# +'invalid'+. An +'ok'+ response indicates the Sensu client
|
38
|
+
# successfully received the JSON hash and will publish the check
|
39
|
+
# result.
|
40
|
+
#
|
41
|
+
# Streams can be of any length. The socket protocol does not require
|
42
|
+
# any headers, instead the socket tries to parse everything it has
|
43
|
+
# been sent each time a chunk of data arrives. Once the JSON parses
|
44
|
+
# successfully, the Sensu client publishes the result. After
|
45
|
+
# +WATCHDOG_DELAY+ (default is 500 msec) since the most recent chunk
|
46
|
+
# of data was received, the agent will give up on the sender, and
|
47
|
+
# instead respond +'invalid'+ and close the connection.
|
2
48
|
class Socket < EM::Connection
|
3
|
-
|
49
|
+
class DataError < StandardError; end
|
50
|
+
|
51
|
+
attr_accessor :logger, :settings, :transport, :protocol
|
52
|
+
|
53
|
+
# The number of seconds that may elapse between chunks of data
|
54
|
+
# from a sender before it is considered dead, and the connection
|
55
|
+
# is close.
|
56
|
+
WATCHDOG_DELAY = 0.5
|
57
|
+
|
58
|
+
#
|
59
|
+
# Sensu::Socket operating mode enum.
|
60
|
+
#
|
61
|
+
|
62
|
+
# ACCEPT mode. Append chunks of data to a buffer and test to see
|
63
|
+
# whether the buffer contents are valid JSON.
|
64
|
+
MODE_ACCEPT = :ACCEPT
|
4
65
|
|
66
|
+
# REJECT mode. No longer receiving data from sender. Discard
|
67
|
+
# chunks of data in this mode, the connection is being closed.
|
68
|
+
MODE_REJECT = :REJECT
|
69
|
+
|
70
|
+
# Initialize instance variables that will be used throughout the
|
71
|
+
# lifetime of the connection. This method is called when the
|
72
|
+
# network connection has been established, and immediately after
|
73
|
+
# responding to a sender.
|
74
|
+
def post_init
|
75
|
+
@protocol ||= :tcp
|
76
|
+
@data_buffer = ''
|
77
|
+
@parse_error = nil
|
78
|
+
@watchdog = nil
|
79
|
+
@mode = MODE_ACCEPT
|
80
|
+
end
|
81
|
+
|
82
|
+
# Send a response to the sender, close the
|
83
|
+
# connection, and call post_init().
|
84
|
+
#
|
85
|
+
# @param [String] data to send as a response.
|
5
86
|
def respond(data)
|
6
|
-
|
87
|
+
if @protocol == :tcp
|
7
88
|
send_data(data)
|
89
|
+
close_connection_after_writing
|
8
90
|
end
|
91
|
+
post_init
|
9
92
|
end
|
10
93
|
|
11
|
-
|
12
|
-
|
94
|
+
# Cancel the current connection watchdog.
|
95
|
+
def cancel_watchdog
|
96
|
+
if @watchdog
|
97
|
+
@watchdog.cancel
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Reset (or start) the connection watchdog.
|
102
|
+
def reset_watchdog
|
103
|
+
cancel_watchdog
|
104
|
+
@watchdog = EM::Timer.new(WATCHDOG_DELAY) do
|
105
|
+
@mode = MODE_REJECT
|
106
|
+
@logger.warn('discarding data buffer for sender and closing connection', {
|
107
|
+
:data => @data_buffer,
|
108
|
+
:parse_error => @parse_error
|
109
|
+
})
|
110
|
+
respond('invalid')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Validate check result attributes.
|
115
|
+
#
|
116
|
+
# @param [Hash] check result to validate.
|
117
|
+
def validate_check_result(check)
|
118
|
+
unless check[:name] =~ /^[\w\.-]+$/
|
119
|
+
raise DataError, 'check name must be a string and cannot contain spaces or special characters'
|
120
|
+
end
|
121
|
+
unless check[:output].is_a?(String)
|
122
|
+
raise DataError, 'check output must be a string'
|
123
|
+
end
|
124
|
+
unless check[:status].is_a?(Integer)
|
125
|
+
raise DataError, 'check status must be an integer'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Publish a check result to the Sensu transport.
|
130
|
+
#
|
131
|
+
# @param [Hash] check result.
|
132
|
+
def publish_check_result(check)
|
133
|
+
payload = {
|
134
|
+
:client => @settings[:client][:name],
|
135
|
+
:check => check.merge(:issued => Time.now.to_i)
|
136
|
+
}
|
137
|
+
@logger.info('publishing check result', {
|
138
|
+
:payload => payload
|
139
|
+
})
|
140
|
+
@transport.publish(:direct, 'results', MultiJson.dump(payload))
|
141
|
+
end
|
142
|
+
|
143
|
+
# Process a check result. Set check result attribute defaults,
|
144
|
+
# validate the attributes, publish the check result to the Sensu
|
145
|
+
# transport, and respond to the sender with the message +'ok'+.
|
146
|
+
#
|
147
|
+
# @param [Hash] check result to be validated and published.
|
148
|
+
# @raise [DataError] if +check+ is invalid.
|
149
|
+
def process_check_result(check)
|
150
|
+
check[:status] ||= 0
|
151
|
+
validate_check_result(check)
|
152
|
+
publish_check_result(check)
|
153
|
+
respond('ok')
|
154
|
+
end
|
155
|
+
|
156
|
+
# Parse a JSON check result. For UDP, immediately raise a parser
|
157
|
+
# error. For TCP, record parser errors, so the connection
|
158
|
+
# +watchdog+ can report them.
|
159
|
+
#
|
160
|
+
# @param [String] data to parse for a check result.
|
161
|
+
def parse_check_result(data)
|
162
|
+
begin
|
163
|
+
check = MultiJson.load(data)
|
164
|
+
cancel_watchdog
|
165
|
+
process_check_result(check)
|
166
|
+
rescue MultiJson::ParseError, ArgumentError => error
|
167
|
+
if @protocol == :tcp
|
168
|
+
@parse_error = error.to_s
|
169
|
+
else
|
170
|
+
raise error
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Process the data received. This method validates the data
|
176
|
+
# encoding, provides ping/pong functionality, and passes potential
|
177
|
+
# check results on for further processing.
|
178
|
+
#
|
179
|
+
# @param [String] data to be processed.
|
180
|
+
def process_data(data)
|
181
|
+
if data.bytes.find { |char| char > 0x80 }
|
13
182
|
@logger.warn('socket received non-ascii characters')
|
14
183
|
respond('invalid')
|
15
184
|
elsif data.strip == 'ping'
|
@@ -20,32 +189,9 @@ module Sensu
|
|
20
189
|
:data => data
|
21
190
|
})
|
22
191
|
begin
|
23
|
-
|
24
|
-
|
25
|
-
check
|
26
|
-
validates = [
|
27
|
-
check[:name] =~ /^[\w\.-]+$/,
|
28
|
-
check[:output].is_a?(String),
|
29
|
-
check[:status].is_a?(Integer)
|
30
|
-
].all?
|
31
|
-
if validates
|
32
|
-
payload = {
|
33
|
-
:client => @settings[:client][:name],
|
34
|
-
:check => check
|
35
|
-
}
|
36
|
-
@logger.info('publishing check result', {
|
37
|
-
:payload => payload
|
38
|
-
})
|
39
|
-
@transport.publish(:direct, 'results', MultiJson.dump(payload))
|
40
|
-
respond('ok')
|
41
|
-
else
|
42
|
-
@logger.warn('invalid check result', {
|
43
|
-
:check => check
|
44
|
-
})
|
45
|
-
respond('invalid')
|
46
|
-
end
|
47
|
-
rescue MultiJson::ParseError => error
|
48
|
-
@logger.warn('check result must be valid json', {
|
192
|
+
parse_check_result(data)
|
193
|
+
rescue => error
|
194
|
+
@logger.error('failed to process check result from socket', {
|
49
195
|
:data => data,
|
50
196
|
:error => error.to_s
|
51
197
|
})
|
@@ -53,6 +199,27 @@ module Sensu
|
|
53
199
|
end
|
54
200
|
end
|
55
201
|
end
|
202
|
+
|
203
|
+
# This method is called whenever data is received. For UDP, it
|
204
|
+
# will only be called once, the original data length can be
|
205
|
+
# expected. For TCP, this method may be called several times, data
|
206
|
+
# received is buffered. TCP connections require a +watchdog+.
|
207
|
+
#
|
208
|
+
# @param [String] data received from the sender.
|
209
|
+
def receive_data(data)
|
210
|
+
unless @mode == MODE_REJECT
|
211
|
+
case @protocol
|
212
|
+
when :udp
|
213
|
+
process_data(data)
|
214
|
+
when :tcp
|
215
|
+
if EM.reactor_running?
|
216
|
+
reset_watchdog
|
217
|
+
end
|
218
|
+
@data_buffer << data
|
219
|
+
process_data(@data_buffer)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
56
223
|
end
|
57
224
|
|
58
225
|
class SocketHandler < EM::Connection
|
data/sensu.gemspec
CHANGED
@@ -22,15 +22,15 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_dependency('sensu-extension', '1.0.0')
|
23
23
|
s.add_dependency('sensu-extensions', '1.0.0')
|
24
24
|
s.add_dependency('sensu-transport', '1.0.0')
|
25
|
-
s.add_dependency('sensu-spawn', '1.
|
25
|
+
s.add_dependency('sensu-spawn', '1.1.0')
|
26
26
|
s.add_dependency('em-redis-unified', '0.5.0')
|
27
27
|
s.add_dependency('sinatra', '1.3.5')
|
28
28
|
s.add_dependency('async_sinatra', '1.0.0')
|
29
29
|
s.add_dependency('thin', '1.5.0') unless RUBY_PLATFORM =~ /java/
|
30
30
|
|
31
|
-
s.add_development_dependency('rake')
|
32
|
-
s.add_development_dependency('rspec')
|
33
|
-
s.add_development_dependency('em-http-request')
|
31
|
+
s.add_development_dependency('rake', '~> 10.3')
|
32
|
+
s.add_development_dependency('rspec', '~> 3.0.0')
|
33
|
+
s.add_development_dependency('em-http-request', '~> 1.1')
|
34
34
|
|
35
35
|
s.files = Dir.glob('{bin,lib}/**/*') + %w[sensu.gemspec README.md CHANGELOG.md MIT-LICENSE.txt]
|
36
36
|
s.executables = Dir.glob('bin/**/*').map { |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.14.0.beta
|
5
5
|
platform: java
|
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: 2014-
|
12
|
+
date: 2014-09-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_json
|
@@ -129,12 +129,12 @@ dependencies:
|
|
129
129
|
requirements:
|
130
130
|
- - '='
|
131
131
|
- !ruby/object:Gem::Version
|
132
|
-
version: 1.
|
132
|
+
version: 1.1.0
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - '='
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: 1.
|
137
|
+
version: 1.1.0
|
138
138
|
prerelease: false
|
139
139
|
type: :runtime
|
140
140
|
- !ruby/object:Gem::Dependency
|
@@ -183,42 +183,42 @@ dependencies:
|
|
183
183
|
name: rake
|
184
184
|
version_requirements: !ruby/object:Gem::Requirement
|
185
185
|
requirements:
|
186
|
-
- -
|
186
|
+
- - ~>
|
187
187
|
- !ruby/object:Gem::Version
|
188
|
-
version: '
|
188
|
+
version: '10.3'
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|
190
190
|
requirements:
|
191
|
-
- -
|
191
|
+
- - ~>
|
192
192
|
- !ruby/object:Gem::Version
|
193
|
-
version: '
|
193
|
+
version: '10.3'
|
194
194
|
prerelease: false
|
195
195
|
type: :development
|
196
196
|
- !ruby/object:Gem::Dependency
|
197
197
|
name: rspec
|
198
198
|
version_requirements: !ruby/object:Gem::Requirement
|
199
199
|
requirements:
|
200
|
-
- -
|
200
|
+
- - ~>
|
201
201
|
- !ruby/object:Gem::Version
|
202
|
-
version:
|
202
|
+
version: 3.0.0
|
203
203
|
requirement: !ruby/object:Gem::Requirement
|
204
204
|
requirements:
|
205
|
-
- -
|
205
|
+
- - ~>
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
207
|
+
version: 3.0.0
|
208
208
|
prerelease: false
|
209
209
|
type: :development
|
210
210
|
- !ruby/object:Gem::Dependency
|
211
211
|
name: em-http-request
|
212
212
|
version_requirements: !ruby/object:Gem::Requirement
|
213
213
|
requirements:
|
214
|
-
- -
|
214
|
+
- - ~>
|
215
215
|
- !ruby/object:Gem::Version
|
216
|
-
version: '
|
216
|
+
version: '1.1'
|
217
217
|
requirement: !ruby/object:Gem::Requirement
|
218
218
|
requirements:
|
219
|
-
- -
|
219
|
+
- - ~>
|
220
220
|
- !ruby/object:Gem::Version
|
221
|
-
version: '
|
221
|
+
version: '1.1'
|
222
222
|
prerelease: false
|
223
223
|
type: :development
|
224
224
|
description: A monitoring framework that aims to be simple, malleable, and scalable.
|
@@ -265,9 +265,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
265
265
|
version: '0'
|
266
266
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
267
267
|
requirements:
|
268
|
-
- - '
|
268
|
+
- - '>'
|
269
269
|
- !ruby/object:Gem::Version
|
270
|
-
version:
|
270
|
+
version: 1.3.1
|
271
271
|
requirements: []
|
272
272
|
rubyforge_project:
|
273
273
|
rubygems_version: 2.1.9
|