consul-templaterb 1.21.7 → 1.21.8

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: e96073c3de0da295ed12521d3af5df5192f2d28e7d9cdaa619a37d061002bd38
4
- data.tar.gz: 282d095657af92cce7b11e1b0b597cd004e53052d6f8fdff8a97028eaf062bd8
3
+ metadata.gz: 74f293ea13d55d0199e95f0aecb01d30293b52f411e7261328c0a90adbfbd053
4
+ data.tar.gz: 310fc6106203eb69db6cc2128e9abdac3c50db3449d952ad0dadba7e3d5501ff
5
5
  SHA512:
6
- metadata.gz: 44554f9816067e6f0dd52d8924b70f97a586791ee16f847c58c6292f9d43b60e4bb08274a956b9e3f21b1c2a721b24bc30cffd42a2322025fe4f77be3ca25d37
7
- data.tar.gz: 5f9bd0348e1ee7174d4692c15971a2a515912322e418b822c30eba89f80312f5d9d514d241cf49d91fa92a8a1e195923c036011f1ebae0d75118c9b5b8b58e1e
6
+ metadata.gz: 5c38462f4d2bff46c5d745ebaf893bf8cae04906c5b416ba6a9574cf570b31fdb5afe612a2991c966eef921ba147c1fee46fba7bbec3cde40bcffb49b39dde47
7
+ data.tar.gz: e263ee86afacbf6b2b32b02d7b89dbf8d05d019b24267c52b446719f9eb301cf9ae53d9d017a879f39ef1a5c074e6313062e16c4adb25f53e7f3c49c1260f575
@@ -2,7 +2,11 @@
2
2
 
3
3
  ## (UNRELEASED)
4
4
 
5
- ## 1.21.6 (December 16, 2019)
5
+ ## 1.21.8 (January 2, 2020)
6
+
7
+ * Escape properly metadata containing double quotes in prometheus exporter
8
+
9
+ ## 1.21.7 (December 16, 2019)
6
10
 
7
11
  * Fixed warning color from critical to warning on consul-ui timeline
8
12
 
@@ -1,5 +1,5 @@
1
1
  module Consul
2
2
  module Async
3
- VERSION = '1.21.7'.freeze
3
+ VERSION = '1.21.8'.freeze
4
4
  end
5
5
  end
@@ -1,8 +1,18 @@
1
- // In this file, you can tune how data is displayed,
2
- // For instance create links
3
-
4
1
  // Utilities
5
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/'
6
16
 
7
17
  function url_decorator(key, value) {
8
18
  var e = document.createElement('a');
@@ -11,10 +21,66 @@ function url_decorator(key, value) {
11
21
  return e;
12
22
  }
13
23
 
24
+ function usefullLinksGenerator(instance, serviceName, node_meta_info) {
25
+ var top = document.createElement('div');
26
+ top.className = 'instance-links';
27
+
28
+ 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
+ ];
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
+ var first = true;
51
+ for (let usefullLink of usefullLinks) {
52
+ link = document.createElement('a');
53
+ link.href = usefullLink.href;
54
+ if (typeof usefullLink.iconClassName !== 'undefined') {
55
+ icon = document.createElement('i');
56
+ icon.className = usefullLink.iconClassName;
57
+ link.appendChild(icon);
58
+ link.appendChild(document.createTextNode("\u00A0"));
59
+ }
60
+ if (!first) {
61
+ top.appendChild(document.createTextNode(' | '));
62
+ } else {
63
+ first = false;
64
+ }
65
+ link.appendChild(document.createTextNode(usefullLink.title));
66
+ top.appendChild(link);
67
+ }
68
+
69
+ return top;
70
+ }
71
+
14
72
  /**
15
73
  * serviceInstanceDecorator is called to decorate an instance.
16
74
  */
