consul-templaterb 1.26.0 → 1.27.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79f77f92ae3811c48a823724fb4fb242b78fb78713de126cc035de4089a5e607
4
- data.tar.gz: 3aa6c6f9c1aca03006963dd03ab30c3ba9ceabc4ff88c3a0d7fa8470a024b2d2
3
+ metadata.gz: 6c4d19fa22c559f4a7960529dd3960c1c741f631b1cf0b51f5d10155b2b8a131
4
+ data.tar.gz: 926930e64938a40c2a2653abf9a84f0c86057201646a2f8e02fed06ed51927b8
5
5
  SHA512:
6
- metadata.gz: ed5763f1c109d678a867dddbe77a2b4e8d0b9adde1663f80e9bb6db2812c104f84edcd9f5c929d8e1f4763e9b4fa3af138da87c58af1285d6f1b0c6f5924760d
7
- data.tar.gz: af7a53d991a486b4050632576b36c2cb1fe5e899bee75ec73a2e6bd76bb18e350913e5703b69ee8a05aa51b2d64a64a60b8c17dcc1e071b8cac3544331de0600
6
+ metadata.gz: 5126d79bcbd0d469bcb7ec5d214c979990056c3c11e1547d4819849f3fcd7fddd1534354f565722a52dbb09ba26c63dd4553f40282fcafaccd7be6a2a1d9442f
7
+ data.tar.gz: 7d6345911c69a8c0622f0b88343968ff951d8243db78d41b8cfad74e26ad5c87a39ae02e3bb24d4cf1615fe329fc53642f81aaf76591d1f5be4098c576baea96
@@ -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: 182
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,16 +2,54 @@
2
2
 
3
3
  ## (UNRELEASED)
4
4
 
