consul-templaterb 1.26.2 → 1.28.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/.rubocop.yml +7 -7
- data/.travis.yml +5 -5
- data/CHANGELOG.md +38 -0
- data/README.md +19 -4
- data/TemplateAPI.md +9 -0
- data/bin/consul-templaterb +52 -6
- data/lib/consul/async/consul_endpoint.rb +19 -3
- data/lib/consul/async/consul_template.rb +26 -8
- data/lib/consul/async/consul_template_render.rb +1 -1
- data/lib/consul/async/json_endpoint.rb +15 -2
- data/lib/consul/async/process_handler.rb +7 -1
- data/lib/consul/async/vault_endpoint.rb +16 -2
- data/lib/consul/async/version.rb +1 -1
- data/samples/checks_in_warning_or_critical_state.yaml.erb +13 -0
- data/samples/consul-ui/css/style.css +4 -0
- data/samples/consul-ui/decorators.js.erb +2 -171
- data/samples/consul-ui/js/nodes.js +1 -1
- data/samples/consul-ui/js/service.js +1 -1
- data/samples/consul-ui/js/utils.js +45 -20
- data/samples/display_timestamped_changes.txt.erb +17 -0
- data/samples/prometheus_datacenter_coordinates.erb +56 -0
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c15ee78520048d7d091882b9d3b1d43b4cc5f5658cf39d782f06e1dc617d8cd9
|
|
4
|
+
data.tar.gz: 6f77a9daab557420f2640a314a97f78af68e26fec91c1a66f3ee575d9bf150f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c2b374a9400061f3ffd673e418771bb5685ec3d13a631c3839660121d86575be1fbbd1cd99f7ee1a4ddedf850ec72fa984ca084575da587b7a239d2e4654b2e
|
|
7
|
+
data.tar.gz: '0933c0a2f1f58c617c184679ab68c1e90d55f1d9ab796e45336ddbbf49ae2fd73cf1aafbfea6e921254a520c8be3e5f0f380cfbdacd694ba2de6c5f8e4f5a074'
|
data/.rubocop.yml
CHANGED
|
@@ -7,28 +7,28 @@ Layout/LineLength:
|
|
|
7
7
|
Max: 175
|
|
8
8
|
|
|
9
9
|
Metrics/AbcSize:
|
|
10
|
-
Max:
|
|
10
|
+
Max: 87
|
|
11
11
|
|
|
12
12
|
Metrics/BlockLength:
|
|
13
|
-
Max:
|
|
13
|
+
Max: 188
|
|
14
14
|
|
|
15
15
|
Metrics/BlockNesting:
|
|
16
16
|
Max: 4
|
|
17
17
|
|
|
18
18
|
Metrics/ClassLength:
|
|
19
|
-
Max:
|
|
19
|
+
Max: 285
|
|
20
20
|
|
|
21
21
|
Metrics/CyclomaticComplexity:
|
|
22
|
-
Max:
|
|
22
|
+
Max: 21
|
|
23
23
|
|
|
24
24
|
Metrics/MethodLength:
|
|
25
|
-
Max:
|
|
25
|
+
Max: 68
|
|
26
26
|
|
|
27
27
|
Metrics/ParameterLists:
|
|
28
|
-
Max:
|
|
28
|
+
Max: 18
|
|
29
29
|
|
|
30
30
|
Metrics/PerceivedComplexity:
|
|
31
|
-
Max:
|
|
31
|
+
Max: 24
|
|
32
32
|
|
|
33
33
|
# We use `dc` as a parameter in many methods
|
|
34
34
|
Naming/MethodParameterName:
|
data/.travis.yml
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
language: ruby
|
|
2
2
|
rvm:
|
|
3
|
-
- 2.4.
|
|
4
|
-
- 2.5.
|
|
5
|
-
- 2.6.
|
|
6
|
-
- 2.7.
|
|
3
|
+
- 2.4.10
|
|
4
|
+
- 2.5.8
|
|
5
|
+
- 2.6.6
|
|
6
|
+
- 2.7.1
|
|
7
7
|
jobs:
|
|
8
8
|
include:
|
|
9
9
|
- stage: Gem release
|
|
10
|
-
rvm: 2.5.
|
|
10
|
+
rvm: 2.5.8
|
|
11
11
|
script: echo "Publishing consul-templaterb on rubygems.org ..."
|
|
12
12
|
deploy:
|
|
13
13
|
provider: rubygems
|
data/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
## (UNRELEASED)
|
|
4
4
|
|
|
5
|
+
## 1.28.0 (Sept 25, 2020)
|
|
6
|
+
|
|
7
|
+
NEW FEATURES:
|
|
8
|
+
|
|
9
|
+
* Added `-W` or `--wait-between-reload-signal` to avoid sending too many signals
|
|
10
|
+
to a process executed. This avoids for instance reloading too much a HAProxy configuration
|
|
11
|
+
without having to play with `-w` as described in [#69](https://github.com/criteo/consul-templaterb/issues/69)
|
|
12
|
+
|
|
13
|
+
BUGFIX:
|
|
14
|
+
|
|
15
|
+
* Removed warnings at runtime with Ruby 2.7+
|
|
16
|
+
* Minor JS fix in Consul-UI (Added missing unused parameter to function `serviceTitleGenerator`)
|
|
17
|
+
|
|
18
|
+
## 1.27.2 (Sept 4, 2020)
|
|
19
|
+
|
|
20
|
+
IMPROVEMENTS:
|
|
21
|
+
|
|
22
|
+
* Consul-UI now supports navigation between nodes and services in both ways
|
|
23
|
+
|
|
24
|
+
## 1.27.1 (July 28, 2020)
|
|
25
|
+
|
|
26
|
+
BUGIX:
|
|
27
|
+
|
|
28
|
+
* Fix collision in JSON queries when using payload in requests #68
|
|
29
|
+
|
|
30
|
+
## 1.27.0 (June 5, 2020)
|
|
31
|
+
|
|
5
32
|
NEW FEATURES:
|
|
6
33
|
|
|
34
|
+
* For Consul 1.7+, now support `checks_in_state(check_state, dc: nil, [agent: consul_agent_address])`,
|
|
35
|
+
fixes feature [#65](https://github.com/criteo/consul-templaterb/issues/65)
|
|
36
|
+
* New options to support/disable TLS validation thanks to [@jeromegn](https://github.com/jeromegn)
|
|
37
|
+
[#66](https://github.com/criteo/consul-templaterb/pull/66)
|
|
38
|
+
|
|
39
|
+
## 1.26.3 (April 15, 2020)
|
|
40
|
+
|
|
41
|
+
BUGFIX:
|
|
42
|
+
|
|
43
|
+
* Removed all Criteo specific decorators from Consul-UI
|
|
44
|
+
|
|
7
45
|
## 1.26.2 (April 15, 2020)
|
|
8
46
|
|
|
9
47
|
BUGFIX:
|
data/README.md
CHANGED
|
@@ -165,9 +165,19 @@ USAGE: consul-templaterb [[options]]
|
|
|
165
165
|
-f, --[no-]fail-fast If consul/vault endpoints fail at startup, fail immediately
|
|
166
166
|
-g, --no-gzip-compression Disable GZIP compression in HTTP requests
|
|
167
167
|
-c, --consul-addr=<address> Address of Consul, eg: http://localhost:8500
|
|
168
|
+
--consul-cert-chain=<path/to/cert_chain>
|
|
169
|
+
Path to Consul TLS client certificate chain to use
|
|
170
|
+
--consul-private-key=<path/to/private_key>
|
|
171
|
+
Path to Consul TLS client private key to use
|
|
172
|
+
--skip-consul-verify-tls Skip verifying Consul TLS via certificate authority (DANGEROUS)
|
|
168
173
|
-l, --log-level=<log_level> Log level, default=info, any of none|error|info|debug
|
|
169
174
|
--consul-token=<token> Use a token to connect to Consul
|
|
170
175
|
-V, --vault-addr=<address> Address of Vault, eg: http://localhost:8200
|
|
176
|
+
--vault-cert-chain=<path/to/cert_chain>
|
|
177
|
+
Path to Vault TLS client certificate chain to use
|
|
178
|
+
--vault-private-key=<path/to/private_key>
|
|
179
|
+
Path to Vault TLS client private key to use
|
|
180
|
+
--skip-vault-verify-tls Skip verifying Vault TLS via certificate authority (DANGEROUS)
|
|
171
181
|
--vault-token=<token> Token used to authenticate against vault.
|
|
172
182
|
--[no-]vault-renew Control auto-renewal of the Vault token. Default: activated
|
|
173
183
|
--vault-retry, --vault-retry-attempts [RETRIES]
|
|
@@ -178,10 +188,11 @@ USAGE: consul-templaterb [[options]]
|
|
|
178
188
|
-r, --retry-delay=<min_duration> Min Retry delay on Error/Missing Consul Index
|
|
179
189
|
-k, --hot-reload=<behavior> Control hot reload behaviour, one of :[die (kill daemon on hot reload failure), keep (on error, keep running), disable (hot reload disabled)]
|
|
180
190
|
-K, --sig-term=kill_signal Signal to send to next --exec command on kill, default=TERM
|
|
191
|
+
-M, --debug-memory-usage Display messages when RAM grows
|
|
181
192
|
-T, --trim-mode=trim_mode ERB Trim mode to use (- by default)
|
|
182
193
|
-R, --sig-reload=reload_signal Signal to send to next --exec command on reload (NONE supported), default=HUP
|
|
183
|
-
-
|
|
184
|
-
-e, --exec=<command> Execute the following command
|
|
194
|
+
-W, --wait-signal=min_duration Wait at least n seconds before each reload signal being sent to next --exec process
|
|
195
|
+
-e, --exec=<command> Execute the following command in as a subprocess when all templates are ready
|
|
185
196
|
-d, --debug-network-usage Debug the network usage
|
|
186
197
|
-t erb_file:[output]:[command]:[params_file],
|
|
187
198
|
--template Add a erb template, its output and optional reload command
|
|
@@ -235,7 +246,11 @@ nor write the file.
|
|
|
235
246
|
Signals can be customized per process. Two signals are supported with options `--sig-reload` and
|
|
236
247
|
`--sig-term`. When the option is added, the next `--exec` options to start a process will use the
|
|
237
248
|
given signal. By default, HUP will be sent to reload events (you can use NONE to avoid sending any
|
|
238
|
-
reload signal), TERM will be used when leaving consul-templaterb.
|
|
249
|
+
reload signal), TERM will be used when leaving consul-templaterb. A minimum duration between reload
|
|
250
|
+
signals can be specified for each sub process by prepending `--wait-signal=min_duration` to `--exec`
|
|
251
|
+
command.
|
|
252
|
+
In such case, the signal will be sent every `min_duration` as a maximum (very useful for templates
|
|
253
|
+
changing a lot, but you don't want to trigger too many reloads, for instance for a load-balancer).
|
|
239
254
|
|
|
240
255
|
### Bandwidth limitation
|
|
241
256
|
|
|
@@ -332,7 +347,7 @@ Please consult [CHANGELOG.md](CHANGELOG.md) for fixed bugs.
|
|
|
332
347
|
|
|
333
348
|
## TODO
|
|
334
349
|
|
|
335
|
-
* [x] Hashi's Vault support
|
|
350
|
+
* [x] Hashi's Vault support
|
|
336
351
|
* [ ] Implement automatic dynamic rate limit
|
|
337
352
|
* [x] More samples: apache, nginx, a full website displaying consul information...
|
|
338
353
|
* [x] Optimize rendering speed at start-up: an iteration is done every second by default, but it would be possible to speed
|
data/TemplateAPI.md
CHANGED
|
@@ -388,6 +388,15 @@ name or its ID. If DC is specified, will lookup for given node in another datace
|
|
|
388
388
|
|
|
389
389
|
[Find all the checks](https://www.consul.io/api/health.html#list-checks-for-service) of a given service.
|
|
390
390
|
|
|
391
|
+
## def checks_in_state(check_state, dc: nil, [agent: consul_agent_address])
|
|
392
|
+
|
|
393
|
+
[Find all the checks in a given state](https://www.consul.io/api-docs/health#list-checks-in-state) in the whole cluster.
|
|
394
|
+
|
|
395
|
+
The filter check_state must be one of any|critical|warning|passing.
|
|
396
|
+
|
|
397
|
+
Warning: this endpoint might be very frequently updated in a
|
|
398
|
+
large cluster if you are using `any` value. This endpoint is supported with Consul 1.7+.
|
|
399
|
+
|
|
391
400
|
## kv(name, [dc: nil], [keys: false], [recurse: false], [agent: consul_agent_address])
|
|
392
401
|
|
|
393
402
|
[Read keys from KV Store](https://www.consul.io/api/kv.html#read-key). It can be used for both listing the keys and
|
data/bin/consul-templaterb
CHANGED
|
@@ -28,6 +28,9 @@ options = {
|
|
|
28
28
|
},
|
|
29
29
|
base_url: ENV['VAULT_ADDR'] || 'http://localhost:8200',
|
|
30
30
|
token: ENV['VAULT_TOKEN'] || nil,
|
|
31
|
+
tls_cert_chain: ENV['VAULT_CLIENT_CERT'] || nil,
|
|
32
|
+
tls_private_key: ENV['VAULT_CLIENT_KEY'] || nil,
|
|
33
|
+
tls_verify_peer: true,
|
|
31
34
|
max_consecutive_errors_on_endpoint: 10, # Stop program after n consecutive failures on same endpoint
|
|
32
35
|
fail_fast_errors: nil, # fail fast the program if endpoint was never success
|
|
33
36
|
token_renew: true,
|
|
@@ -48,6 +51,9 @@ options = {
|
|
|
48
51
|
},
|
|
49
52
|
base_url: ENV['CONSUL_HTTP_ADDR'] || 'http://localhost:8500',
|
|
50
53
|
token: ENV['CONSUL_HTTP_TOKEN'] || nil,
|
|
54
|
+
tls_cert_chain: ENV['CONSUL_CLIENT_CERT'] || nil,
|
|
55
|
+
tls_private_key: ENV['CONSUL_CLIENT_KEY'] || nil,
|
|
56
|
+
tls_verify_peer: true,
|
|
51
57
|
max_consecutive_errors_on_endpoint: 10, # Stop program after n consecutive failures on same endpoint
|
|
52
58
|
fail_fast_errors: nil, # fail fast the program if endpoint was never success
|
|
53
59
|
retry_duration: 10, # On error, retry after n seconds
|
|
@@ -88,6 +94,7 @@ consul_engine = Consul::Async::ConsulTemplateEngine.new
|
|
|
88
94
|
@programs = {}
|
|
89
95
|
cur_sig_reload = 'HUP'.freeze
|
|
90
96
|
cur_sig_term = 'TERM'.freeze
|
|
97
|
+
cur_min_duration_between_signals = 1
|
|
91
98
|
|
|
92
99
|
optparse = OptionParser.new do |opts|
|
|
93
100
|
opts.banner = usage_text
|
|
@@ -122,6 +129,18 @@ optparse = OptionParser.new do |opts|
|
|
|
122
129
|
options[:consul][:base_url] = consul_url
|
|
123
130
|
end
|
|
124
131
|
|
|
132
|
+
opts.on('--consul-cert-chain=<path/to/cert_chain>', String, 'Path to Consul TLS client certificate chain to use') do |consul_client_cert|
|
|
133
|
+
options[:consul][:tls_cert_chain] = consul_client_cert
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
opts.on('--consul-private-key=<path/to/private_key>', String, 'Path to Consul TLS client private key to use') do |consul_client_key|
|
|
137
|
+
options[:consul][:tls_private_key] = consul_client_key
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
opts.on('--skip-consul-verify-tls', 'Skip verifying Consul TLS via certificate authority (DANGEROUS)') do
|
|
141
|
+
options[:consul][:tls_verify_peer] = false
|
|
142
|
+
end
|
|
143
|
+
|
|
125
144
|
opts.on('-l', '--log-level=<log_level>', String, "Log level, default=info, any of #{::Consul::Async::Debug.levels.join('|')}") do |log_level|
|
|
126
145
|
::Consul::Async::Debug.level = log_level
|
|
127
146
|
end
|
|
@@ -134,6 +153,18 @@ optparse = OptionParser.new do |opts|
|
|
|
134
153
|
options[:vault][:base_url] = vault_url
|
|
135
154
|
end
|
|
136
155
|
|
|
156
|
+
opts.on('--vault-cert-chain=<path/to/cert_chain>', String, 'Path to Vault TLS client certificate chain to use') do |vault_client_cert|
|
|
157
|
+
options[:vault][:tls_cert_chain] = vault_client_cert
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
opts.on('--vault-private-key=<path/to/private_key>', String, 'Path to Vault TLS client private key to use') do |vault_client_key|
|
|
161
|
+
options[:vault][:tls_private_key] = vault_client_key
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
opts.on('--skip-vault-verify-tls', 'Skip verifying Vault TLS via certificate authority (DANGEROUS)') do
|
|
165
|
+
options[:vault][:tls_verify_peer] = false
|
|
166
|
+
end
|
|
167
|
+
|
|
137
168
|
opts.on('-T', '--vault-token=<token>', String, 'Token used to authenticate against vault.') do |vault_token|
|
|
138
169
|
options[:vault][:token] = vault_token
|
|
139
170
|
end
|
|
@@ -185,6 +216,10 @@ optparse = OptionParser.new do |opts|
|
|
|
185
216
|
cur_sig_term = compute_signal(sig, nil)
|
|
186
217
|
end
|
|
187
218
|
|
|
219
|
+
opts.on('-M', '--debug-memory-usage', 'Display messages when RAM grows') do
|
|
220
|
+
consul_engine.debug_memory = true
|
|
221
|
+
end
|
|
222
|
+
|
|
188
223
|
opts.on('-T', '--trim-mode=trim_mode', String,
|
|
189
224
|
"ERB Trim mode to use (#{options[:erb][:trim_mode]} by default)") do |trim_mode|
|
|
190
225
|
options[:erb][:trim_mode] = trim_mode
|
|
@@ -195,25 +230,36 @@ optparse = OptionParser.new do |opts|
|
|
|
195
230
|
cur_sig_reload = compute_signal(sig, 'NONE')
|
|
196
231
|
end
|
|
197
232
|
|
|
198
|
-
opts.on('-
|
|
199
|
-
|
|
233
|
+
opts.on('-W', '--wait-signal=min_duration', Float, 'Wait at least n seconds before each reload signal being sent to next --exec process') do |min_duration|
|
|
234
|
+
raise "-wait-between-reload-signal=#{min_duration} must be greater than 0" unless min_duration.positive?
|
|
235
|
+
|
|
236
|
+
cur_min_duration_between_signals = min_duration
|
|
200
237
|
end
|
|
201
238
|
|
|
202
|
-
opts.on('-e', '--exec=<command>', String, 'Execute the following command') do |cmd|
|
|
239
|
+
opts.on('-e', '--exec=<command>', String, 'Execute the following command in as a subprocess when all templates are ready') do |cmd|
|
|
203
240
|
sig_reload = cur_sig_reload
|
|
204
241
|
sig_term = cur_sig_term
|
|
242
|
+
sig_min_interval = cur_min_duration_between_signals
|
|
205
243
|
consul_engine.add_template_callback do |all_ready, template_manager, results|
|
|
206
244
|
if all_ready
|
|
207
245
|
modified = results.any?(&:modified)
|
|
208
246
|
if @programs[cmd].nil?
|
|
209
|
-
warn "[EXEC] Starting process: #{cmd}... on_reload=#{sig_reload || 'NONE'} on_term=#{sig_term}"
|
|
247
|
+
warn "[EXEC] Starting process: #{cmd}... on_reload=#{sig_reload || 'NONE'} on_term=#{sig_term}, delay between reloads=#{sig_min_interval}s"
|
|
210
248
|
@programs[cmd] = Consul::Async::ProcessHandler.new(cmd, sig_reload: sig_reload, sig_term: sig_term)
|
|
211
249
|
@programs[cmd].start
|
|
212
250
|
else
|
|
251
|
+
|
|
213
252
|
# At least one template has been modified
|
|
214
|
-
@programs[cmd]
|
|
253
|
+
process_to_reload = @programs[cmd]
|
|
254
|
+
if modified && !process_to_reload.reload_scheduled
|
|
255
|
+
process_to_reload.reload_scheduled = true
|
|
256
|
+
now = Time.now
|
|
257
|
+
delay = sig_min_interval - (now - @programs[cmd].last_signal_sent)
|
|
258
|
+
delay = 0 if delay.negative?
|
|
259
|
+
EventMachine.add_timer(delay) { process_to_reload.reload }
|
|
260
|
+
end
|
|
215
261
|
begin
|
|
216
|
-
|
|
262
|
+
process_to_reload.process_status
|
|
217
263
|
rescue Consul::Async::ProcessDoesNotExist => e
|
|
218
264
|
warn "[FATAL] The process is dead, aborting run: #{e.inspect}"
|
|
219
265
|
template_manager.terminate
|
|
@@ -9,7 +9,7 @@ module Consul
|
|
|
9
9
|
class ConsulConfiguration
|
|
10
10
|
attr_reader :base_url, :token, :retry_duration, :min_duration, :wait_duration, :max_retry_duration, :retry_on_non_diff,
|
|
11
11
|
:missing_index_retry_time_on_diff, :missing_index_retry_time_on_unchanged, :debug, :enable_gzip_compression,
|
|
12
|
-
:fail_fast_errors, :max_consecutive_errors_on_endpoint
|
|
12
|
+
:fail_fast_errors, :max_consecutive_errors_on_endpoint, :tls_cert_chain, :tls_private_key, :tls_verify_peer
|
|
13
13
|
def initialize(base_url: 'http://localhost:8500',
|
|
14
14
|
debug: { network: false },
|
|
15
15
|
token: nil,
|
|
@@ -23,7 +23,10 @@ module Consul
|
|
|
23
23
|
enable_gzip_compression: true,
|
|
24
24
|
paths: {},
|
|
25
25
|
max_consecutive_errors_on_endpoint: 10,
|
|
26
|
-
fail_fast_errors: 1
|
|
26
|
+
fail_fast_errors: 1,
|
|
27
|
+
tls_cert_chain: nil,
|
|
28
|
+
tls_private_key: nil,
|
|
29
|
+
tls_verify_peer: true)
|
|
27
30
|
@base_url = base_url
|
|
28
31
|
@token = token
|
|
29
32
|
@debug = debug
|
|
@@ -38,6 +41,9 @@ module Consul
|
|
|
38
41
|
@paths = paths
|
|
39
42
|
@max_consecutive_errors_on_endpoint = max_consecutive_errors_on_endpoint
|
|
40
43
|
@fail_fast_errors = fail_fast_errors
|
|
44
|
+
@tls_cert_chain = tls_cert_chain
|
|
45
|
+
@tls_private_key = tls_private_key
|
|
46
|
+
@tls_verify_peer = tls_verify_peer
|
|
41
47
|
end
|
|
42
48
|
|
|
43
49
|
def ch(path, symbol)
|
|
@@ -71,7 +77,10 @@ module Consul
|
|
|
71
77
|
enable_gzip_compression: enable_gzip_compression,
|
|
72
78
|
paths: @paths,
|
|
73
79
|
max_consecutive_errors_on_endpoint: @max_consecutive_errors_on_endpoint,
|
|
74
|
-
fail_fast_errors: @fail_fast_errors
|
|
80
|
+
fail_fast_errors: @fail_fast_errors,
|
|
81
|
+
tls_cert_chain: ch(path, :tls_cert_chain),
|
|
82
|
+
tls_private_key: ch(path, :tls_private_key),
|
|
83
|
+
tls_verify_peer: ch(path, :tls_verify_peer))
|
|
75
84
|
end
|
|
76
85
|
end
|
|
77
86
|
|
|
@@ -233,6 +242,13 @@ module Consul
|
|
|
233
242
|
connect_timeout: 5, # default connection setup timeout
|
|
234
243
|
inactivity_timeout: conf.wait_duration + 1 + (conf.wait_duration / 16) # default connection inactivity (post-setup) timeout
|
|
235
244
|
}
|
|
245
|
+
unless conf.tls_cert_chain.nil?
|
|
246
|
+
options[:tls] = {
|
|
247
|
+
cert_chain_file: conf.tls_cert_chain,
|
|
248
|
+
private_key_file: conf.tls_private_key,
|
|
249
|
+
verify_peer: conf.tls_verify_peer
|
|
250
|
+
}
|
|
251
|
+
end
|
|
236
252
|
connection = {
|
|
237
253
|
conn: EventMachine::HttpRequest.new(conf.base_url, options)
|
|
238
254
|
}
|
|
@@ -31,7 +31,8 @@ module Consul
|
|
|
31
31
|
|
|
32
32
|
def as_json(url, default_value, refresh_delay_secs: 10, **opts)
|
|
33
33
|
conf = JSONConfiguration.new(url: url, min_duration: refresh_delay_secs, retry_on_non_diff: refresh_delay_secs, **opts)
|
|
34
|
-
|
|
34
|
+
endpoint_id = url + opts.to_json
|
|
35
|
+
@endp_manager.create_if_missing(url, {}, endpoint_id: endpoint_id) do
|
|
35
36
|
if default_value.is_a?(Array)
|
|
36
37
|
ConsulTemplateJSONArray.new(JSONEndpoint.new(conf, url, default_value))
|
|
37
38
|
else
|
|
@@ -161,6 +162,18 @@ module Consul
|
|
|
161
162
|
create_if_missing(path, query_params, agent: agent) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
|
|
162
163
|
end
|
|
163
164
|
|
|
165
|
+
# https://www.consul.io/api-docs/health#list-checks-in-state
|
|
166
|
+
# Supported in Consul 1.7+
|
|
167
|
+
def checks_in_state(check_state, dc: nil, agent: nil)
|
|
168
|
+
valid_checks_states = %w[any critical passing warning]
|
|
169
|
+
raise "checks_in_state('#{check_state}'...) must be one of #{valid_checks_states}" unless valid_checks_states.include?(check_state)
|
|
170
|
+
|
|
171
|
+
path = "/v1/health/state/#{check_state}"
|
|
172
|
+
query_params = {}
|
|
173
|
+
query_params[:dc] = dc if dc
|
|
174
|
+
create_if_missing(path, query_params, agent: agent) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
|
|
175
|
+
end
|
|
176
|
+
|
|
164
177
|
# https://www.consul.io/api/catalog.html#list-nodes
|
|
165
178
|
def nodes(dc: nil, agent: nil)
|
|
166
179
|
path = '/v1/catalog/nodes'
|
|
@@ -382,16 +395,21 @@ module Consul
|
|
|
382
395
|
VaultEndpoint.new(vault_conf, path, :POST, {}, {})
|
|
383
396
|
end
|
|
384
397
|
|
|
385
|
-
def create_if_missing(path, query_params, fail_fast_errors: @fail_fast_errors,
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
398
|
+
def create_if_missing(path, query_params, fail_fast_errors: @fail_fast_errors,
|
|
399
|
+
max_consecutive_errors_on_endpoint: @max_consecutive_errors_on_endpoint,
|
|
400
|
+
agent: nil, endpoint_id: nil)
|
|
401
|
+
endpoint_id ||= begin
|
|
402
|
+
fqdn = path.dup
|
|
403
|
+
query_params.each_pair do |k, v|
|
|
404
|
+
fqdn = "#{agent}#{fqdn}&#{k}=#{v}"
|
|
405
|
+
end
|
|
406
|
+
fqdn
|
|
407
|
+
end
|
|
408
|
+
tpl = @endpoints[endpoint_id]
|
|
391
409
|
unless tpl
|
|
392
410
|
tpl = yield
|
|
393
411
|
::Consul::Async::Debug.print_debug "path #{path.ljust(64)} #{query_params.inspect}\r"
|
|
394
|
-
@endpoints[
|
|
412
|
+
@endpoints[endpoint_id] = tpl
|
|
395
413
|
tpl.endpoint.on_response do |result|
|
|
396
414
|
@net_info[:success] += 1
|
|
397
415
|
@net_info[:bytes_read] += result.data.bytesize
|
|
@@ -59,7 +59,7 @@ module Consul
|
|
|
59
59
|
return false unless new_template != @template
|
|
60
60
|
|
|
61
61
|
# We render to ensure the template is valid
|
|
62
|
-
render(new_template, current_template_info)
|
|
62
|
+
render(new_template, current_template_info: current_template_info)
|
|
63
63
|
@template = new_template.freeze
|
|
64
64
|
true
|
|
65
65
|
end
|
|
@@ -9,7 +9,7 @@ module Consul
|
|
|
9
9
|
class JSONConfiguration
|
|
10
10
|
attr_reader :url, :retry_duration, :min_duration, :retry_on_non_diff,
|
|
11
11
|
:debug, :enable_gzip_compression, :request_method, :json_body,
|
|
12
|
-
:headers
|
|
12
|
+
:headers, :tls_cert_chain, :tls_private_key, :tls_verify_peer
|
|
13
13
|
def initialize(url:,
|
|
14
14
|
debug: { network: false },
|
|
15
15
|
retry_duration: 10,
|
|
@@ -18,7 +18,10 @@ module Consul
|
|
|
18
18
|
request_method: :get,
|
|
19
19
|
json_body: nil,
|
|
20
20
|
headers: {},
|
|
21
|
-
enable_gzip_compression: true
|
|
21
|
+
enable_gzip_compression: true,
|
|
22
|
+
tls_cert_chain: nil,
|
|
23
|
+
tls_private_key: nil,
|
|
24
|
+
tls_verify_peer: true)
|
|
22
25
|
@url = url
|
|
23
26
|
@debug = debug
|
|
24
27
|
@enable_gzip_compression = enable_gzip_compression
|
|
@@ -28,6 +31,9 @@ module Consul
|
|
|
28
31
|
@request_method = request_method
|
|
29
32
|
@json_body = json_body
|
|
30
33
|
@headers = headers
|
|
34
|
+
@tls_cert_chain = tls_cert_chain
|
|
35
|
+
@tls_private_key = tls_private_key
|
|
36
|
+
@tls_verify_peer = tls_verify_peer
|
|
31
37
|
end
|
|
32
38
|
|
|
33
39
|
def create(_url)
|
|
@@ -181,6 +187,13 @@ module Consul
|
|
|
181
187
|
connect_timeout: 5, # default connection setup timeout
|
|
182
188
|
inactivity_timeout: 60 # default connection inactivity (post-setup) timeout
|
|
183
189
|
}
|
|
190
|
+
unless conf.tls_cert_chain.nil?
|
|
191
|
+
options[:tls] = {
|
|
192
|
+
cert_chain_file: conf.tls_cert_chain,
|
|
193
|
+
private_key_file: conf.tls_private_key,
|
|
194
|
+
verify_peer: conf.tls_verify_peer
|
|
195
|
+
}
|
|
196
|
+
end
|
|
184
197
|
connection = {
|
|
185
198
|
conn: EventMachine::HttpRequest.new(conf.url, options)
|
|
186
199
|
}
|
|
@@ -7,7 +7,8 @@ module Consul
|
|
|
7
7
|
# Handle the full lifecycle of a process and allows to forward
|
|
8
8
|
# Posix signals to child process when needed.
|
|
9
9
|
class ProcessHandler
|
|
10
|
-
attr_reader :command, :sig_reload, :sig_term, :pid, :exit_status
|
|
10
|
+
attr_reader :command, :sig_reload, :sig_term, :pid, :exit_status, :last_signal_sent, :reload_scheduled
|
|
11
|
+
attr_writer :reload_scheduled
|
|
11
12
|
def initialize(command, sig_reload: 'HUP', sig_term: 'TERM')
|
|
12
13
|
raise 'empty sig_term is not supported' unless sig_term
|
|
13
14
|
|
|
@@ -16,18 +17,23 @@ module Consul
|
|
|
16
17
|
@sig_term = sig_term
|
|
17
18
|
@pid = nil
|
|
18
19
|
@exit_status = nil
|
|
20
|
+
@last_signal_sent = Time.now
|
|
21
|
+
@reload_scheduled = false
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
def start
|
|
22
25
|
return pid unless pid.nil?
|
|
23
26
|
|
|
24
27
|
@pid = Process.spawn(command)
|
|
28
|
+
@last_signal_sent = Time.now
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
def reload
|
|
28
32
|
return if sig_reload.nil?
|
|
29
33
|
|
|
34
|
+
@last_signal_sent = Time.now
|
|
30
35
|
warn "Sending SIG #{sig_reload} to #{pid}..."
|
|
36
|
+
@reload_scheduled = false
|
|
31
37
|
begin
|
|
32
38
|
Process.kill(sig_reload, pid)
|
|
33
39
|
rescue Errno::ESRCH => e
|
|
@@ -10,7 +10,8 @@ module Consul
|
|
|
10
10
|
# Configuration for Vault Endpoints
|
|
11
11
|
class VaultConfiguration
|
|
12
12
|
attr_reader :base_url, :token, :token_renew, :retry_duration, :min_duration, :wait_duration, :max_retry_duration, :retry_on_non_diff,
|
|
13
|
-
:lease_duration_factor, :debug, :max_consecutive_errors_on_endpoint, :fail_fast_errors
|
|
13
|
+
:lease_duration_factor, :debug, :max_consecutive_errors_on_endpoint, :fail_fast_errors, :tls_cert_chain, :tls_private_key,
|
|
14
|
+
:tls_verify_peer
|
|
14
15
|
|
|
15
16
|
def initialize(base_url: 'http://localhost:8200',
|
|
16
17
|
debug: { network: false },
|
|
@@ -22,7 +23,10 @@ module Consul
|
|
|
22
23
|
max_retry_duration: 600,
|
|
23
24
|
paths: {},
|
|
24
25
|
max_consecutive_errors_on_endpoint: 10,
|
|
25
|
-
fail_fast_errors: false
|
|
26
|
+
fail_fast_errors: false,
|
|
27
|
+
tls_cert_chain: nil,
|
|
28
|
+
tls_private_key: nil,
|
|
29
|
+
tls_verify_peer: true)
|
|
26
30
|
@base_url = base_url
|
|
27
31
|
@token_renew = token_renew
|
|
28
32
|
@debug = debug
|
|
@@ -34,6 +38,9 @@ module Consul
|
|
|
34
38
|
@token = token
|
|
35
39
|
@max_consecutive_errors_on_endpoint = max_consecutive_errors_on_endpoint
|
|
36
40
|
@fail_fast_errors = fail_fast_errors
|
|
41
|
+
@tls_cert_chain = tls_cert_chain
|
|
42
|
+
@tls_private_key = tls_private_key
|
|
43
|
+
@tls_verify_peer = tls_verify_peer
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
def ch(path, symbol)
|
|
@@ -226,6 +233,13 @@ module Consul
|
|
|
226
233
|
connect_timeout: 5, # default connection setup timeout
|
|
227
234
|
inactivity_timeout: 1 # default connection inactivity (post-setup) timeout
|
|
228
235
|
}
|
|
236
|
+
unless conf.tls_cert_chain.nil?
|
|
237
|
+
options[:tls] = {
|
|
238
|
+
cert_chain_file: conf.tls_cert_chain,
|
|
239
|
+
private_key_file: conf.tls_private_key,
|
|
240
|
+
verify_peer: conf.tls_verify_peer
|
|
241
|
+
}
|
|
242
|
+
end
|
|
229
243
|
connection = EventMachine::HttpRequest.new(conf.base_url, options)
|
|
230
244
|
cb = proc do |_|
|
|
231
245
|
http = connection.send(http_method.downcase, build_request) # Under the hood: c.send('get', {stuff}) === c.get({stuff})
|
data/lib/consul/async/version.rb
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<%=
|
|
2
|
+
# This sample displays checks for the whole cluster
|
|
3
|
+
# in warning or critical state
|
|
4
|
+
# API available with Consul 1.7+
|
|
5
|
+
res = []
|
|
6
|
+
checks_in_state('warning').each do |c|
|
|
7
|
+
res << c
|
|
8
|
+
end
|
|
9
|
+
checks_in_state('critical').each do |c|
|
|
10
|
+
res << c
|
|
11
|
+
end
|
|
12
|
+
YAML.dump({'warning_or_critical_checks' => res})
|
|
13
|
+
%>
|
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Use this file to configure custom decorators for your Consul-UI
|
|
2
2
|
var httpRegexp = new RegExp('^http[s]?://[^ ]+$');
|
|
3
|
-
var dc = "<%= ENV['CRITEO_DC'] || 'par'%>";
|
|
4
|
-
var env = "<%= ENV['CRITEO_ENV'] || 'preprod'%>";
|
|
5
|
-
|
|
6
|
-
var availability_url = 'https://grafana.crto.in/d/xFX5gCnWz/service-availability?var-datacenter=' + dc + '&var-service=';
|
|
7
|
-
if (env == 'preprod') {
|
|
8
|
-
availability_url = 'https://grafana.preprod.crto.in/d/E0ANGjnZz/service-availability?var-datacenter=' + dc + '&var-service=';
|
|
9
|
-
}
|
|
10
|
-
var swagger_url = 'https://swaggercatalogapp.' + dc + '.' + env + '.crto.in/explore/swagger?key=';
|
|
11
|
-
var slack_url = 'https://criteo.slack.com/app_redirect?channel=';
|
|
12
|
-
|
|
13
|
-
var rackguru_url = 'https://rackguru.' + env + '.crto.in/serial/';
|
|
14
|
-
|
|
15
|
-
var asapi_url = 'https://idm.' + env + '.crto.in/tool/multiGroupInfo/'
|
|
16
3
|
|
|
17
4
|
function url_decorator(key, value) {
|
|
18
5
|
var e = document.createElement('a');
|
|
@@ -26,27 +13,7 @@ function usefullLinksGenerator(instance, serviceName, node_meta_info) {
|
|
|
26
13
|
top.className = 'instance-links';
|
|
27
14
|
|
|
28
15
|
var usefullLinks = [
|
|
29
|
-
{
|
|
30
|
-
title: "Trigger security scan",
|
|
31
|
-
iconClassName: "fas fa-shield-alt",
|
|
32
|
-
href: "https://security.crto.in/#/scan/?ip=" + instance.addr
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
title: "Availability Graph",
|
|
36
|
-
iconClassName: "fas fa-chart-area",
|
|
37
|
-
href: availability_url + serviceName
|
|
38
|
-
},
|
|
39
16
|
];
|
|
40
|
-
if (node_meta_info!= null) {
|
|
41
|
-
var serial = node_meta_info['serial_number'];
|
|
42
|
-
if (serial != null) {
|
|
43
|
-
usefullLinks.push({
|
|
44
|
-
title: "RackGuru",
|
|
45
|
-
iconClassName: "fas fa-server",
|
|
46
|
-
href: rackguru_url + serial
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
17
|
var first = true;
|
|
51
18
|
for (let usefullLink of usefullLinks) {
|
|
52
19
|
link = document.createElement('a');
|
|
@@ -134,19 +101,6 @@ function groups_decorator(instance, key, value, serviceName) {
|
|
|
134
101
|
return span;
|
|
135
102
|
}
|
|
136
103
|
|
|
137
|
-
/**
|
|
138
|
-
* Decorates with a slack channel link
|
|
139
|
-
*/
|
|
140
|
-
function slack_channel(instance, key, value, serviceName) {
|
|
141
|
-
var sName = value;
|
|
142
|
-
if (sName.startsWith('#')) {
|
|
143
|
-
sName = sName.substring(1);
|
|
144
|
-
}
|
|
145
|
-
return build_link(slack_url + encodeURIComponent(sName), '#'+ sName);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const start_regexp = /(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})Z/
|
|
149
|
-
|
|
150
104
|
function decorateIsoDate(value, formated) {
|
|
151
105
|
const parsed = Date.parse(formated);
|
|
152
106
|
if (isNaN(parsed)) {
|
|
@@ -163,55 +117,6 @@ function decorateIsoDate(value, formated) {
|
|
|
163
117
|
// This is the list of function called
|
|
164
118
|
// When a service meta is found
|
|
165
119
|
var registered_decorators = {
|
|
166
|
-
alert_availability_slack_channel: slack_channel,
|
|
167
|
-
gerrit_repository: function(instance, key, value, serviceName) {
|
|
168
|
-
return build_link('https://review.crto.in/#/q/' + value, value);
|
|
169
|
-
},
|
|
170
|
-
version: function(instance, key, value, serviceName) {
|
|
171
|
-
var asInt = parseInt(value);
|
|
172
|
-
if (asInt < 10000) {
|
|
173
|
-
return document.createTextNode(value);
|
|
174
|
-
}
|
|
175
|
-
if (instance.sMeta['CRITEO_APP_POOL'] != null) {
|
|
176
|
-
return build_link("https://devtools.crto.in/log.html?moab=cs&im=nb-to&range=100%2C" + asInt, value);
|
|
177
|
-
} else {
|
|
178
|
-
var tUrl = "https://devtools.crto.in/log.html?moab=j&im=nb-to&range=100%2C" + asInt;
|
|
179
|
-
if (instance.sMeta['jvm_artifact'] != null) {
|
|
180
|
-
tUrl += '&with-dependencies=true&artifacts=' + encodeURIComponent(instance.sMeta['jvm_artifact']);
|
|
181
|
-
}
|
|
182
|
-
return build_link(tUrl, value);
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
MESOS_TERM_DEBUG_GRANTED_TO: groups_decorator,
|
|
186
|
-
OWNERS: groups_decorator,
|
|
187
|
-
marathon_app_id: function(instance, key, value, serviceName) {
|
|
188
|
-
var app_name = value;
|
|
189
|
-
if (app_name[0] != '/') {
|
|
190
|
-
app_name = '/' + app_name;
|
|
191
|
-
}
|
|
192
|
-
if (instance.sMeta && instance.sMeta['marathon_ui']) {
|
|
193
|
-
return build_link(instance.sMeta['marathon_ui'] + '/#/apps/' + encodeURIComponent(app_name), value);
|
|
194
|
-
} else {
|
|
195
|
-
// non decorated value
|
|
196
|
-
return document.createTextNode(value);
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
marathon_app_version: function(instance, key, value, serviceName) {
|
|
200
|
-
return decorateIsoDate(value, value);
|
|
201
|
-
},
|
|
202
|
-
slack_channel: slack_channel,
|
|
203
|
-
start: function(instance, key, value, serviceName) {
|
|
204
|
-
const reg = start_regexp.exec(value);
|
|
205
|
-
if (reg != null) {
|
|
206
|
-
var formated = reg[1] + '-' + reg[2] + '-' + reg[3] + 'T' + reg[4] + ':' + reg[5] + ':' + reg[6] + 'Z';
|
|
207
|
-
return decorateIsoDate(value, formated);
|
|
208
|
-
} else {
|
|
209
|
-
return document.createTextNode(value);
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
swagger_key: function(instance, key, value, serviceName) {
|
|
213
|
-
return build_link(swagger_url + encodeURIComponent(value), value);
|
|
214
|
-
},
|
|
215
120
|
}
|
|
216
121
|
|
|
217
122
|
function service_meta_semantics_decorator(instance, key, value, serviceName) {
|
|
@@ -286,85 +191,11 @@ function nodeMetaGenerator(nodeMetaTags, serviceMetaIfAny) {
|
|
|
286
191
|
* it does not have to return anything.
|
|
287
192
|
*/
|
|
288
193
|
function navBarDecorator(navbar) {
|
|
289
|
-
if (typeof consulManager === 'undefined') {
|
|
290
|
-
// Timepicker is not supported on this page
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
var timepicker_container = document.createElement('div');
|
|
294
|
-
timepicker_container.innerHTML = `
|
|
295
|
-
<div class="row">
|
|
296
|
-
<button type="button" disabled class="btn btn-secondary" data-toggle="tooltip" data-html="true" title="Data returned is the closest available to request" id="currently-displayed-data-date">
|
|
297
|
-
Pick a date to see data from the past
|
|
298
|
-
</button>
|
|
299
|
-
<div class="col-sm-14">
|
|
300
|
-
<div class="form-group">
|
|
301
|
-
<div class="input-group date" id="datetimepicker1" data-target-input="nearest">
|
|
302
|
-
<input type="text" class="form-control datetimepicker-input" data-target="#datetimepicker1"/>
|
|
303
|
-
<div class="input-group-append" data-target="#datetimepicker1" data-toggle="datetimepicker">
|
|
304
|
-
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
307
|
-
</div>
|
|
308
|
-
</div>
|
|
309
|
-
</div>
|
|
310
|
-
`;
|
|
311
|
-
|
|
312
|
-
navbar.appendChild(timepicker_container);
|
|
313
|
-
var script= document.createElement('script');
|
|
314
|
-
script.type='text/javascript';
|
|
315
|
-
// TODO(g.seux): extract code to another file and set "source" on script element
|
|
316
|
-
script.innerHTML = `
|
|
317
|
-
$('#datetimepicker1').datetimepicker({
|
|
318
|
-
format: 'DD/MM/YYYY HH:mm:ss Z', // default format does not allow to select seconds
|
|
319
|
-
sideBySide: true, // display date+time on the same widget
|
|
320
|
-
useCurrent: true // by default, select current date
|
|
321
|
-
});
|
|
322
|
-
$("#datetimepicker1").on("change.datetimepicker", function (e) {
|
|
323
|
-
console.log("Will fetch data from date " + e.date);
|
|
324
|
-
console.log("will clean existing data");
|
|
325
|
-
consulManager.clean().then(function(result) {
|
|
326
|
-
switch(consulManager.constructor.name) {
|
|
327
|
-
case "ConsulServiceManager":
|
|
328
|
-
backup_type = 'consul_services';
|
|
329
|
-
break;
|
|
330
|
-
case "ConsulKeysManager":
|
|
331
|
-
backup_type = 'consul_keys'
|
|
332
|
-
break;
|
|
333
|
-
case "ConsulNodesManager":
|
|
334
|
-
backup_type = 'consul_nodes'
|
|
335
|
-
break;
|
|
336
|
-
default:
|
|
337
|
-
console.log("Unknown " + consulManager.constructor.name + " type");
|
|
338
|
-
}
|
|
339
|
-
if (e.date) {
|
|
340
|
-
console.log("Will replace data by closest snapshot to " + e.date);
|
|
341
|
-
var target_url = "https://consul-info-timeline-history.<%= ENV['CRITEO_DC'] %>.<%= ENV['CRITEO_ENV']%>.crto.in/backup/" + backup_type + "/" + e.date / 1000;
|
|
342
|
-
} else {
|
|
343
|
-
console.log("Will restore to local version");
|
|
344
|
-
var target_url = defaultConsulManager.resourceURL;
|
|
345
|
-
}
|
|
346
|
-
if (typeof(defaultConsulManager) == 'undefined') {
|
|
347
|
-
// store first manager to be able to restore it
|
|
348
|
-
defaultConsulManager = consulManager
|
|
349
|
-
}
|
|
350
|
-
consulManager = new consulManager.constructor(target_url);
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
`;
|
|
354
|
-
navbar.appendChild(script);
|
|
355
194
|
}
|
|
356
195
|
|
|
357
|
-
|
|
358
196
|
/**
|
|
359
197
|
* fetchedResponseDecorator is called with http response when a resource is fetched by any instance of ConsulUIManager
|
|
360
198
|
* it does not have to return anything.
|
|
361
199
|
*/
|
|
362
200
|
async function fetchedResponseDecorator(httpResponse) {
|
|
363
|
-
|
|
364
|
-
current_date_display = $('#currently-displayed-data-date');
|
|
365
|
-
if (data_date > 0) {
|
|
366
|
-
current_date_display.html("Data is a snapshot from: " + moment.unix(data_date).format('DD/MM/YYYY HH:mm:ss Z'));
|
|
367
|
-
} else {
|
|
368
|
-
current_date_display.html("Pick a date to see data from the past");
|
|
369
|
-
}
|
|
370
|
-
}
|
|
201
|
+
}
|
|
@@ -111,7 +111,7 @@ class NodeMainSelector extends MainSelector {
|
|
|
111
111
|
nodesChecks.appendChild(checksStatusGenerator(node, node['Node']['Name']));
|
|
112
112
|
content.appendChild(nodesChecks);
|
|
113
113
|
|
|
114
|
-
content.appendChild(servicesGenerator(node['Service']));
|
|
114
|
+
content.appendChild(servicesGenerator(node['Service'], node));
|
|
115
115
|
content.appendChild(tagsGenerator(getTagsNode(node)));
|
|
116
116
|
|
|
117
117
|
sidebar.setAttribute('status', state);
|
|
@@ -304,7 +304,7 @@ class ServiceMainSelector extends MainSelector {
|
|
|
304
304
|
element.setAttribute("class", "list-group-item service-instance");
|
|
305
305
|
var state = nodeState(instance.checks);
|
|
306
306
|
element.appendChild(weightsGenerator(instance.weights, state));
|
|
307
|
-
element.appendChild(serviceTitleGenerator(instance));
|
|
307
|
+
element.appendChild(serviceTitleGenerator(instance, serviceName));
|
|
308
308
|
var node_info = this.nodes[instance.name];
|
|
309
309
|
if (node_info != null) {
|
|
310
310
|
node_info = node_info.meta;
|
|
@@ -63,7 +63,7 @@ function nodeState(checks) {
|
|
|
63
63
|
|
|
64
64
|
supported_protocols = ['https', 'http', 'sftp', 'ftp', 'ssh', 'telnet']
|
|
65
65
|
|
|
66
|
-
function serviceTitleGenerator(instance) {
|
|
66
|
+
function serviceTitleGenerator(instance, serviceName) {
|
|
67
67
|
var protocol = null;
|
|
68
68
|
for (i in supported_protocols) {
|
|
69
69
|
var protoc = supported_protocols[i]
|
|
@@ -74,10 +74,6 @@ function serviceTitleGenerator(instance) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
var htmlTitle = document.createElement('h5');
|
|
77
|
-
htmlTitle.setAttribute('title', 'Node Name: ' + instance.name +
|
|
78
|
-
'\nAddress: ' + instance.addr +
|
|
79
|
-
'\nService ID: ' + instance.id +
|
|
80
|
-
'\nService Port: ' + instance.port);
|
|
81
77
|
|
|
82
78
|
htmlTitle.setAttribute('class', 'instance-name');
|
|
83
79
|
var instanceLink = document.createElement('a');
|
|
@@ -91,6 +87,15 @@ function serviceTitleGenerator(instance) {
|
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
instanceLink.appendChild(document.createTextNode(instance.name + appendPort));
|
|
90
|
+
const nodeInfo = document.createElement('a');
|
|
91
|
+
nodeInfo.appendChild(document.createTextNode('\u24D8'));
|
|
92
|
+
nodeInfo.setAttribute('title', 'Click to see details of Node: ' + instance.name +
|
|
93
|
+
'\nAddress: ' + instance.addr +
|
|
94
|
+
'\nService ID: ' + instance.id +
|
|
95
|
+
'\nService Port: ' + instance.port);
|
|
96
|
+
nodeInfo.setAttribute('href', 'consul-nodes-ui.html?node_filter=^' + encodeURIComponent(instance.name) + '$');
|
|
97
|
+
htmlTitle.appendChild(nodeInfo);
|
|
98
|
+
htmlTitle.appendChild(document.createTextNode(' '));
|
|
94
99
|
htmlTitle.appendChild(instanceLink);
|
|
95
100
|
htmlTitle.appendChild(document.createTextNode(' '));
|
|
96
101
|
htmlTitle.appendChild(document.createTextNode(instance.addr));
|
|
@@ -216,24 +221,44 @@ function toCSSClass(state) {
|
|
|
216
221
|
return state;
|
|
217
222
|
}
|
|
218
223
|
|
|
219
|
-
function servicesGenerator(instanceServices) {
|
|
220
|
-
var
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
+
function servicesGenerator(instanceServices, node) {
|
|
225
|
+
var servicesTop = document.createElement('div');
|
|
226
|
+
servicesTop.className = 'instance-services';
|
|
227
|
+
const card = document.createElement('div');
|
|
228
|
+
card.setAttribute('class', 'card');
|
|
229
|
+
const servicesCard = document.createElement('div');
|
|
230
|
+
servicesCard.setAttribute('class', 'card-body');
|
|
231
|
+
const title = document.createElement('h5');
|
|
232
|
+
title.appendChild(document.createTextNode('Services'));
|
|
233
|
+
title.setAttribute('class', 'card-title')
|
|
234
|
+
servicesCard.appendChild(title);
|
|
235
|
+
const services = document.createElement('div');
|
|
236
|
+
servicesCard.appendChild(services);
|
|
224
237
|
for (var serviceKey in instanceServices) {
|
|
225
|
-
|
|
226
|
-
|
|
238
|
+
const serviceGrp = document.createElement('span');
|
|
239
|
+
serviceGrp.setAttribute('class', 'btn btn-sm');
|
|
240
|
+
serviceGrp.classList.add('btn-outline-' + toCSSClass(nodeState(instanceServices[serviceKey]['Checks'])))
|
|
241
|
+
const service = document.createElement('a');
|
|
242
|
+
serviceGrp.appendChild(service);
|
|
243
|
+
const serviceName = instanceServices[serviceKey]['Service']['Service'];
|
|
244
|
+
service.setAttribute('class', 'serviceLink');
|
|
245
|
+
service.setAttribute('href', 'consul-services-ui.html?service=' + encodeURIComponent(serviceName) + '&node_filter=^' + encodeURIComponent(node['Node']['Name'])+'$');
|
|
246
|
+
service.appendChild(document.createTextNode(serviceName));
|
|
227
247
|
var servicePort = instanceServices[serviceKey]['Service']['Port'];
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
248
|
+
if (servicePort) {
|
|
249
|
+
// Add unbreakable space
|
|
250
|
+
serviceGrp.appendChild(document.createTextNode('\u00A0'));
|
|
251
|
+
const servicePortElem = document.createElement('a');
|
|
252
|
+
servicePortElem.setAttribute('class', 'serviceTargetPort');
|
|
253
|
+
const nodeAddr = instanceServices[serviceKey]['Service']['Address'];
|
|
254
|
+
servicePortElem.setAttribute('href', 'http://' + nodeAddr + ':' + servicePort);
|
|
255
|
+
servicePortElem.appendChild(document.createTextNode(':' + servicePort));
|
|
256
|
+
serviceGrp.appendChild(servicePortElem);
|
|
257
|
+
}
|
|
258
|
+
services.appendChild(serviceGrp);
|
|
235
259
|
}
|
|
236
|
-
|
|
260
|
+
servicesTop.appendChild(servicesCard);
|
|
261
|
+
return servicesTop;
|
|
237
262
|
}
|
|
238
263
|
|
|
239
264
|
function checksStatusGenerator(instance, prefix) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%
|
|
2
|
+
# This example show how to display local time informaition about changes
|
|
3
|
+
# Example of usage to display logs of changes on nodes() endpoint:
|
|
4
|
+
#
|
|
5
|
+
# consul-templaterb --template "display_timestamped_changes.txt.erb:display_timestamped_changes.txt:cat display_timestamped_changes.txt" -l error
|
|
6
|
+
#
|
|
7
|
+
# Would output:
|
|
8
|
+
# Last update: 1588800554 (2020-05-06 21:29:14 UTC), X-Consul-Index: 4345827328
|
|
9
|
+
# Last update: 1588800569 (2020-05-06 21:29:29 UTC), X-Consul-Index: 4345829548
|
|
10
|
+
# Last update: 1588800676 (2020-05-06 21:31:16 UTC), X-Consul-Index: 4345836342
|
|
11
|
+
#
|
|
12
|
+
@my_last_time = Time.now.utc unless @my_last_time
|
|
13
|
+
val = nodes()
|
|
14
|
+
new_idx = val.endpoint.x_consul_index
|
|
15
|
+
@my_last_time = Time.now.utc if @my_last_idx != new_idx
|
|
16
|
+
@my_last_idx = new_idx
|
|
17
|
+
%>Last update: <%= @my_last_time.to_i %> (<%= @my_last_time %>), X-Consul-Index: <%= new_idx %>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# HELP consul_wan_servers_rtt_seconds Min Round trip with other servers of DC
|
|
2
|
+
# TYPE consul_wan_servers_rtt_seconds gauge
|
|
3
|
+
<%
|
|
4
|
+
# This computes the RTT over WAN for all DCs
|
|
5
|
+
results = {'min' => {}, 'max' => {}, 'p50' => {}, 'p90' => {}}
|
|
6
|
+
my_dcname = (agent_self['Config'] || {})['Datacenter']
|
|
7
|
+
my_dc = coordinate.datacenters.select { |d| d['Datacenter'] == my_dcname }.first
|
|
8
|
+
|
|
9
|
+
def percentile(values_sorted, percentile)
|
|
10
|
+
k = (percentile*(values_sorted.length-1)+1).floor - 1
|
|
11
|
+
f = (percentile*(values_sorted.length-1)+1).modulo(1)
|
|
12
|
+
return values_sorted[k] + (f * (values_sorted[k+1] - values_sorted[k]))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
if my_dc
|
|
16
|
+
from = my_dc['Datacenter']
|
|
17
|
+
coordinate.datacenters.each do |dc_coords|
|
|
18
|
+
min = Float::MAX
|
|
19
|
+
max = 0
|
|
20
|
+
rtts = []
|
|
21
|
+
dc_coords['Coordinates'].each do |s2|
|
|
22
|
+
my_dc['Coordinates'].each do |s1|
|
|
23
|
+
rtt = coordinate.rtt(s1['Coord'], s2['Coord'])
|
|
24
|
+
min = rtt if rtt < min
|
|
25
|
+
max = rtt if rtt > max
|
|
26
|
+
idx = rtts.bsearch_index { |x| x > rtt }
|
|
27
|
+
if idx.nil?
|
|
28
|
+
rtts << rtt
|
|
29
|
+
else
|
|
30
|
+
rtts = rtts.insert(idx, rtt)
|
|
31
|
+
end
|
|
32
|
+
%>
|
|
33
|
+
consul_wan_servers_rtt_seconds{from="<%= from %>",to="<%= dc_coords['Datacenter'] %>",from_node="<%= s1['Node'] %>",to_node="<%= s2['Node'] %>"} <%= rtt.round(3) %><%
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
results['min'][dc_coords['Datacenter']] = min
|
|
37
|
+
results['max'][dc_coords['Datacenter']] = max
|
|
38
|
+
results['p50'][dc_coords['Datacenter']] = percentile(rtts, 0.5)
|
|
39
|
+
results['p90'][dc_coords['Datacenter']] = percentile(rtts, 0.9)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Now, we iterate over aggregated results, type is min, max...
|
|
43
|
+
results.each do |type, res_type|
|
|
44
|
+
%>
|
|
45
|
+
|
|
46
|
+
# HELP consul_wan_dc_<%= type %>_seconds <%= type %> round trip with other DCs
|
|
47
|
+
# TYPE consul_wan_dc_<%= type %>_seconds gauge
|
|
48
|
+
<%
|
|
49
|
+
# Iterate over destinations
|
|
50
|
+
res_type.each do |dst, val|
|
|
51
|
+
%>consul_wan_dc_<%= type %>_seconds{from="<%= my_dcname %>",to="<%= dst %>"} <%= val.round(3) %>
|
|
52
|
+
<%
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
%>
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: consul-templaterb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.28.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SRE Core Services
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-09-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: em-http-request
|
|
@@ -198,6 +198,7 @@ files:
|
|
|
198
198
|
- samples/all_services.txt.erb
|
|
199
199
|
- samples/all_services_multi_agents.txt.erb
|
|
200
200
|
- samples/all_templates.erb
|
|
201
|
+
- samples/checks_in_warning_or_critical_state.yaml.erb
|
|
201
202
|
- samples/consul-ui/README.md
|
|
202
203
|
- samples/consul-ui/common/footer.html.erb
|
|
203
204
|
- samples/consul-ui/common/header.html.erb
|
|
@@ -229,6 +230,7 @@ files:
|
|
|
229
230
|
- samples/criteo/haproxy.cfg.erb
|
|
230
231
|
- samples/debug/compare_connect_services.txt.erb
|
|
231
232
|
- samples/demos/compute_pricing.txt.erb
|
|
233
|
+
- samples/display_timestamped_changes.txt.erb
|
|
232
234
|
- samples/find_all_invalid_dns_labels.json.erb
|
|
233
235
|
- samples/find_nodes_in_catalog_but_not_in_members.json.erb
|
|
234
236
|
- samples/ha_proxy.cfg.erb
|
|
@@ -240,6 +242,7 @@ files:
|
|
|
240
242
|
- samples/members.json.erb
|
|
241
243
|
- samples/metrics.erb
|
|
242
244
|
- samples/prometheus_consul_coordinates.erb
|
|
245
|
+
- samples/prometheus_datacenter_coordinates.erb
|
|
243
246
|
- samples/render_template_from_kv.erb
|
|
244
247
|
- samples/sample_keys.html.erb
|
|
245
248
|
- samples/service_checks_metrics.erb
|
|
@@ -270,8 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
270
273
|
- !ruby/object:Gem::Version
|
|
271
274
|
version: '0'
|
|
272
275
|
requirements: []
|
|
273
|
-
|
|
274
|
-
rubygems_version: 2.7.7
|
|
276
|
+
rubygems_version: 3.0.8
|
|
275
277
|
signing_key:
|
|
276
278
|
specification_version: 4
|
|
277
279
|
summary: Implementation of Consul template using Ruby and .erb templating language
|