17
75
  function serviceInstanceDecorator(instance, element, serviceName, node_meta_info) {
76
+ for (let child of element.children) {
77
+ if (child.className && child.className.includes("instance-meta")) {
78
+ var instanceMetaChild = child;
79
+ }
80
+ }
81
+
82
+ element.insertBefore(usefullLinksGenerator(instance, serviceName, node_meta_info), instanceMetaChild);
83
+ element.insertBefore(document.createElement("hr"), instanceMetaChild);
18
84
  return element;
19
85
  }
20
86
 
@@ -26,20 +92,222 @@ function serviceMetaDecorator(instance, key, value, serviceName, node_meta_info)
26
92
  if (httpRegexp.test(value)) {
27
93
  return url_decorator(key, value);
28
94
  } else {
29
- return document.createTextNode(value);
95
+ return service_meta_semantics_decorator(instance, key, value, serviceName);
30
96
  }
31
97
  }
32
98
 
99
+ function build_link(href, value) {
100
+ var e = document.createElement('a');
101
+ e.setAttribute('href', href);
102
+ e.appendChild(document.createTextNode(value));
103
+ return e;
104
+ }
105
+
106
+ function default_decorator(instance, key, value, serviceName) {
107
+ return document.createTextNode(value);
108
+ }
109
+
110
+ function groups_decorator(instance, key, value, serviceName) {
111
+ var values = value.split(',');
112
+ var span = document.createElement('span');
113
+ var first = true;
114
+ for (var i in values) {
115
+ if (!first) {
116
+ span.appendChild(document.createTextNode(', '));
117
+ } else {
118
+ first = false;
119
+ }
120
+ var grp = values[i];
121
+ if (grp.indexOf('.') != -1) {
122
+ var x = document.createElement('span');
123
+ x.setAttribute('class', 'badge badge-warning');
124
+ x.appendChild(document.createTextNode(grp));
125
+ span.appendChild(x);
126
+ } else {
127
+ var a = document.createElement('a');
128
+ a.target = 'asapi';
129
+ a.appendChild(document.createTextNode(grp));
130
+ a.href = asapi_url + encodeURIComponent(grp);
131
+ span.appendChild(a);
132
+ }
133
+ }
134
+ return span;
135
+ }
136
+
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
+ function decorateIsoDate(value, formated) {
151
+ const parsed = Date.parse(formated);
152
+ if (isNaN(parsed)) {
153
+ return document.createTextNode(value);
154
+ }
155
+ const d = new Date(parsed);
156
+ console.log(d);
157
+ const e = document.createElement('time');
158
+ e.setAttribute('datetime', formated);
159
+ e.setAttribute('title', value);
160
+ e.appendChild(document.createTextNode(d.toLocaleString()));
161
+ return e;
162
+ }
163
+
164
+ // This is the list of function called
165
+ // When a service meta is found
166
+ var registered_decorators = {
167
+ alert_availability_slack_channel: slack_channel,
168
+ gerrit_repository: function(instance, key, value, serviceName) {
169
+ return build_link('https://review.crto.in/#/q/' + value, value);
170
+ },
171
+ version: function(instance, key, value, serviceName) {
172
+ var asInt = parseInt(value);
173
+ if (asInt < 10000) {
174
+ return document.createTextNode(value);
175
+ }
176
+ if (instance.sMeta['CRITEO_APP_POOL'] != null) {
177
+ return build_link("https://devtools.crto.in/log.html?moab=cs&im=nb-to&range=100%2C" + asInt, value);
178
+ } else {
179
+ var tUrl = "https://devtools.crto.in/log.html?moab=j&im=nb-to&range=100%2C" + asInt;
180
+ if (instance.sMeta['jvm_artifact'] != null) {
181
+ tUrl += '&with-dependencies=true&artifacts=' + encodeURIComponent(instance.sMeta['jvm_artifact']);
182
+ }
183
+ return build_link(tUrl, value);
184
+ }
185
+ },
186
+ MESOS_TERM_DEBUG_GRANTED_TO: groups_decorator,
187
+ OWNERS: groups_decorator,
188
+ marathon_app_id: function(instance, key, value, serviceName) {
189
+ var app_name = value;
190
+ if (app_name[0] != '/') {
191
+ app_name = '/' + app_name;
192
+ }
193
+ if (instance.sMeta && instance.sMeta['marathon_ui']) {
194
+ return build_link(instance.sMeta['marathon_ui'] + '/#/apps/' + encodeURIComponent(app_name), value);
195
+ } else {
196
+ // non decorated value
197
+ return document.createTextNode(value);
198
+ }
199
+ },
200
+ marathon_app_version: function(instance, key, value, serviceName) {
201
+ return decorateIsoDate(value, value);
202
+ },
203
+ slack_channel: slack_channel,
204
+ start: function(instance, key, value, serviceName) {
205
+ const reg = start_regexp.exec(value);
206
+ if (reg != null) {
207
+ var formated = reg[1] + '-' + reg[2] + '-' + reg[3] + 'T' + reg[4] + ':' + reg[5] + ':' + reg[6] + 'Z';
208
+ return decorateIsoDate(value, formated);
209
+ } else {
210
+ return document.createTextNode(value);
211
+ }
212
+ },
213
+ swagger_key: function(instance, key, value, serviceName) {
214
+ return build_link(swagger_url + encodeURIComponent(value), value);
215
+ },
216
+ }
217
+
218
+ function service_meta_semantics_decorator(instance, key, value, serviceName) {
219
+ var fun = registered_decorators[key];
220
+ if (fun == null) {
221
+ fun = default_decorator;
222
+ }
223
+ return fun(instance, key, value);
224
+ }
225
+
33
226
  /**
34
227
  * navBarDecorator is called to modify to modify naviguation bar of all UI pages.
35
228
  * it receives the nav bar div
36
229
  * it does not have to return anything.
37
230
  */
