consul-templaterb 1.8.2 → 1.8.3

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: 6d652b0259f34bd70784ebdfbfe18e042bb48bdd03af5f5d920a71b94bb1281d
4
- data.tar.gz: 00116db5cf7b2f11516abb912aab335c2608ec01fdf9ba527f11deb9bc861755
3
+ metadata.gz: 68013fd942d003c33f69526b5061fa9f6ce149332bf97db49978e2a2bc9628e0
4
+ data.tar.gz: d38f04e18ed0c9a7a051804d8cdae8826140ee6161fa17ce400ba5943c8465b5
5
5
  SHA512:
6
- metadata.gz: c53f3a2704b5b52b3febb4c4844c36dae660b163d1de8298acde2f88c0cb9b9e65bc202d35c160d0747b3624bfa1355c0e014ef58e2d31673a5b40d17b0d8847
7
- data.tar.gz: bc16ad7b30485b403c19d01251c87ffa66d17b937b09affdf2c74470455283d5121b95909524ec703d29239efe97b626f7e0c70bb34090a04bab69ad224a176c
6
+ metadata.gz: 30f1983821cdd6300dd7f6c2610c9936e70d7f110dc4a83afa36b75256d652bdcf59dc20f378d4e3918f8473934e5c01e8ce17f4724d72e96a6ac0c0c77438b9
7
+ data.tar.gz: 4c0695f4f2a2f0e0ec4695394e6845a8a1880e7745d73b70b400f2cf2039f98f5005f82bc0e1b6bc964909efd81a4b140c6104e44503567b12565fb804cb89b5
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## (UNRELEASED)
4
4
 
5
+ ## 1.8.3 (December 18, 2018)
6
+
7
+ OPTIMIZATIONS:
8
+
9
+ * Consul timeline now autorefresh itself
10
+ * large performance improvement in Consul
11
+
5
12
  ## 1.8.2 (December 18, 2018)
6
13
 
7
14
  NEW FEATURES:
@@ -1,5 +1,5 @@
1
1
  module Consul
2
2
  module Async
3
- VERSION = '1.8.2'.freeze
3
+ VERSION = '1.8.3'.freeze
4
4
  end
5
5
  end
@@ -6,23 +6,21 @@
6
6
  <div id="filter-menu" class="col-2 col-m-3 px-4 pt-4">
7
7
  <div class="form-group">
8
8
  <div class="input-group">
9
- <input id="service-filter" type="text" placeholder="filter instances" class="form-control" />
10
- <div class="input-group-append">
11
- <span class="input-group-text" id="service-counter"></span>
12
- </div>
9
+ <input id="service-filter" type="search" placeholder="filter services" class="form-control" />
13
10
  </div>
14
11
  </div>
15
12
  <div id="service-wrapper" >
16
13
  <ul id="service-list" class="list-group">
17
- <li onfocus="serviceTimeline.selectService(this)" onclick="serviceTimeline.selectService(this)" value="" class="serviceListItem list-group-item list-group-item-actionn active" id="anyService"><div class="statuses float-right"><span class="lookup badge badge-pill badge-dark">1000</span></div><div class="service-name">All</div></li>
14
+ <li onfocus="serviceTimeline.selectService(this)" onclick="serviceTimeline.selectService(this)" value="" class="serviceListItem list-group-item list-group-item-actionn" id="anyService"><div class="statuses float-right"><span id="allServicesCount" class="lookup badge badge-pill badge-secondary">loading&hellip;</span></div><div class="service-name">All</div></li>
18
15
  </ul>
19
16
  </div>
20
17
  </div>
21
18
  <div class="col-10 col-m-9">
19
+ <div id="autorefresh"><input id="autorefresh-check" type="checkbox" checked><label for="autorefresh-check">Autorefresh</label></div>
22
20
  <h2 class="text-center" id="service-title"></h2>
23
21
  <div class="row mb-2">
24
22
  <div class="input-group float-left col-12">
25
- <input id="instance-filter" type="text" placeholder="filter nodes by name or tags" class="form-control" />
23
+ <input id="instance-filter" type="search" placeholder="filter events" class="form-control" />
26
24
  </div>
27
25
  </div>
28
26
  <div id="instances-wrapper">
@@ -34,8 +32,8 @@
34
32
  <th scope="col" class="serviceCol">Service</th>
35
33
  <th scope="col">Instance</th>
36
34
  <th scope="col">Check State</th>