5
+ ## 1.27.1 (July 28 2020)
6
+
7
+ BUGIX:
8
+
9
+ * Fix collision in JSON queries when using payload in requests #68
10
+
11
+ ## 1.27.0 (June 5, 2020)
12
+
13
+ NEW FEATURES:
14
+
15
+ * For Consul 1.7+, now support `checks_in_state(check_state, dc: nil, [agent: consul_agent_address])`,
16
+ fixes feature [#65](https://github.com/criteo/consul-templaterb/issues/65)
17
+ * New options to support/disable TLS validation thanks to [@jeromegn](https://github.com/jeromegn)
18
+ [#66](https://github.com/criteo/consul-templaterb/pull/66)
19
+
20
+ ## 1.26.3 (April 15, 2020)
21
+
22
+ BUGFIX:
23
+
24
+ * Removed all Criteo specific decorators from Consul-UI
25
+
26
+ ## 1.26.2 (April 15, 2020)
27
+
28
+ BUGFIX:
29
+
30
+ * Fixed broken Dockerfile (was missing the new `decorator.js.erb` file). Fixes #61 (Thanks to @ simongareste)
31
+
5
32
  NEW FEATURES:
6
33
 
34
+ * Added `consul_members_count` metric in [samples/metrics.erb](samples/metrics.erb)
35
+
36
+ ## 1.26.1 (March 27, 2020)
37
+
38
+ BUGFIX:
39
+
40
+ * Using `agent: http://vault_or_consul_agent:port>` was not properly taken into account in some endpoints
41
+
7
42
  ## 1.26.0 (March 5, 2020)
8
43
 
44
+ NEW FEATURES:
45
+
9
46
  * Using `agent: http://vault_or_consul_agent:port>` on most methods will now override the agent
10
47
  used to perform Consul queries. It might be useful for very large clusters or large WAN federations,
11
48
  because you can perform some requests on some agents, and some others on other agenrs. Might
12
49
  also be useful to federate data from preprod/prod for instance.
13
- See [samples/all_services_multi_agents.txt.erb](samples/all_services_multi_agents.txt.erb) for an
14
- example.
50
+ * Added agent attribute for all methods in documentation
51
+ * Added [samples/all_services_multi_agents.txt.erb](samples/all_services_multi_agents.txt.erb) as an
52
+ example of new feature.
15
53
 
16
54
  ## 1.25.2 (February 29, 2020)
17
55
 
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 (EXPERIMENTAL)
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
@@ -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
@@ -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
@@ -120,4 +120,5 @@ If you don’t want to bother configuring and tuning it, you can try it very qui
120
120
  * [Mixing Observability with Service Discovery](https://medium.com/criteo-labs/mixing-observability-with-service-discovery-2bb8909e8530)
121
121
 
122
122
  Pierre Souchay, 2020-03-03
123
- Also published on https://medium.com/criteo-labs/template-based-discovery-with-consul-templaterb-8ff88434c457
123
+
124
+ Also published on https://medium.com/criteo-labs/template-based-discovery-with-consul-templaterb-8ff88434c457
@@ -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
@@ -53,7 +54,7 @@ module Consul
53
54
  query_params = {}
54
55
  query_params[:dc] = dc if dc
55
56
  @endp_manager.create_if_missing(path, query_params, agent: agent) do
56
- ConsulTemplateNodes.new(ConsulEndpoint.new(@endp_manager.consul_conf, path, true, query_params, '[]', agent: agent))
57
+ ConsulTemplateNodes.new(ConsulEndpoint.new(@endp_manager.consul_conf, path, true, query_params, '[]', agent))
57
58
  end
58
59
  end
59
60
 
@@ -63,7 +64,7 @@ module Consul
63
64
  query_params = {}
64
65
  query_params[:dc] = dc if dc
65
66
  @endp_manager.create_if_missing(path, query_params, agent: agent) do
66
- ConsulTemplateNodes.new(ConsulEndpoint.new(@endp_manager.consul_conf, path, true, query_params, '[]', agent: agent))
67
+ ConsulTemplateNodes.new(ConsulEndpoint.new(@endp_manager.consul_conf, path, true, query_params, '[]', agent))
67
68
  end
68
69
  end
69
70
 
@@ -136,7 +137,7 @@ module Consul
136
137
  query_params[:dc] = dc if dc
137
138
  query_params[:passing] = passing if passing
138
139
  query_params[:tag] = tag if tag
139
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateService.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
140
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateService.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
140
141
  end
141
142
 
142
143
  # https://www.consul.io/api/health.html#list-checks-for-service
@@ -147,7 +148,7 @@ module Consul
147
148
  query_params = {}
148
149
  query_params[:dc] = dc if dc
149
150
  query_params[:passing] = passing if passing
150
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
151
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
151
152
  end
152
153
 
153
154
  # https://www.consul.io/api/health.html#list-checks-for-node
@@ -158,7 +159,19 @@ module Consul
158
159
  query_params = {}
159
160
  query_params[:dc] = dc if dc
160
161
  query_params[:passing] = passing if passing
161
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
162
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateChecks.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
163
+ end
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)) }
162
175
  end
163
176
 
164
177
  # https://www.consul.io/api/catalog.html#list-nodes
@@ -166,7 +179,7 @@ module Consul
166
179
  path = '/v1/catalog/nodes'
167
180
  query_params = {}
168
181
  query_params[:dc] = dc if dc
169
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateNodes.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
182
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateNodes.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
170
183
  end
171
184
 
172
185
  # https://www.consul.io/api/catalog.html#list-services-for-node
@@ -174,7 +187,7 @@ module Consul
174
187
  path = "/v1/catalog/node/#{name_or_id}"
175
188
  query_params = {}
176
189
  query_params[:dc] = dc if dc
177
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateNodes.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '{}')) }
190
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateNodes.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '{}', agent)) }
178
191
  end
179
192
 
180
193
  # https://www.consul.io/api/agent.html#read-configuration
@@ -182,7 +195,7 @@ module Consul
182
195
  path = '/v1/agent/self'
183
196
  query_params = {}
184
197
  default_value = '{"Config":{}, "Coord":{}, "Member":{}, "Meta":{}, "Stats":{}}'
185
- create_if_missing(path, query_params, agent: agent) { ConsulAgentSelf.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value)) }
198
+ create_if_missing(path, query_params, agent: agent) { ConsulAgentSelf.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value, agent)) }
186
199
  end
187
200
 
188
201
  # https://www.consul.io/api/agent.html#view-metrics
@@ -190,7 +203,7 @@ module Consul
190
203
  path = '/v1/agent/metrics'
191
204
  query_params = {}
