consul-templaterb 1.21.7 → 1.21.8

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: 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