37
- <th scope="col">Service&nbsp;Status&nbsp;Change</th>
38
- <th colspan="2" scope="col">Service&nbsp;Instances</th>
35
+ <th scope="col">Service&nbsp;Status</th>
36
+ <th id="all-instances-header" colspan="2" scope="col">Instances</th>
39
37
  </tr>
40
38
  </thead>
41
39
  <tbody>
@@ -17,6 +17,39 @@
17
17
  text-overflow: ellipsis;
18
18
  overflow: hidden;
19
19
  }
20
+ .checkTransition {
21
+ float: left;
22
+ }
23
+ .checkName {
24
+ padding-left: 5px;
25
+ overflow: hidden;
26
+ white-space: nowrap;
27
+ text-overflow: ellipsis;
28
+ }
29
+ td.serviceName {
30
+ max-width: 15%;
31
+ overflow: hidden;
32
+ text-overflow: ellipsis;
33
+ }
34
+ #autorefresh{
35
+ float: right;
36
+ }
37
+ td.instance {
38
+ max-width: 15em;
39
+ overflow: hidden;
40
+ text-overflow: ellipsis;
41
+ }
42
+ #all-instances-header {
43
+ width: 12em;
44
+ text-align: right;
45
+ padding-right: 1em;
46
+ }
47
+ td.ts {
48
+ width: 9em;
49
+ }
50
+ td.serviceName {
51
+ max-width: 12em;
52
+ }
20
53
 
21
54
  #service-list .favorite {
22
55
  width: 20px;
@@ -60,7 +93,13 @@
60
93
  border-left: 0px;
61
94
  border-right: 0px;
62
95
  }
63
-
96
+ .service-status {
97
+ width: 10em;
98
+ }
99
+ .all-instances {
100
+ width: 14em;
101
+ text-align: right;
102
+ }
64
103
  #node-statuses span {
65
104
  font-size: 1rem;
66
105
  transition: background-color .16s linear;