38
- function navBarDecorator(navbar) { }
231
+ function navBarDecorator(navbar) {
232
+ if (typeof consulManager === 'undefined') {
233
+ // Timepicker is not supported on this page
234
+ return;
235
+ }
236
+ var timepicker_container = document.createElement('div');
237
+ timepicker_container.innerHTML = `
238
+ <div class="row">
239
+ <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">
240
+ Pick a date to see data from the past
241
+ </button>
242
+ <div class="col-sm-14">
243
+ <div class="form-group">
244
+ <div class="input-group date" id="datetimepicker1" data-target-input="nearest">
245
+ <input type="text" class="form-control datetimepicker-input" data-target="#datetimepicker1"/>
246
+ <div class="input-group-append" data-target="#datetimepicker1" data-toggle="datetimepicker">
247
+ <div class="input-group-text"><i class="fa fa-calendar"></i></div>
248
+ </div>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ `;
254
+
255
+ navbar.appendChild(timepicker_container);
256
+ var script= document.createElement('script');
257
+ script.type='text/javascript';
258
+ // TODO(g.seux): extract code to another file and set "source" on script element
259
+ script.innerHTML = `
260
+ $('#datetimepicker1').datetimepicker({
261
+ format: 'DD/MM/YYYY HH:mm:ss Z', // default format does not allow to select seconds
262
+ sideBySide: true, // display date+time on the same widget
263
+ useCurrent: true // by default, select current date
264
+ });
265
+ $("#datetimepicker1").on("change.datetimepicker", function (e) {
266
+ console.log("Will fetch data from date " + e.date);
267
+ console.log("will clean existing data");
268
+ consulManager.clean().then(function(result) {
269
+ switch(consulManager.constructor.name) {
270
+ case "ConsulServiceManager":
271
+ backup_type = 'consul_services';
272
+ break;
273
+ case "ConsulKeysManager":
274
+ backup_type = 'consul_keys'
275
+ break;
276
+ case "ConsulNodesManager":
277
+ backup_type = 'consul_nodes'
278
+ break;
279
+ default:
280
+ console.log("Unknown " + consulManager.constructor.name + " type");
281
+ }
282
+ if (e.date) {
283
+ console.log("Will replace data by closest snapshot to " + e.date);
284
+ var target_url = "https://consul-info-timeline-history.<%= ENV['CRITEO_DC'] %>.<%= ENV['CRITEO_ENV']%>.crto.in/backup/" + backup_type + "/" + e.date / 1000;
285
+ } else {
286
+ console.log("Will restore to local version");
287
+ var target_url = defaultConsulManager.resourceURL;
288
+ }
289
+ if (typeof(defaultConsulManager) == 'undefined') {
290
+ // store first manager to be able to restore it
291
+ defaultConsulManager = consulManager
292
+ }
293
+ consulManager = new consulManager.constructor(target_url);
294
+ });
295
+ });
296
+ `;
297
+ navbar.appendChild(script);
298
+ }
39
299
 
