consul-templaterb 1.26.1 → 1.27.2
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 +37 -0
- data/Dockerfile +1 -1
- data/README.md +1 -1
- data/TemplateAPI.md +9 -0
- data/bin/consul-templaterb +30 -0
- data/lib/consul/async/consul_endpoint.rb +19 -3
- data/lib/consul/async/consul_template.rb +26 -8
- data/lib/consul/async/json_endpoint.rb +15 -2
- 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/README.md +19 -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/utils.js +45 -20
- data/samples/display_timestamped_changes.txt.erb +17 -0
- data/samples/find_nodes_in_catalog_but_not_in_members.json.erb +28 -0
- data/samples/metrics.erb +14 -0
- data/samples/prometheus_datacenter_coordinates.erb +56 -0
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a67e2df58bcd5c322789984815ff60bd95e50fc047cb20c929a67ca29c07f553
|
|
4
|
+
data.tar.gz: c4df4357ae2852ad487eb90336a0d2d7d380767d51d05e02e7b452d29acda9c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 723beb9fca614d1675e50cc1516f37c4aad93815a1725abcdecb33c8bf0aa5e399449f8c3826a14eac8705aa8cb354aa1034796cf68b46304624f958c1b2ba90
|
|
7
|
+
data.tar.gz: 379cb1ca86d8edc44c68694f70b6bd7c1373b8b707f26bef3459379554f94fa12f27653354dc52647eadbd2cf5b0df7cec7f01bcb457e7ed159b7396709ce00d
|
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: 182
|
|
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,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
## (UNRELEASED)
|
|
4
4
|
|
|
5
|
+
## 1.27.2 (Sept 4, 2020)
|
|
6
|
+
|
|
7
|
+
IMPROVEMENTS:
|
|
8
|
+
|
|
9
|
+
* Consul-UI now supports navigation between nodes and services in both ways
|
|
10
|
+
|
|
11
|
+
## 1.27.1 (July 28, 2020)
|
|
12
|
+
|
|
13
|
+
BUGIX:
|
|
14
|
+
|
|
15
|
+
* Fix collision in JSON queries when using payload in requests #68
|
|
16
|
+
|
|
17
|
+
## 1.27.0 (June 5, 2020)
|
|
18
|
+
|
|
19
|
+
NEW FEATURES:
|
|
20
|
+
|
|
21
|
+
* For Consul 1.7+, now support `checks_in_state(check_state, dc: nil, [agent: consul_agent_address])`,
|
|
22
|
+
fixes feature [#65](https://github.com/criteo/consul-templaterb/issues/65)
|
|
23
|
+
* New options to support/disable TLS validation thanks to [@jeromegn](https://github.com/jeromegn)
|
|
24
|
+
[#66](https://github.com/criteo/consul-templaterb/pull/66)
|
|
25
|
+
|
|
26
|
+
## 1.26.3 (April 15, 2020)
|
|
27
|
+
|
|
28
|
+
BUGFIX:
|
|
29
|
+
|
|
30
|
+
* Removed all Criteo specific decorators from Consul-UI
|
|
31
|
+
|
|
32
|
+
## 1.26.2 (April 15, 2020)
|
|
33
|
+
|
|
34
|
+
BUGFIX:
|
|
35
|
+
|
|
36
|
+
* Fixed broken Dockerfile (was missing the new `decorator.js.erb` file). Fixes #61 (Thanks to @ simongareste)
|
|
37
|
+
|
|
38
|
+
NEW FEATURES:
|
|
39
|
+
|
|
40
|
+
* Added `consul_members_count` metric in [samples/metrics.erb](samples/metrics.erb)
|
|
41
|
+
|
|
5
42
|
## 1.26.1 (March 27, 2020)
|
|
6
43
|
|
|
7
44
|
BUGFIX:
|
data/Dockerfile
CHANGED
|
@@ -12,4 +12,4 @@ ENV LANG C.UTF-8
|
|
|
12
12
|
ENV CONSUL_HTTP_ADDR http://consul-relay.service.consul.preprod.crto.in:8500
|
|
13
13
|
|
|
14
14
|
ENTRYPOINT ["/usr/local/bin/bundle", "exec", "consul-templaterb"]
|
|
15
|
-
CMD ["--template", "samples/consul-ui/consul-keys-ui.html.erb", "--template", "samples/consul-ui/consul-nodes-ui.html.erb", "--template", "samples/consul-ui/consul-services-ui.html.erb", "--template", "samples/consul-ui/consul-timeline-ui.html.erb", "--template", "samples/consul-ui/consul_keys.json.erb", "--template", "samples/consul-ui/consul_nodes.json.erb", "--template", "samples/consul-ui/consul_services.json.erb", "--template", "samples/consul-ui/timeline.json.erb", "--template", "samples/consul-ui/consul-services-ui.html.erb:samples/consul-ui/index.html:touch samples/consul-ui/ready", "--sig-reload=NONE", "--exec=nginx -c /usr/src/app/docker-nginx-conf/nginx.conf"]
|
|
15
|
+
CMD ["--template", "samples/consul-ui/consul-keys-ui.html.erb", "--template", "samples/consul-ui/decorators.js.erb", "--template", "samples/consul-ui/consul-nodes-ui.html.erb", "--template", "samples/consul-ui/consul-services-ui.html.erb", "--template", "samples/consul-ui/consul-timeline-ui.html.erb", "--template", "samples/consul-ui/consul_keys.json.erb", "--template", "samples/consul-ui/consul_nodes.json.erb", "--template", "samples/consul-ui/consul_services.json.erb", "--template", "samples/consul-ui/timeline.json.erb", "--template", "samples/consul-ui/consul-services-ui.html.erb:samples/consul-ui/index.html:touch samples/consul-ui/ready", "--sig-reload=NONE", "--exec=nginx -c /usr/src/app/docker-nginx-conf/nginx.conf"]
|
data/README.md
CHANGED
|
@@ -332,7 +332,7 @@ Please consult [CHANGELOG.md](CHANGELOG.md) for fixed bugs.
|
|
|
332
332
|
|
|
333
333
|
## TODO
|
|
334
334
|
|
|
335
|
-
* [x] Hashi's Vault support
|
|
335
|
+
* [x] Hashi's Vault support
|
|
336
336
|
* [ ] Implement automatic dynamic rate limit
|
|
337
337
|
* [x] More samples: apache, nginx, a full website displaying consul information...
|
|
338
338
|
* [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
|
|
@@ -122,6 +128,18 @@ optparse = OptionParser.new do |opts|
|
|
|
122
128
|
options[:consul][:base_url] = consul_url
|
|
123
129
|
end
|
|
124
130
|
|
|
131
|
+
opts.on('--consul-cert-chain=<path/to/cert_chain>', String, 'Path to Consul TLS client certificate chain to use') do |consul_client_cert|
|
|
132
|
+
options[:consul][:tls_cert_chain] = consul_client_cert
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
opts.on('--consul-private-key=<path/to/private_key>', String, 'Path to Consul TLS client private key to use') do |consul_client_key|
|
|
136
|
+
options[:consul][:tls_private_key] = consul_client_key
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
opts.on('--skip-consul-verify-tls', 'Skip verifying Consul TLS via certificate authority (DANGEROUS)') do
|
|
140
|
+
options[:consul][:tls_verify_peer] = false
|
|
141
|
+
end
|
|
142
|
+
|
|
125
143
|
opts.on('-l', '--log-level=<log_level>', String, "Log level, default=info, any of #{::Consul::Async::Debug.levels.join('|')}") do |log_level|
|
|
126
144
|
::Consul::Async::Debug.level = log_level
|
|
127
145
|
end
|
|
@@ -134,6 +152,18 @@ optparse = OptionParser.new do |opts|
|
|
|
134
152
|
options[:vault][:base_url] = vault_url
|
|
135
153
|
end
|
|
136
154
|
|
|
155
|
+
opts.on('--vault-cert-chain=<path/to/cert_chain>', String, 'Path to Vault TLS client certificate chain to use') do |vault_client_cert|
|
|
156
|
+
options[:vault][:tls_cert_chain] = vault_client_cert
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
opts.on('--vault-private-key=<path/to/private_key>', String, 'Path to Vault TLS client private key to use') do |vault_client_key|
|
|
160
|
+
options[:vault][:tls_private_key] = vault_client_key
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
opts.on('--skip-vault-verify-tls', 'Skip verifying Vault TLS via certificate authority (DANGEROUS)') do
|
|
164
|
+
options[:vault][:tls_verify_peer] = false
|
|
165
|
+
end
|
|
166
|
+
|
|
137
167
|
opts.on('-T', '--vault-token=<token>', String, 'Token used to authenticate against vault.') do |vault_token|
|
|
138
168
|
options[:vault][:token] = vault_token
|
|
139
169
|
end
|
|
@@ -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
|
|
@@ -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
|
}
|
|
@@ -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
|
+
%>
|
data/samples/consul-ui/README.md
CHANGED
|
@@ -50,6 +50,25 @@ The content is statically created, so you can serve it using any HTTP server ver
|
|
|
50
50
|
For development, you might use `python -m SimpleHTTPServer` in order to server the result
|
|
51
51
|
on your browser.
|
|
52
52
|
|
|
53
|
+
### Running it in production
|
|
54
|
+
|
|
55
|
+
Whatever your solution, be sure to have a index.html, so read next below on
|
|
56
|
+
how generating an index.html.
|
|
57
|
+
|
|
58
|
+
#### Running with web server
|
|
59
|
+
|
|
60
|
+
You can run it with your favoite web server, at Criteo we run it with nginx
|
|
61
|
+
which handles nicely cache and offer good performance.
|
|
62
|
+
|
|
63
|
+
In that case, consul-templaterb can start nginx with `--exec` or you can run it
|
|
64
|
+
as a daemon, in which case, consul-templaterb only generate the files.
|
|
65
|
+
|
|
66
|
+
#### Run it in Consul
|
|
67
|
+
|
|
68
|
+
You can run consul with `-ui-dir=/path/to/directory/of/consul-ui`, in such case
|
|
69
|
+
reaching consul on poort 8500 will redirect to the /ui/ path, displaying the UI
|
|
70
|
+
of your choice on http://consul-agent.example.org:8500/ui/.
|
|
71
|
+
|
|
53
72
|
### Generating index.html
|
|
54
73
|
|
|
55
74
|
By default, the command `consul-templaterb -c http://localhost:8500 samples/consul-ui/*.erb``
|
|
@@ -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);
|
|
@@ -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,28 @@
|
|
|
1
|
+
<%=
|
|
2
|
+
all_catalog = nodes.map{ |n| [n['Node'], n] }.to_h
|
|
3
|
+
all_members = agent_members.sort{ |a,b| a['Name'] <=> b['Name'] }
|
|
4
|
+
members_by_state = {}
|
|
5
|
+
all_members.each do |m|
|
|
6
|
+
state = m.status
|
|
7
|
+
members = members_by_state[state] || 0
|
|
8
|
+
members_by_state[state] = members + 1
|
|
9
|
+
end
|
|
10
|
+
# Find all virtual nodes (eg: k8s-sync)
|
|
11
|
+
catalog_external_sources = nodes.select{|n| (n['Meta']||{})['external-source'] }.map{|n| n['Node']}
|
|
12
|
+
in_catalog_but_not_in_members = all_catalog.keys - all_members.map{ |m| m['Name'] }
|
|
13
|
+
not_virtual_not_in_members = in_catalog_but_not_in_members - catalog_external_sources
|
|
14
|
+
JSON.pretty_generate(
|
|
15
|
+
{
|
|
16
|
+
'stats' => {
|
|
17
|
+
'catalog' => all_catalog.count,
|
|
18
|
+
'catalog_virtual' => in_catalog_but_not_in_members.count,
|
|
19
|
+
'members' => all_members.count,
|
|
20
|
+
'members_by_state': members_by_state,
|
|
21
|
+
'catalog_external_sources' => catalog_external_sources,
|
|
22
|
+
},
|
|
23
|
+
'errors': {
|
|
24
|
+
'in_catalog_but_not_in_members' => in_catalog_but_not_in_members,
|
|
25
|
+
'not_virtual_not_in_members' => not_virtual_not_in_members,
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
%>
|
data/samples/metrics.erb
CHANGED
|
@@ -21,6 +21,20 @@
|
|
|
21
21
|
all_stats = {}
|
|
22
22
|
service_count = 0
|
|
23
23
|
|
|
24
|
+
statuses = agent_members().map {|m| m.status}.reduce({}) do |sum, s|
|
|
25
|
+
v = sum[s] || 0
|
|
26
|
+
sum[s] = v + 1
|
|
27
|
+
sum
|
|
28
|
+
end
|
|
29
|
+
%>
|
|
30
|
+
# HELP consul_members_count A gauge of number of serf members with their count and their status('alive', 'leaving', 'left', 'failed')
|
|
31
|
+
# TYPE consul_members_count gauge
|
|
32
|
+
<%
|
|
33
|
+
statuses.each do |k, v|
|
|
34
|
+
%>
|
|
35
|
+
consul_members_count{serf="lan",status="<%= k %>"} <%= v %><%
|
|
36
|
+
end
|
|
37
|
+
|
|
24
38
|
services(tag: service_tag_filter).each do |service_name, tags|
|
|
25
39
|
if !services_blacklist.any? {|r| r.match(service_name)} && (instance_must_tag.nil? || tags.include?(instance_must_tag))
|
|
26
40
|
service_count += 1
|
|
@@ -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.27.2
|
|
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-04 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,7 +230,9 @@ 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
|
|
235
|
+
- samples/find_nodes_in_catalog_but_not_in_members.json.erb
|
|
233
236
|
- samples/ha_proxy.cfg.erb
|
|
234
237
|
- samples/haproxy_dns.cfg.erb
|
|
235
238
|
- samples/hosts.erb
|
|
@@ -239,6 +242,7 @@ files:
|
|
|
239
242
|
- samples/members.json.erb
|
|
240
243
|
- samples/metrics.erb
|
|
241
244
|
- samples/prometheus_consul_coordinates.erb
|
|
245
|
+
- samples/prometheus_datacenter_coordinates.erb
|
|
242
246
|
- samples/render_template_from_kv.erb
|
|
243
247
|
- samples/sample_keys.html.erb
|
|
244
248
|
- samples/service_checks_metrics.erb
|
|
@@ -269,8 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
269
273
|
- !ruby/object:Gem::Version
|
|
270
274
|
version: '0'
|
|
271
275
|
requirements: []
|
|
272
|
-
|
|
273
|
-
rubygems_version: 2.7.7
|
|
276
|
+
rubygems_version: 3.0.8
|
|
274
277
|
signing_key:
|
|
275
278
|
specification_version: 4
|
|
276
279
|
summary: Implementation of Consul template using Ruby and .erb templating language
|