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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc35b5803af2e05001323f77e18be90ec85baa05dd621030a83127cf1b5fd9f1
4
- data.tar.gz: f7d3e25054dcd6c1b022e5c4bf58ea902c5c95676aafa936512659eaec3de9a1
3
+ metadata.gz: c15ee78520048d7d091882b9d3b1d43b4cc5f5658cf39d782f06e1dc617d8cd9
4
+ data.tar.gz: 6f77a9daab557420f2640a314a97f78af68e26fec91c1a66f3ee575d9bf150f8
5
5
  SHA512:
6
- metadata.gz: e1e053e41716e64177917ef8a3ef1360ba82995758bb7dacfafd3bc7fb7a8f5774f107c62cbb7c4340189ea59cab15db936fc27854f6fab1ba487466ad0add3f
7
- data.tar.gz: 95c0584f456239478395ceb0d2678e2ec1c7165f2148371f272ab23780148ed6498f419bc8104933d14cd155fcf20403c2b66521e604a3d2f4232bb8373f69c2
6
+ metadata.gz: 8c2b374a9400061f3ffd673e418771bb5685ec3d13a631c3839660121d86575be1fbbd1cd99f7ee1a4ddedf850ec72fa984ca084575da587b7a239d2e4654b2e
7
+ data.tar.gz: '0933c0a2f1f58c617c184679ab68c1e90d55f1d9ab796e45336ddbbf49ae2fd73cf1aafbfea6e921254a520c8be3e5f0f380cfbdacd694ba2de6c5f8e4f5a074'
@@ -7,28 +7,28 @@ Layout/LineLength:
7
7
  Max: 175
8
8
 
9
9
  Metrics/AbcSize:
10
- Max: 82
10
+ Max: 87
11
11
 
12
12
  Metrics/BlockLength:
13
- Max: 160
13
+ Max: 188
14
14
 
15
15
  Metrics/BlockNesting:
16
16
  Max: 4
17
17
 
18
18
  Metrics/ClassLength:
19
- Max: 275
19
+ Max: 285
20
20
 
21
21
  Metrics/CyclomaticComplexity:
22
- Max: 20
22
+ Max: 21
23
23
 
24
24
  Metrics/MethodLength:
25
- Max: 65
25
+ Max: 68
26
26
 
27
27
  Metrics/ParameterLists:
28
- Max: 14
28
+ Max: 18
29
29
 
30
30
  Metrics/PerceivedComplexity:
31
- Max: 23
31
+ Max: 24
32
32
 
33
33
  # We use `dc` as a parameter in many methods
34
34
  Naming/MethodParameterName:
@@ -1,13 +1,13 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.4.9
4
- - 2.5.7
5
- - 2.6.5
6
- - 2.7.0
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.7
10
+ rvm: 2.5.8
11
11
  script: echo "Publishing consul-templaterb on rubygems.org ..."
12
12
  deploy:
13
13
  provider: rubygems
@@ -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
- -M, --debug-memory-usage Display messages when RAM grows
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 (EXPERIMENTAL)
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
@@ -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
@@ -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('-M', '--debug-memory-usage', 'Display messages when RAM grows') do
199
- consul_engine.debug_memory = true
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].reload if modified
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
- @programs[cmd].process_status
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
- @endp_manager.create_if_missing(url, {}) do
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, max_consecutive_errors_on_endpoint: @max_consecutive_errors_on_endpoint, agent: nil)
386
- fqdn = path.dup
387
- query_params.each_pair do |k, v|
388
- fqdn = "#{agent}#{fqdn}&#{k}=#{v}"
389
- end
390
- tpl = @endpoints[fqdn]
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[fqdn] = tpl
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})
@@ -1,5 +1,5 @@
1
1
  module Consul
2
2
  module Async
3
- VERSION = '1.26.2'.freeze
3
+ VERSION = '1.28.0'.freeze
4
4
  end
5
5
  end
@@ -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
+ %>
@@ -15,6 +15,10 @@
15
15
  content: '⚠ ';
16
16
  }
17
17
 
18
+ .btn-outline-success a:hover, .btn-outline-warning a:hover, .btn-outline-danger a:hover{
19
+ color: #fff;
20
+ }
21
+
18
22
  #service-wrapper, #instances-wrapper, #keys-wrapper {
19
23
  overflow-y: scroll;
20
24
  border-top-left-radius: 0px;
@@ -1,18 +1,5 @@
1
- // Utilities
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
- const data_date = await httpResponse.headers.get('X-Consul-Snapshot-Timestamp');
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 services = document.createElement('div');
221
- services.className = 'instance-services';
222
- services.appendChild(document.createTextNode("Services: "));
223
- services.appendChild(document.createElement('br'));
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
- var service = document.createElement('a');
226
- var serviceName = instanceServices[serviceKey]['Service']['Service'];
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
- service.setAttribute('class', 'btn btn-sm m-1 lookup');
229
- service.setAttribute('target', '_blank');
230
- nodeAddr = instanceServices[serviceKey]['Service']['Address'];
231
- service.setAttribute('href', 'http://' + nodeAddr + ':' + servicePort);
232
- service.classList.add('btn-outline-' + toCSSClass(nodeState(instanceServices[serviceKey]['Checks'])))
233
- service.appendChild(document.createTextNode(serviceName + ':' + servicePort));
234
- services.appendChild(service);
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
- return services;
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.26.2
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-04-15 00:00:00.000000000 Z
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
- rubyforge_project:
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