40
300
 
41
301
  /**
42
302
  * fetchedResponseDecorator is called with http response when a resource is fetched by any instance of ConsulUIManager
43
303
  * it does not have to return anything.
44
304
  */
45
- async function fetchedResponseDecorator(httpResponse) { }
305
+ async function fetchedResponseDecorator(httpResponse) {
306
+ const data_date = await httpResponse.headers.get('X-Consul-Snapshot-Timestamp');
307
+ current_date_display = $('#currently-displayed-data-date');
308
+ if (data_date > 0) {
309
+ current_date_display.html("Data is a snapshot from: " + moment.unix(data_date).format('DD/MM/YYYY HH:mm:ss Z'));
310
+ } else {
311
+ current_date_display.html("Pick a date to see data from the past");
312
+ }
313
+ }
@@ -91,13 +91,17 @@ end
91
91
  # TYPE consul_service_changes_total counter
92
92
 
93
93
  <%
94
+ def escape_meta(val)
95
+ val.gsub('"', '\"')
96
+ end
97
+
94
98
  json_backends = {}
95
99
  now = Time.now.utc
96
100
  backends.each_pair do |k, service_info|
97
101
  service_name = service_info[:service_name]
98
102
  meta_string = ""
99
103
  service_info[:metas].each_pair do |k,v|
100
- meta_string+=",#{k}=\"#{v}\""
104
+ meta_string+=",#{k}=\"#{escape_meta(v)}\""
101
105
  end
102
106
  service_info[:state].each_pair do |state_name, state_count|
103
107
  %>consul_service_count{service="<%= service_name %>",state="<%= state_name %>"<%= meta_string %>} <%= state_count %>
@@ -107,15 +111,15 @@ end
107
111
 
108
112
  # Global statistics
109
113
  all_stats.each_pair do |service_name, current_stats|
110
- %>consul_service_stats_requests_total{service="<%= service_name %>",type="success"} <%= current_stats.successes %>
114
+ %>consul_service_stats_requests_total{service="<%= escape_meta(service_name) %>",type="success"} <%= current_stats.successes %>
111
115
  <%
112
116
  if current_stats.errors > 0
113
- %>consul_service_stats_requests_total{service="<%= service_name %>",type="errors"} <%= current_stats.errors %>
117
+ %>consul_service_stats_requests_total{service="<%= escape_meta(service_name) %>",type="errors"} <%= current_stats.errors %>
114
118
  <%
115
119
  end
116
- %>consul_service_stats_requests_bytes{service="<%= service_name %>"} <%= current_stats.body_bytes %>
117
- consul_service_stats_requests_bytes_per_sec{service="<%= service_name %>"} <%= current_stats.bytes_per_sec(now) %>
118
- consul_service_changes_total{service="<%= service_name %>"} <%= current_stats.changes %>
120
+ %>consul_service_stats_requests_bytes{service="<%= escape_meta(service_name) %>"} <%= current_stats.body_bytes %>
121
+ consul_service_stats_requests_bytes_per_sec{service="<%= escape_meta(service_name) %>"} <%= current_stats.bytes_per_sec(now) %>
122
+ consul_service_changes_total{service="<%= escape_meta(service_name) %>"} <%= current_stats.changes %>
119
123
 
120
124
  <%
121
125
  end
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.21.7
4
+ version: 1.21.8
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: 2019-12-16 00:00:00.000000000 Z
11
+ date: 2020-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request