@@ -2,7 +2,7 @@
2
2
  class ServiceTimeline {
3
3
  constructor(ressourceURL, refresh) {
4
4
  this.ressourceURL = ressourceURL;
5
- this.fetchRessource();
5
+ this.fetchRessource(true);
6
6
  this.serviceList = $("#service-list");
7
7
  this.serviceFilter = $("#service-filter");
8
8
  this.serviceFilter.keyup(this.filterService);
@@ -12,26 +12,34 @@ class ServiceTimeline {
12
12
  this.refresh = parseInt(refresh);
13
13
  this.filterStatus = null;
14
14
  this.refreshTimeout = null;
15
- this.serviceFilterCounter = $("#service-counter");
16
- this.serviceFilterCount = 0;
15
+ this.reloadData = null;
17
16
  this.services = {}
17
+ this.lastEntryLoaded = null;
18
18
  this.presentServices = {}
19
+ this.currentlyUpdating = false;
19
20
  var sT = this;
20
21
  }
21
22
 
22
- fetchRessource() {
23
- $.ajax({url: this.ressourceURL, cache: false, dataType: "json", sourceObject: this, success: function(result){
24
- serviceTimeline.initRessource(result);
25
- }});
23
+ fetchRessource(firstReload) {
24
+ $.ajax({url: this.ressourceURL, cache: false, dataType: "json", sourceObject: this,
25
+ success: function(result){
26
+ serviceTimeline.initRessource(result, firstReload);
27
+ },
28
+ error: function(err) {
29
+ console.log("Error updating data", err);
30
+ serviceTimeline.currentlyUpdating = false;
31
+ }
32
+ });
26
33
  }
27
34
 
28
- initRessource(data) {
35
+ initRessource(data, firstReload) {
29
36
  this.data = data;
30
- this.reloadTimeline(true);
37
+ this.reloadTimeline(firstReload);
31
38
  }
32
39
 
33
40
  createServiceDefItem(label, serviceName, counter) {
34
41
  var listItem = document.createElement('li');
42
+ listItem.setAttribute('id', 'service-item-filter-' + serviceName);
35
43
  listItem.setAttribute('onfocus','serviceTimeline.selectService(this, true)');
36
44
  listItem.setAttribute('onclick','serviceTimeline.selectService(this, true)');
37
45
  listItem.setAttribute('value', serviceName);
@@ -44,17 +52,25 @@ class ServiceTimeline {
44
52
 
45
53
  var statuses = document.createElement('div');
46
54
  statuses.setAttribute('class','statuses float-right');
47
- statuses.appendChild(this.createBadge(counter, 'dark'));
55
+ statuses.appendChild(this.createBadge(counter, 'dark instanceCounter'));
48
56
  listItem.prepend(statuses);
49
57
  return listItem;
50
58
  }
51
59
 
60
+ reloadDataFromJSON(){
61
+ if (document.getElementById('autorefresh-check').checked) {
62
+ if (serviceTimeline.currentlyUpdating == false) {
63
+ serviceTimeline.currentlyUpdating = true;
64
+ serviceTimeline.fetchRessource(false);
65
+ }
66
+ }
67
+ }
68
+
52
69
  reloadTimeline(firstReload) {
53
70
  if (!this.data) {
54
71
  console.log("No data to display");
72
+ serviceTimeline.currentlyUpdating = false;
55
73
  }
56
- this.serviceList.html('');
57
- this.serviceFilterCount = 0;
58
74
  var servicesPerName = {};
59
75
  var numberOfEvents = this.data.length;
60
76
  for (var i = 0 ; i < numberOfEvents; i++) {
@@ -68,17 +84,22 @@ class ServiceTimeline {
68
84
  }
69
85
  var sorted = Object.keys(servicesPerName).sort();
70
86
  var serviceListItems = this.serviceList[0];
71
- var allServices = this.createServiceDefItem('All', '', numberOfEvents);
72
- allServices.setAttribute('id', 'anyService');
73
- serviceListItems.appendChild(allServices);
87
+ $('#allServicesCount').html(numberOfEvents)
74
88
  this.presentServices = servicesPerName;
75
89
  for (var i = 0 ; i < sorted.length; i++) {
76
90
  var serviceName = sorted[i];
77
91
  var counter = servicesPerName[serviceName];
78
- var listItem = this.createServiceDefItem(serviceName, serviceName, counter);
79
- serviceListItems.appendChild(listItem);
92
+ var existing = $('#service-item-filter-' + serviceName);
93
+ if (existing.length > 0) {
94
+ $('#service-item-filter-' + serviceName+ ' .instanceCounter').html(counter);
95
+ } else {
96
+ var listItem = this.createServiceDefItem(serviceName, serviceName, counter);
97
+ serviceListItems.appendChild(listItem);
98
+ }
99
+
80
100
  }
81
- this.displayEvents();
101
+ this.displayEvents(firstReload);
102
+ serviceTimeline.currentlyUpdating = false;
82
103
  if (firstReload) {
83
104
  var sT = this;
84
105
  setTimeout(function(){
@@ -111,7 +132,10 @@ class ServiceTimeline {
111
132
  if (!found) {
112
133
  sT.selectService($('#anyService', false));
113
134
  }
135
+ setInterval(sT.reloadDataFromJSON, 10000);
114
136
  }, 150);
137
+ } else {
138
+ this.doFilter();
115
139
  }
116
140
  }
117
141
 
@@ -146,8 +170,7 @@ class ServiceTimeline {
146
170
  return span;
147
171
  }
148
172
 
149
- doFilter() {
150
- var filterValue = $('#instance-filter')[0].value;
173
+ performFiltering(filterValue) {
151
174
  this.refreshTimeout = null;
152
175
  var matcher;
153
176
  try {
@@ -199,6 +222,16 @@ class ServiceTimeline {
199
222
  }
200
223
  }
201
224
 
225
+ doFilter() {
226
+ var filterValue = $('#instance-filter')[0].value;
227
+ if (this.refreshTimeout) {
228
+ clearTimeout(this.refreshTimeout);
229
+ }
230
+ this.refreshTimeout = window.setTimeout(function(){
231
+ serviceTimeline.performFiltering(filterValue);
232
+ }, 16);
233
+ }
234
+
202
235
  selectService(source, updateUrl) {
203
236
  $(this.selectedService).removeClass('active');
204
237
  var serviceName = $(source).find(".service-name").html()
@@ -236,7 +269,6 @@ class ServiceTimeline {
236
269
  console.log("Failed to compile regexp for '" + serviceVal + "', using strict lookup due to: " + e);
237
270
  filter = new RegExp(safeReg);
238
271
  }
239
- serviceTimeline.serviceFilterCount = 0;
240
272
  var showProxiesInList = this.showProxiesInList;
241
273
  serviceTimeline.serviceList.children('.serviceListItem').each(function (){
242
274
  var ui = $(this);
@@ -250,17 +282,50 @@ class ServiceTimeline {
250
282
  });
251
283
  }
252
284
 
253
- displayEvents() {
285
+ displayEvents(firstReload) {
254
286
  //$("#service-title").html(service['name']);
255
287
  var tableBody = $('#all-events > tbody');
256
- tableBody.html("");
288
+ var startIndex = 0;
289
+ if (firstReload || this.lastEntryLoaded == null) {
290
+ tableBody.html("");
291
+ } else {
292
+ // We first try to find new entries...
293
+ var o = this.lastEntryLoaded;
294
+ for (var i = 0 ; i < this.data.length; i++) {
295
+ var e = this.data[i];
296
+ if (o.ts == e.ts && o.instance == e.instance) {
297
+ startIndex = i + 1;
298
+ console.log('Resuming at ', startIndex, " with ", e);
299
+ break;
300
+ }
301
+ }
302
+ }
257
303
  var tbody = tableBody[0];
258
304
  var filter = "";
259
- for (var i = 0 ; i < this.data.length; i++) {
305
+ var lastEntryFound = null;
306
+ for (var i = startIndex ; i < this.data.length; i++) {
260
307
  var e = this.data[i];
308
+ lastEntryFound = e;
261
309
  var row = document.createElement('tr');
262
310
  row.setAttribute("class", 'srv-' + e.service);
263
- this.buildCell(row, 'td', 'ts', this.appChild('time', document.createTextNode(e.ts)));
311
+ var timestamp;
312
+ var fullTimestamp;
313
+ try {
314
+ var tsMs = Date.parse(e.ts);
315
+ if (isNaN(tsMs)) {
316
+ timestamp = e.ts;
317
+ fullTimestamp = e.ts;
318
+ } else {
319
+ fullTimestamp = new Date(tsMs);
320
+ timestamp = formatDate(fullTimestamp);
321
+ }
322
+ } catch (err){ console.log("Failed parsing date", e.ts, err);}
323
+ {
324
+ var timeElement = this.appChild('time', document.createTextNode(timestamp));
325
+ timeElement.setAttribute('datetime', fullTimestamp);
326
+ timeElement.setAttribute('title', fullTimestamp);
327
+ this.buildCell(row, 'td', 'ts', timeElement);
328
+ }
264
329
  this.buildCell(row, 'td', 'lookup serviceName serviceCol', document.createTextNode(e.service));
265
330
  var text = e.instance;
266
331
  if (e.instance_info && e.instance_info.node) {
@@ -272,39 +337,38 @@ class ServiceTimeline {
272
337
  var instanceCell = this.buildCell(row, 'td', 'lookup instance', document.createTextNode(text));
273
338
  instanceCell.setAttribute("title", e.instance);
274
339
  {
275
- var checksCell = document.createElement("div")
276
- this.buildCell(row, 'td', 'lookup checks', checksCell);
277
- for (var j = 0; j < e.checks.length; j++) {
278
- var c = e.checks[j];
279
- var statusSpan = document.createElement('div');
280
- statusSpan.setAttribute('class', 'checkTransition');
281
- statusSpan.appendChild(this.createBadge(c['old']));
282
- statusSpan.appendChild(document.createTextNode(''));
283
- var newBadge = this.createBadge(c['new']);
284
- newBadge.setAttribute('title', c['output']);
285
- statusSpan.appendChild(newBadge);
286
- checksCell.appendChild(statusSpan);
287
- var checkName = document.createElement('div');
288
- checkName.setAttribute('class', 'lookup checkName');
289
- checkName.setAttribute('title', c['id']);
290
- checkName.appendChild(document.createTextNode(c['name']));
291
- checksCell.appendChild(checkName);
340
+ var checksCell;
341
+ if (e.checks.length == 0) {
342
+ checksCell = this.createBadge('No check modified', 'primary');
343
+ } else {
344
+ checksCell = document.createElement("div");
345
+ for (var j = 0; j < e.checks.length; j++) {
346
+ var c = e.checks[j];
347
+ var statusSpan = document.createElement('div');
348
+ statusSpan.setAttribute('class', 'checkTransition');
349
+ statusSpan.appendChild(this.createBadge(c['old']));
350
+ statusSpan.appendChild(document.createTextNode('→'));
351
+ var newBadge = this.createBadge(c['new']);
352
+ statusSpan.appendChild(newBadge);
353
+ checksCell.appendChild(statusSpan);
354
+ var checkName = document.createElement('div');
355
+ checkName.setAttribute('class', 'lookup checkName');
356
+ checkName.setAttribute('data-toggle', 'tooltip');
357
+ checkName.setAttribute('title', c['id']+'\n\n' + c.output);
358
+ checkName.appendChild(document.createTextNode(c['name']));
359
+ checksCell.appendChild(checkName);
360
+ }
292
361
  }
362
+ this.buildCell(row, 'td', 'lookup checks', checksCell);
293
363
  }
294
364
  {
295
- var statusSpan = document.createElement('span');
296
- statusSpan.appendChild(this.createBadge(e['old_state']));
297
- statusSpan.appendChild(document.createTextNode(''));
298
- statusSpan.appendChild(this.createBadge(e['new_state']));
299
- this.buildCell(row, 'td', 'status', statusSpan);
365
+ var td = this.buildCell(row, 'td', 'service-status', this.createBadge(e['old_state']));
366
+ td.appendChild(document.createTextNode(''));
367
+ td.appendChild(this.createBadge(e['new_state']));
300
368
  }
301
369
  {
302
- var allInstances = document.createElement('span');
303
370
  var nSuccess = e['stats']['passing'];
304
- if (nSuccess > 0) {
305
- var success = this.createBadge(nSuccess, 'success');
306
- allInstances.appendChild(success);
307
- }
371
+ var allInstances = this.buildCell(row, 'td', 'all-instances', this.createBadge(nSuccess, 'success'));
308
372
  var nWarnings = e['stats']['warning'];
309
373
  if (nWarnings > 0) {
310
374
  var elem = this.createBadge(nWarnings, 'warning');
@@ -325,10 +389,10 @@ class ServiceTimeline {
325
389
  } else if (percent < 50) {
326
390
  clazz = 'warning';
327
391
  }
328
- allInstances.appendChild(this.createBadge(percent + " %", clazz));
329
- row.appendChild(allInstances);
392
+ this.buildCell(row, 'td', 'ipercents', this.createBadge(percent + " %", clazz));
330
393
  }
331
394
  tbody.prepend(row)
332
395
  }
396
+ this.lastEntryLoaded = lastEntryFound;
333
397
  }
334
398
  }
@@ -12,6 +12,15 @@ function buildServiceStatus(service) {
12
12
  return serviceStatus;
13
13
  }
14
14
 
15
+ function padDateUnit(x) {
16
+ return x > 9 ? x : '0' + x;
17
+ }
18
+
19
+ function formatDate(date) {
20
+ return padDateUnit(date.getMonth()+1) + "/" + padDateUnit(date.getDate()) + " " + padDateUnit(date.getHours()) + ':' + padDateUnit(date.getMinutes()) + ':' + padDateUnit(date.getSeconds());
21
+ }
22
+
23
+
15
24
  function nodeState(checks) {
16
25
  status='passing';
17
26
  for (var checkKey in checks) {
@@ -1,13 +1,10 @@
1
1
  <%
2
2
  require 'json'
3
+ services_blacklist = (ENV['EXCLUDE_SERVICES'] || 'consul-agent-http,mesos-slave,mesos-agent-watcher,mesos-exporter-slave').split(',')
3
4
 
4
- @current_time = Time.now.utc
5
+ @current_time = Time.now.utc.iso8601
5
6
  cur_state = services.map do |service_name, _tags|
6
- next if service_name.match?(/^lbl7-/)
7
- next if service_name.match?(/^wmi-/)
8
- next if service_name.match?(/collectd-/)
9
- next if service_name.match?(/-(eu|as|us)$/)
10
- next if service_name.match?(/-admin$/)
7
+ next if services_blacklist.include?(service_name)
11
8
 
12
9
  snodes = service(service_name)
13
10
  cur_stats = {
@@ -79,7 +76,7 @@ def diff(old, new)
79
76
  diff
80
77
  end
81
78
 
82
- @events = RingBuffer.new(max_size: (ENV['CONSUL_TIMELINE_BUFFER'] || 1000).to_i) unless @events
79
+ @events = RingBuffer.new(max_size: (ENV['CONSUL_TIMELINE_BUFFER'] || 10000).to_i) unless @events
83
80
 
84
81
  def log_event(line)
85
82
  puts "#{Time.now.to_i} #{line}" if ENV['DEBUG_TIMELINE']
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: consul-templaterb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 1.8.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - SRE Core Services
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  version: '0'
232
232
  requirements: []
233
233
  rubyforge_project:
234
- rubygems_version: 2.7.7
234
+ rubygems_version: 2.7.8
235
235
  signing_key:
236
236
  specification_version: 4
237
237
  summary: Implementation of Consul template using Ruby and .erb templating language