consul-templaterb 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +1 -1
- data/bin/consul-templaterb +43 -4
- data/lib/consul/async/consul_endpoint.rb +4 -34
- data/lib/consul/async/consul_template.rb +54 -13
- data/lib/consul/async/consul_template_engine.rb +2 -1
- data/lib/consul/async/endpoint.rb +137 -0
- data/lib/consul/async/stats.rb +40 -0
- data/lib/consul/async/vault_endpoint.rb +249 -0
- data/lib/consul/async/version.rb +1 -1
- data/null/ruby-type-inference/ruby-type-inference.mv.db +0 -0
- data/samples/consul-ui/common/header.html.erb +20 -1
- data/samples/consul-ui/consul-keys-ui.html.erb +39 -0
- data/samples/consul-ui/consul-nodes-ui.html.erb +35 -0
- data/samples/consul-ui/consul-services-ui.html.erb +9 -3
- data/samples/consul-ui/consul_keys.json.erb +12 -0
- data/samples/consul-ui/consul_nodes.json.erb +64 -0
- data/samples/consul-ui/{consul_template.json.erb → consul_services.json.erb} +0 -0
- data/samples/consul-ui/css/style.css +80 -4
- data/samples/consul-ui/js/keys.js +129 -0
- data/samples/consul-ui/js/nodes.js +120 -0
- data/samples/consul-ui/js/service.js +53 -179
- data/samples/consul-ui/js/utils.js +347 -0
- data/samples/consul-ui/vendors/highlight/atom-one-dark.css +96 -0
- data/samples/consul-ui/vendors/highlight/highlight.pack.js +2 -0
- data/samples/criteo/vault-test.erb +6 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 875f33bec50159a51a9fb9e59b07fbe37a78a0587cb3a496cc42a1806b5c8c9d
|
4
|
+
data.tar.gz: 08f091608892658b875d716c6935c9fe24f19b72b0c37dcde07eee4bcbdea838
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 481afae4f8b4df204897584ebc0ad4559c54ea5cbdd4a693977c33a573acc67e3e726df8b55a6ed3d2506b01c82f3092d98d27208e0de51c1c2367df01447cb3
|
7
|
+
data.tar.gz: 361f0786469ff9c305f047824b42a8c801109ffe6c7283e0a4325c2f89c3d8dcfa989b3a52bbef982e8cc78bbad17505b2c5c2b57223b67ba0343c0c9722143a
|
data/CHANGELOG.md
CHANGED
@@ -2,8 +2,20 @@
|
|
2
2
|
|
3
3
|
## (UNRELEASED)
|
4
4
|
|
5
|
+
## 1.3.0 (June 7, 2018)
|
6
|
+
|
5
7
|
IMPROVEMENTS:
|
6
8
|
|
9
|
+
* samples/consul-ui/ now supports keys as well as nodes thans to [@geobeau](https://github.com/geobeau)
|
10
|
+
|
11
|
+
NEW FEATURES
|
12
|
+
|
13
|
+
* EXPERIMENTAL Vault support thanks to [@uepock](https://github.com/uepoch)
|
14
|
+
|
15
|
+
BUG FIXES:
|
16
|
+
|
17
|
+
* Properly shutdown connections when receiving Posix signal to kill app
|
18
|
+
|
7
19
|
## 1.2.1 (May 28, 2018)
|
8
20
|
|
9
21
|
BUG FIXES:
|
data/README.md
CHANGED
@@ -276,7 +276,7 @@ Please consult [CHANGELOG.md](CHANGELOG.md) for fixed bugs.
|
|
276
276
|
|
277
277
|
## TODO
|
278
278
|
|
279
|
-
* [
|
279
|
+
* [x] Hashi's Vault support (EXPERIMENTAL)
|
280
280
|
* [ ] Implement automatic dynamic rate limit
|
281
281
|
* [ ] More samples: apache, nginx, full website displaying consul information...
|
282
282
|
* [ ] Optimize rendering speed at start-up: an iteration is done very second by default, but it would be possible to speed
|
data/bin/consul-templaterb
CHANGED
@@ -17,6 +17,24 @@ def compute_default_output(source)
|
|
17
17
|
end
|
18
18
|
|
19
19
|
options = {
|
20
|
+
vault: {
|
21
|
+
debug: {
|
22
|
+
network: false
|
23
|
+
},
|
24
|
+
base_url: ENV['VAULT_ADDR'] || 'http://localhost:8200',
|
25
|
+
token: ENV['VAULT_TOKEN'] || nil,
|
26
|
+
token_renew: true,
|
27
|
+
retry_duration: 10,
|
28
|
+
lease_duration_factor: 0.5, # The time it waits before actualizing data based on the lease time: 2h lease * 0.5 = Fetch data every 1h
|
29
|
+
min_duration: 60,
|
30
|
+
max_retry_duration: 86_400, # Much higher than consul's because some dynamic secrets could be used for a day.
|
31
|
+
paths: {
|
32
|
+
'/v1/sys/mounts' => {
|
33
|
+
max_retry_duration: 600,
|
34
|
+
min_duration: 600
|
35
|
+
}
|
36
|
+
}
|
37
|
+
},
|
20
38
|
consul: {
|
21
39
|
debug: {
|
22
40
|
network: false
|
@@ -71,10 +89,27 @@ optparse = OptionParser.new do |opts|
|
|
71
89
|
options[:consul][:base_url] = consul_url
|
72
90
|
end
|
73
91
|
|
74
|
-
opts.on('
|
92
|
+
opts.on('--consul-token=<token>', String, 'Use a token to connect to Consul') do |consul_token|
|
75
93
|
options[:consul][:token] = consul_token
|
76
94
|
end
|
77
95
|
|
96
|
+
opts.on('-V', '--vault-addr=<address>', String, 'Address of Vault, eg: http://localhost:8200') do |vault_url|
|
97
|
+
options[:vault][:base_url] = vault_url
|
98
|
+
end
|
99
|
+
|
100
|
+
opts.on('-T', '--vault-token=<token>', String, 'Token used to authenticate against vault.') do |vault_token|
|
101
|
+
options[:vault][:token] = vault_token
|
102
|
+
end
|
103
|
+
|
104
|
+
options[:vault][:token_renew] = true
|
105
|
+
opts.on('--[no-]vault-renew', 'Control auto-renewal of the Vault token. Default: activated') do |vault_renew|
|
106
|
+
options[:vault][:token_renew] = vault_renew
|
107
|
+
end
|
108
|
+
|
109
|
+
opts.on('--vault-lease-duration-factor=<factor>', Float, 'Wait at least <factor> * lease time before updating a Vault secret. Default: 0.5') do |factor|
|
110
|
+
options[:vault][:lease_duration_factor] = factor
|
111
|
+
end
|
112
|
+
|
78
113
|
opts.on('-w', '--wait=<min_duration>', Float, 'Wait at least n seconds before each template generation') do |min_duration|
|
79
114
|
options[:consul][:min_duration] = min_duration
|
80
115
|
end
|
@@ -213,8 +248,10 @@ def find_max_descriptors(max_descripors)
|
|
213
248
|
max_size
|
214
249
|
end
|
215
250
|
|
216
|
-
|
217
|
-
options[
|
251
|
+
%i[consul vault].each do |type|
|
252
|
+
unless options[type][:base_url].start_with? 'http', 'https'
|
253
|
+
options[type][:base_url] = "http://#{options[type][:base_url]}"
|
254
|
+
end
|
218
255
|
end
|
219
256
|
|
220
257
|
# Since we might be using a lots of descriptors, document this
|
@@ -227,7 +264,8 @@ STDERR.puts "Max number of descriptors set to #{new_size}" if options[:consul][:
|
|
227
264
|
EM.epoll
|
228
265
|
|
229
266
|
consul_conf = Consul::Async::ConsulConfiguration.new(options[:consul])
|
230
|
-
|
267
|
+
vault_conf = Consul::Async::VaultConfiguration.new(options[:vault])
|
268
|
+
template_manager = Consul::Async::EndPointsManager.new(consul_conf, vault_conf)
|
231
269
|
|
232
270
|
ARGV.each do |tpl|
|
233
271
|
dest = compute_default_output(tpl)
|
@@ -239,6 +277,7 @@ end
|
|
239
277
|
%w[INT PIPE TERM].each do |sig|
|
240
278
|
Signal.trap(sig) do
|
241
279
|
STDERR.puts "[KILL] received #{sig}, stopping myself"
|
280
|
+
template_manager.terminate
|
242
281
|
kill_program
|
243
282
|
end
|
244
283
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'consul/async/utilities'
|
2
|
+
require 'consul/async/stats'
|
2
3
|
require 'em-http'
|
3
4
|
require 'thread'
|
4
5
|
require 'json'
|
@@ -56,38 +57,6 @@ module Consul
|
|
56
57
|
paths: @paths)
|
57
58
|
end
|
58
59
|
end
|
59
|
-
class ConsulEndPointStats
|
60
|
-
attr_reader :successes, :errors, :start, :body_bytes
|
61
|
-
def initialize
|
62
|
-
@start = Time.now.utc
|
63
|
-
@successes = 0
|
64
|
-
@errors = 0
|
65
|
-
@body_bytes = 0
|
66
|
-
end
|
67
|
-
|
68
|
-
def on_reponse(res)
|
69
|
-
@successes += 1
|
70
|
-
@body_bytes = body_bytes + res.http.response.bytesize
|
71
|
-
end
|
72
|
-
|
73
|
-
def on_error(_http)
|
74
|
-
@errors += 1
|
75
|
-
end
|
76
|
-
|
77
|
-
def bytes_per_sec
|
78
|
-
diff = (Time.now.utc - start)
|
79
|
-
diff = 1 if diff < 1
|
80
|
-
(body_bytes / diff).round(0)
|
81
|
-
end
|
82
|
-
|
83
|
-
def bytes_per_sec_human
|
84
|
-
"#{Utilities.bytes_to_h(bytes_per_sec)}/s"
|
85
|
-
end
|
86
|
-
|
87
|
-
def body_bytes_human
|
88
|
-
Utilities.bytes_to_h(body_bytes)
|
89
|
-
end
|
90
|
-
end
|
91
60
|
class ConsulResult
|
92
61
|
attr_reader :data, :http, :x_consul_index, :last_update, :stats, :retry_in
|
93
62
|
def initialize(data, modified, http, x_consul_index, stats, retry_in)
|
@@ -106,6 +75,7 @@ module Consul
|
|
106
75
|
|
107
76
|
def mutate(new_data)
|
108
77
|
@data = new_data.dup
|
78
|
+
@data_json = nil
|
109
79
|
end
|
110
80
|
|
111
81
|
def json
|
@@ -146,9 +116,9 @@ module Consul
|
|
146
116
|
@consecutive_errors = 0
|
147
117
|
@query_params = query_params
|
148
118
|
@stopping = false
|
149
|
-
@stats =
|
119
|
+
@stats = EndPointStats.new
|
150
120
|
@last_result = ConsulResult.new(default_value, false, HttpResponse.new(nil), 0, stats, 1)
|
151
|
-
on_response { |result| @stats.
|
121
|
+
on_response { |result| @stats.on_response result }
|
152
122
|
on_error { |http| @stats.on_error http }
|
153
123
|
_enable_network_debug if conf.debug && conf.debug[:network]
|
154
124
|
fetch
|
@@ -19,10 +19,11 @@ module Consul
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
class
|
23
|
-
attr_reader :
|
24
|
-
def initialize(consul_configuration)
|
25
|
-
@
|
22
|
+
class EndPointsManager
|
23
|
+
attr_reader :consul_conf, :vault_conf, :net_info, :start_time
|
24
|
+
def initialize(consul_configuration, vault_configuration)
|
25
|
+
@consul_conf = consul_configuration
|
26
|
+
@vault_conf = vault_configuration
|
26
27
|
@endpoints = {}
|
27
28
|
@iteration = 1
|
28
29
|
@start_time = Time.now.utc
|
@@ -35,6 +36,11 @@ module Consul
|
|
35
36
|
current_erb_path: nil,
|
36
37
|
params: {}
|
37
38
|
}
|
39
|
+
|
40
|
+
unless @vault_conf.token.nil? || !@vault_conf.token_renew
|
41
|
+
#Setup token renewal
|
42
|
+
vault_setup_token_renew
|
43
|
+
end
|
38
44
|
end
|
39
45
|
|
40
46
|
# https://www.consul.io/api/health.html#list-nodes-for-service
|
@@ -45,7 +51,7 @@ module Consul
|
|
45
51
|
query_params[:dc] = dc if dc
|
46
52
|
query_params[:passing] = passing if passing
|
47
53
|
query_params[:tag] = tag if tag
|
48
|
-
create_if_missing(path, query_params) { ConsulTemplateService.new(ConsulEndpoint.new(
|
54
|
+
create_if_missing(path, query_params) { ConsulTemplateService.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
|
49
55
|
end
|
50
56
|
|
51
57
|
# https://www.consul.io/api/health.html#list-checks-for-service
|
@@ -55,7 +61,7 @@ module Consul
|
|
55
61
|
query_params = {}
|
56
62
|
query_params[:dc] = dc if dc
|
57
63
|
query_params[:passing] = passing if passing
|
58
|
-
create_if_missing(path, query_params) { ConsulTemplateChecks.new(ConsulEndpoint.new(
|
64
|
+
create_if_missing(path, query_params) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
|
59
65
|
end
|
60
66
|
|
61
67
|
# https://www.consul.io/api/catalog.html#list-nodes
|
@@ -63,7 +69,7 @@ module Consul
|
|
63
69
|
path = '/v1/catalog/nodes'
|
64
70
|
query_params = {}
|
65
71
|
query_params[:dc] = dc if dc
|
66
|
-
create_if_missing(path, query_params) { ConsulTemplateNodes.new(ConsulEndpoint.new(
|
72
|
+
create_if_missing(path, query_params) { ConsulTemplateNodes.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
|
67
73
|
end
|
68
74
|
|
69
75
|
# https://www.consul.io/api/catalog.html#list-services-for-node
|
@@ -71,7 +77,7 @@ module Consul
|
|
71
77
|
path = "/v1/catalog/node/#{name_or_id}"
|
72
78
|
query_params = {}
|
73
79
|
query_params[:dc] = dc if dc
|
74
|
-
create_if_missing(path, query_params) { ConsulTemplateNodes.new(ConsulEndpoint.new(
|
80
|
+
create_if_missing(path, query_params) { ConsulTemplateNodes.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '{}')) }
|
75
81
|
end
|
76
82
|
|
77
83
|
# https://www.consul.io/api/agent.html#read-configuration
|
@@ -79,7 +85,7 @@ module Consul
|
|
79
85
|
path = '/v1/agent/self'
|
80
86
|
query_params = {}
|
81
87
|
default_value = '{"Config":{}, "Coord":{}, "Member":{}, "Meta":{}, "Stats":{}}'
|
82
|
-
create_if_missing(path, query_params) { ConsulAgentSelf.new(ConsulEndpoint.new(
|
88
|
+
create_if_missing(path, query_params) { ConsulAgentSelf.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value)) }
|
83
89
|
end
|
84
90
|
|
85
91
|
# https://www.consul.io/api/agent.html#view-metrics
|
@@ -87,7 +93,7 @@ module Consul
|
|
87
93
|
path = '/v1/agent/metrics'
|
88
94
|
query_params = {}
|
89
95
|
default_value = '{"Gauges":[], "Points":[], "Member":{}, "Counters":[], "Samples":{}}'
|
90
|
-
create_if_missing(path, query_params) { ConsulAgentMetrics.new(ConsulEndpoint.new(
|
96
|
+
create_if_missing(path, query_params) { ConsulAgentMetrics.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value)) }
|
91
97
|
end
|
92
98
|
|
93
99
|
# Return a param of template
|
@@ -105,14 +111,14 @@ module Consul
|
|
105
111
|
query_params[:dc] = dc if dc
|
106
112
|
# Tag filtering is performed on client side
|
107
113
|
query_params[:tag] = tag if tag
|
108
|
-
create_if_missing(path, query_params) { ConsulTemplateServices.new(ConsulEndpoint.new(
|
114
|
+
create_if_missing(path, query_params) { ConsulTemplateServices.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '{}')) }
|
109
115
|
end
|
110
116
|
|
111
117
|
# https://www.consul.io/api/catalog.html#list-datacenters
|
112
118
|
def datacenters
|
113
119
|
path = '/v1/catalog/datacenters'
|
114
120
|
query_params = {}
|
115
|
-
create_if_missing(path, query_params) { ConsulTemplateDatacenters.new(ConsulEndpoint.new(
|
121
|
+
create_if_missing(path, query_params) { ConsulTemplateDatacenters.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
|
116
122
|
end
|
117
123
|
|
118
124
|
# https://www.consul.io/api/kv.html#read-key
|
@@ -123,7 +129,23 @@ module Consul
|
|
123
129
|
query_params[:recurse] = recurse if recurse
|
124
130
|
query_params[:keys] = keys if keys
|
125
131
|
default_value = '[]'
|
126
|
-
create_if_missing(path, query_params) { ConsulTemplateKV.new(ConsulEndpoint.new(
|
132
|
+
create_if_missing(path, query_params) { ConsulTemplateKV.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value), name) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def secrets(path = '')
|
136
|
+
raise "You need to provide a vault token to use 'secret' keyword" if vault_conf.token.nil?
|
137
|
+
path = "/v1/#{path}".gsub(/\/{2,}/, '/')
|
138
|
+
query_params = {list: "true"}
|
139
|
+
create_if_missing(path, query_params) { ConsulTemplateVaultSecretList.new(VaultEndpoint.new(vault_conf, path, 'GET',true, query_params,JSON.generate(data: {keys: []}))) }
|
140
|
+
end
|
141
|
+
|
142
|
+
def secret(path = '', post_data = nil )
|
143
|
+
puts post_data
|
144
|
+
raise "You need to provide a vault token to use 'secrets' keyword" if vault_conf.token.nil?
|
145
|
+
path = "/v1/#{path}"
|
146
|
+
query_params = {}
|
147
|
+
method = post_data ? "POST" : "GET"
|
148
|
+
create_if_missing(path, query_params) { ConsulTemplateVaultSecret.new(VaultEndpoint.new(vault_conf, path, method, true, query_params, JSON.generate(data: {}))) }
|
127
149
|
end
|
128
150
|
|
129
151
|
# render a relative file with the given params accessible from template
|
@@ -204,6 +226,12 @@ module Consul
|
|
204
226
|
@endpoints = {}
|
205
227
|
end
|
206
228
|
|
229
|
+
def vault_setup_token_renew
|
230
|
+
path = 'v1/auth/token/renew-self'
|
231
|
+
STDERR.print "[INFO] Setting up vault token renewal"
|
232
|
+
VaultEndpoint.new(vault_conf, path, :POST, {}, {})
|
233
|
+
end
|
234
|
+
|
207
235
|
def create_if_missing(path, query_params)
|
208
236
|
fqdn = path.dup
|
209
237
|
query_params.each_pair do |k, v|
|
@@ -384,5 +412,18 @@ module Consul
|
|
384
412
|
end
|
385
413
|
end
|
386
414
|
end
|
415
|
+
|
416
|
+
class ConsulTemplateVaultSecret < ConsulTemplateAbstractMap
|
417
|
+
def initialize(vault_endpoint)
|
418
|
+
super(vault_endpoint)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
class ConsulTemplateVaultSecretList < ConsulTemplateAbstractArray
|
422
|
+
def parse_result(res)
|
423
|
+
return res if res.data.nil?
|
424
|
+
res.mutate(JSON.generate(res.json['data']['keys']))
|
425
|
+
res
|
426
|
+
end
|
427
|
+
end
|
387
428
|
end
|
388
429
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'consul/async/utilities'
|
2
2
|
require 'consul/async/consul_endpoint'
|
3
|
+
require 'consul/async/vault_endpoint'
|
3
4
|
require 'consul/async/consul_template'
|
4
5
|
require 'consul/async/consul_template_render'
|
5
6
|
require 'em-http'
|
@@ -55,7 +56,7 @@ module Consul
|
|
55
56
|
template_manager.terminate
|
56
57
|
EventMachine.stop
|
57
58
|
rescue StandardError => e
|
58
|
-
STDERR.puts "[ERROR] Fatal error occured: #{e.inspect} - #{e.backtrace}"
|
59
|
+
STDERR.puts "[ERROR] Fatal error occured: #{e.inspect} - #{e.backtrace.join("\n\t")}"
|
59
60
|
template_manager.terminate
|
60
61
|
EventMachine.stop
|
61
62
|
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'consul/async/utilities'
|
2
|
+
|
3
|
+
class Endpoint
|
4
|
+
attr_reader :conf, :path, :x_consul_index, :queue, :stats, :last_result, :enforce_json_200, :start_time, :default_value, :query_params
|
5
|
+
def initialize(conf, path, enforce_json_200 = true, query_params = {}, default_value = '[]')
|
6
|
+
@conf = conf.create(path)
|
7
|
+
@default_value = default_value
|
8
|
+
@path = path
|
9
|
+
@queue = EM::Queue.new
|
10
|
+
@s_callbacks = []
|
11
|
+
@e_callbacks = []
|
12
|
+
@enforce_json_200 = enforce_json_200
|
13
|
+
@start_time = Time.now.utc
|
14
|
+
@consecutive_errors = 0
|
15
|
+
@query_params = query_params
|
16
|
+
@stopping = false
|
17
|
+
@stats = EndPointStats.new
|
18
|
+
@last_result = ConsulResult.new(default_value, false, HttpResponse.new(nil), 0, stats, 1)
|
19
|
+
on_response { |result| @stats.on_reponse result }
|
20
|
+
on_error { |http| @stats.on_error http }
|
21
|
+
_enable_network_debug if conf.debug && conf.debug[:network]
|
22
|
+
fetch
|
23
|
+
queue << 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def _enable_network_debug
|
27
|
+
on_response do |result|
|
28
|
+
state = result.x_consul_index.to_i < 1 ? '[WARN]' : '[ OK ]'
|
29
|
+
stats = result.stats
|
30
|
+
STDERR.puts "[DEBUG]#{state}#{result.modified? ? '[MODIFIED]' : '[NO DIFF]'}" \
|
31
|
+
"[s:#{stats.successes},err:#{stats.errors}]" \
|
32
|
+
"[#{stats.body_bytes_human.ljust(8)}][#{stats.bytes_per_sec_human.ljust(9)}]"\
|
33
|
+
" #{path.ljust(48)} idx:#{result.x_consul_index}, next in #{result.retry_in} s"
|
34
|
+
end
|
35
|
+
on_error { |http| STDERR.puts "[ERROR]: #{path}: #{http.error}" }
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_response(&block)
|
39
|
+
@s_callbacks << block
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_error(&block)
|
43
|
+
@e_callbacks << block
|
44
|
+
end
|
45
|
+
|
46
|
+
def ready?
|
47
|
+
@ready
|
48
|
+
end
|
49
|
+
|
50
|
+
def terminate
|
51
|
+
@stopping = true
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def build_request(headers = {}, query_params = {})
|
57
|
+
req = {
|
58
|
+
head: headers,
|
59
|
+
path: path,
|
60
|
+
query: query_params,
|
61
|
+
keepalive: true,
|
62
|
+
callback: method(:on_response)
|
63
|
+
}
|
64
|
+
@query_params.each_pair do |k, v|
|
65
|
+
req[:query][k] = v
|
66
|
+
end
|
67
|
+
req
|
68
|
+
end
|
69
|
+
|
70
|
+
def log(level, message)
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def _handle_error(http, consul_index)
|
75
|
+
retry_in = [600, conf.retry_duration + 2**@consecutive_errors].min
|
76
|
+
STDERR.puts "[ERROR][#{path}] X-Consul-Index:#{consul_index} - #{http.error} - Retry in #{retry_in}s #{stats.body_bytes_human}"
|
77
|
+
@consecutive_errors += 1
|
78
|
+
http_result = HttpResponse.new(http)
|
79
|
+
EventMachine.add_timer(retry_in) do
|
80
|
+
yield
|
81
|
+
queue.push(consul_index)
|
82
|
+
end
|
83
|
+
@e_callbacks.each { |c| c.call(http_result) }
|
84
|
+
end
|
85
|
+
|
86
|
+
def fetch
|
87
|
+
options = {
|
88
|
+
connect_timeout: 5, # default connection setup timeout
|
89
|
+
inactivity_timeout: conf.wait_duration + 1, # default connection inactivity (post-setup) timeout
|
90
|
+
}
|
91
|
+
connection = EventMachine::HttpRequest.new(conf.base_url, options)
|
92
|
+
cb = proc do |consul_index|
|
93
|
+
http = connection.get(build_request(consul_index))
|
94
|
+
http.callback do
|
95
|
+
# Dirty hack, but contrary to other path, when key is not present, Consul returns 404
|
96
|
+
is_kv_empty = path.start_with?('/v1/kv') && http.response_header.status == 404
|
97
|
+
if !is_kv_empty && enforce_json_200 && http.response_header.status != 200 && http.response_header['Content-Type'] != 'application/json'
|
98
|
+
_handle_error(http, consul_index) { connection = EventMachine::HttpRequest.new(conf.base_url, options) }
|
99
|
+
else
|
100
|
+
n_consul_index = find_x_consul_token(http)
|
101
|
+
@consecutive_errors = 0
|
102
|
+
http_result = if is_kv_empty
|
103
|
+
HttpResponse.new(http, default_value)
|
104
|
+
else
|
105
|
+
HttpResponse.new(http)
|
106
|
+
end
|
107
|
+
new_content = http_result.response.freeze
|
108
|
+
modified = @last_result.nil? ? true : @last_result.data != new_content
|
109
|
+
if n_consul_index == consul_index || n_consul_index.nil?
|
110
|
+
retry_in = modified ? conf.missing_index_retry_time_on_diff : conf.missing_index_retry_time_on_unchanged
|
111
|
+
n_consul_index = consul_index
|
112
|
+
else
|
113
|
+
retry_in = modified ? conf.min_duration : conf.retry_on_non_diff
|
114
|
+
end
|
115
|
+
retry_in = 0.1 if retry_in < 0.1
|
116
|
+
unless @stopping
|
117
|
+
EventMachine.add_timer(retry_in) do
|
118
|
+
queue.push(n_consul_index)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
result = ConsulResult.new(new_content, modified, http_result, n_consul_index, stats, retry_in)
|
122
|
+
@last_result = result
|
123
|
+
@ready = true
|
124
|
+
@s_callbacks.each { |c| c.call(result) }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
http.errback do
|
129
|
+
unless @stopping
|
130
|
+
_handle_error(http, consul_index) { connection = EventMachine::HttpRequest.new(conf.base_url, options) }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
queue.pop(&cb)
|
134
|
+
end
|
135
|
+
queue.pop(&cb)
|
136
|
+
end
|
137
|
+
end
|