192
205
  default_value = '{"Gauges":[], "Points":[], "Member":{}, "Counters":[], "Samples":{}}'
193
- create_if_missing(path, query_params, agent: agent) { ConsulAgentMetrics.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value)) }
206
+ create_if_missing(path, query_params, agent: agent) { ConsulAgentMetrics.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value, agent)) }
194
207
  end
195
208
 
196
209
  # https://www.consul.io/api/agent.html#list-members
@@ -199,7 +212,7 @@ module Consul
199
212
  query_params = {}
200
213
  query_params['wan'] = true if wan
201
214
  default_value = '[]'
202
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateMembers.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value)) }
215
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateMembers.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value, agent)) }
203
216
  end
204
217
 
205
218
  # Return a param of template
@@ -222,14 +235,14 @@ module Consul
222
235
  query_params[:dc] = dc if dc
223
236
  # Tag filtering is performed on client side
224
237
  query_params[:tag] = tag if tag
225
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateServices.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '{}')) }
238
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateServices.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '{}', agent)) }
226
239
  end
227
240
 
228
241
  # https://www.consul.io/api/catalog.html#list-datacenters
229
242
  def datacenters(agent: nil)
230
243
  path = '/v1/catalog/datacenters'
231
244
  query_params = {}
232
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateDatacenters.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]')) }
245
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateDatacenters.new(ConsulEndpoint.new(consul_conf, path, true, query_params, '[]', agent)) }
233
246
  end
234
247
 
235
248
  # https://www.consul.io/api/kv.html#read-key
@@ -240,7 +253,7 @@ module Consul
240
253
  query_params[:recurse] = recurse if recurse
241
254
  query_params[:keys] = keys if keys
242
255
  default_value = '[]'
243
- create_if_missing(path, query_params, agent: agent) { ConsulTemplateKV.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value), name) }
256
+ create_if_missing(path, query_params, agent: agent) { ConsulTemplateKV.new(ConsulEndpoint.new(consul_conf, path, true, query_params, default_value, agent), name) }
244
257
  end
245
258
 
246
259
  def secrets(path = '', agent: nil)
@@ -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
@@ -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})
@@ -1,5 +1,5 @@
1
1
  module Consul
2
2
  module Async
3
- VERSION = '1.26.0'.freeze
3
+ VERSION = '1.27.1'.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
+ %>
@@ -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
- // 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
+ }
@@ -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,12 @@
1
+ <%
2
+ r = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,62}[a-zA-Z0-9])?$/
3
+ invalid_services = {}
4
+ services.each do |servive_name, tags|
5
+ errors = []
6
+ errors << "Invalid service name #{servive_name}" unless r.match(servive_name)
7
+ tags.each do |tag|
8
+ errors << "Invalid tag #{tag}" unless r.match(tag)
9
+ end
10
+ invalid_services[servive_name] = errors unless errors.empty?
11
+ end
12
+ %><%= JSON.pretty_generate({"errors": invalid_services.size, "details": invalid_services}) %>
@@ -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
+ %>
@@ -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.26.0
4
+ version: 1.27.1
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-03-05 00:00:00.000000000 Z
11
+ date: 2020-07-28 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,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
234
+ - samples/find_all_invalid_dns_labels.json.erb
235
+ - samples/find_nodes_in_catalog_but_not_in_members.json.erb
232
236
  - samples/ha_proxy.cfg.erb
233
237
  - samples/haproxy_dns.cfg.erb
234
238
  - samples/hosts.erb
@@ -238,6 +242,7 @@ files:
238
242
  - samples/members.json.erb
239
243
  - samples/metrics.erb
240
244
  - samples/prometheus_consul_coordinates.erb
245
+ - samples/prometheus_datacenter_coordinates.erb
241
246
  - samples/render_template_from_kv.erb
242
247
  - samples/sample_keys.html.erb
243
248
  - samples/service_checks_metrics.erb
@@ -268,8 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
273
  - !ruby/object:Gem::Version
269
274
  version: '0'
270
275
  requirements: []
271
- rubyforge_project:
272
- rubygems_version: 2.7.7
276
+ rubygems_version: 3.0.8
273
277
  signing_key:
274
278
  specification_version: 4
275
279
  summary: Implementation of Consul template using Ruby and .erb templating language