consul-templaterb 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ <% path = ENV['kv_path'] || ''
2
+ require 'base64'
3
+ require 'json'
4
+ require 'date'
5
+
6
+ data = {}
7
+ kv(path, recurse:true).each do |tuple|
8
+ data[tuple['Key']] = tuple['Value']
9
+ end
10
+ %><%
11
+ json = { kv: data, generated_at: Time.now}
12
+ %><%= JSON.pretty_generate(json) %>
@@ -0,0 +1,64 @@
1
+ <%
2
+ # This template can be configure the following way with environment variables
3
+ # Environment variables to filter services/instances
4
+ # SERVICES_TAG_FILTER: basic tag filter for service (default HTTP)
5
+ # INSTANCE_MUST_TAG: Second level of filtering (optional, default to SERVICES_TAG_FILTER)
6
+ # INSTANCE_EXCLUDE_TAG: Exclude instances having the given tag (default: canary)
7
+ # EXCLUDE_SERVICES: comma-separated services to exclude (default: consul-agent-http,mesos-slave,mesos-agent-watcher)
8
+
9
+ service_tag_filter = ENV['SERVICES_TAG_FILTER'] || nil
10
+ instance_must_tag = ENV['INSTANCE_MUST_TAG'] || service_tag_filter
11
+ instance_exclude_tag = ENV['INSTANCE_EXCLUDE_TAG']
12
+
13
+ # Services to hide
14
+ services_blacklist = (ENV['EXCLUDE_SERVICES'] || 'consul-agent-http,mesos-slave,mesos-agent-watcher,mesos-exporter-slave').split(',')
15
+ service_per_node = {}
16
+ services.each do |service_name, tags|
17
+ if !services_blacklist.include? service_name
18
+ service(service_name, tag: service_tag_filter).sort {|a,b| a['Node']['Node'] <=> b['Node']['Node'] }.each do |snode|
19
+ node_info = service_per_node[snode['Node']['Node']] || {}
20
+
21
+ node_node_data = {
22
+ Name: snode['Node']['Node'],
23
+ Address: snode['Node']['Address'],
24
+ Meta: snode['Node']['Meta'],
25
+ }
26
+
27
+ node_services_data = node_info[:Service] || []
28
+
29
+ service_data = {
30
+ Service: snode["Service"]["Service"],
31
+ Address: snode.service_address,
32
+ Tags: snode["Service"]["Tags"],
33
+ Port: snode["Service"]["Port"],
34
+ }
35
+ checks_array = []
36
+ snode["Checks"].each do |check|
37
+ checks_data = {
38
+ name: check["Name"],
39
+ status: check["Status"],
40
+ notes: check["Notes"],
41
+ output: check["Output"],
42
+ }
43
+ checks_array.push(checks_data)
44
+ end
45
+ node_service = {
46
+ Service: service_data,
47
+ Checks: checks_array,
48
+ }
49
+ node_services_data.push(node_service)
50
+
51
+ node_data = {
52
+ Node: node_node_data,
53
+ Service: node_services_data,
54
+ }
55
+
56
+ service_per_node[snode['Node']['Node']] = node_data
57
+ end
58
+ # break
59
+ end
60
+ end
61
+ %><%
62
+ json_datacenters = datacenters
63
+ json = { nodes: service_per_node, datacenters: json_datacenters, generated_at: Time.now}
64
+ %><%= JSON.pretty_generate(json) %>
@@ -3,7 +3,7 @@
3
3
  box-shadow: none;
4
4
  }
5
5
 
6
- #service-wrapper, #instances-wrapper {
6
+ #service-wrapper, #instances-wrapper, #keys-wrapper {
7
7
  overflow: scroll;
8
8
  border-top-left-radius: 0px;
9
9
  border-top-right-radius: 0px;
@@ -18,23 +18,35 @@
18
18
  overflow: hidden;
19
19
  }
20
20
 
21
- #service-wrapper .list-group-item:last-child, #instances-wrapper .list-group-item:last-child {
21
+ #service-wrapper .list-group-item:last-child, #instances-wrapper .list-group-item:last-child,
22
+ #keys-wrapper .list-group-item:last-child {
22
23
  border-bottom-width: 0px;
23
24
  border-bottom-left-radius: 0px;
24
25
  border-bottom-right-radius: 0px;
25
26
  }
26
27
 
27
- #service-wrapper .list-group-item:first-child, #instances-wrapper .list-group-item:first-child {
28
+ #service-wrapper .list-group-item:first-child, #instances-wrapper .list-group-item:first-child,
29
+ #keys-wrapper .list-group-item:first-child {
28
30
  border-top-width: 0px;
29
31
  border-top-left-radius: 0px;
30
32
  border-top-right-radius: 0px;
31
33
  }
32
34
 
33
- #service-wrapper .list-group-item, #instances-wrapper .list-group-item {
35
+ #service-wrapper .list-group-item, #instances-wrapper .list-group-item, #keys-wrapper .list-group-item {
34
36
  border-left: 0px;
35
37
  border-right: 0px;
36
38
  }
37
39
 
40
+ #node-statuses span {
41
+ font-size: 1rem;
42
+ transition: background-color .16s linear;
43
+ cursor: pointer;
44
+ }
45
+
46
+ #node-statuses {
47
+ margin-top: 0.4rem;
48
+ }
49
+
38
50
  h2 {
39
51
  margin-top: 1rem;
40
52
  margin-bottom: 1rem;
@@ -75,3 +87,67 @@ h2 .fas:hover {
75
87
  background-color: #a5a5a5 !important;
76
88
  color: #f1f1f1 !important;
77
89
  }
90
+
91
+ .status-deactivated {
92
+ background-color: #a5a5a5 !important;
93
+ color: #f1f1f1 !important;
94
+ }
95
+
96
+ .service-status {
97
+ transition: background-color .16s linear;
98
+ font-size: 85%;
99
+ cursor: pointer;
100
+ }
101
+
102
+ #instance-statuses {
103
+ padding-top: 5px;
104
+ text-align: center;
105
+ }
106
+
107
+ .status-sidebar {
108
+ width: 5px !important;
109
+ min-height: 1px;
110
+ flex-shrink: 0;
111
+ flex-grow: 0;
112
+ }
113
+
114
+ .instance-content {
115
+ width: 100%;
116
+ padding-top: 12px;
117
+ padding-bottom: 12px;
118
+ padding-left: 12px;
119
+ }
120
+
121
+ #nodes #instances-list .list-group-item {
122
+ padding-left: 0px;
123
+ padding-top: 0px;
124
+ padding-bottom: 0px;
125
+ display: flex;
126
+ flex-direction: row;
127
+ }
128
+
129
+ html, body {
130
+ height:100%;
131
+ }
132
+
133
+ .instance-content-header {
134
+ display: flex;
135
+ }
136
+
137
+ .instance-content-header h5 {
138
+ margin-right: 10px;
139
+ }
140
+
141
+ .meta-tags {
142
+ text-align: right;
143
+ flex: 2 0 0;
144
+ }
145
+
146
+ #data-wrapper {
147
+ overflow: scroll;
148
+ }
149
+
150
+ pre, code {
151
+ height: 100%;
152
+ margin-bottom: 0px;
153
+ }
@@ -0,0 +1,129 @@
1
+ class ConsulKeys {
2
+ constructor(ressourceURL, refresh) {
3
+ this.ressourceURL = ressourceURL;
4
+ this.fetchRessource();
5
+ this.keysList = $("#keys-list");
6
+ this.keysFilter = $("#keys-filter");
7
+ this.keysFilter.keyup(this.filterService);
8
+ this.refresh = parseInt(refresh);
9
+ this.keysFilterCounter = $("#keys-counter");
10
+ this.keysFilterCount = 0;
11
+ }
12
+
13
+ fetchRessource() {
14
+ $.ajax({url: this.ressourceURL, cache: false, dataType: "json", sourceObject: this, success: function(result){
15
+ consulKeys.initRessource(result);
16
+ }});
17
+ }
18
+
19
+ initRessource(data) {
20
+ this.data = data;
21
+ this.reloadKeysList();
22
+ console.log('Data generated at: ' + data['generated_at']);
23
+
24
+ var urlParam = new URL(location.href).searchParams.get('key');
25
+ if (urlParam) {
26
+ var nodes = document.getElementById('keys-list').childNodes;
27
+ for(var i in nodes) {
28
+ if($(nodes[i]).find(".key-name").html() == urlParam) {
29
+ var selectedElement = $(nodes[i])
30
+ this.selectKey(selectedElement);
31
+ selectedElement.focus()
32
+ break;
33
+ }
34
+ }
35
+ } else {
36
+ this.selectKey(document.getElementById('keys-list').firstElementChild);
37
+ }
38
+
39
+ if(this.refresh > 0) {
40
+ setTimeout(this.fetchRessource, this.refresh * 1000);
41
+ }
42
+ }
43
+
44
+ reloadKeysList() {
45
+ this.keysList.html('');
46
+ this.keysFilterCount = 0;
47
+
48
+ for (var key in this.data.kv) {
49
+
50
+ var listItem = document.createElement('button');
51
+ listItem.setAttribute('type','button');
52
+ listItem.setAttribute('onfocus','consulKeys.onClickServiceName(this)');
53
+ listItem.setAttribute('onclick','consulKeys.onClickServiceName(this)');
54
+ listItem.setAttribute('value',key);
55
+ listItem.setAttribute('class','list-group-item list-group-item-action');
56
+
57
+ var serviceNameItem = document.createElement('div');
58
+ serviceNameItem.setAttribute('class', 'key-name');
59
+ serviceNameItem.appendChild(document.createTextNode(key));
60
+ listItem.appendChild(serviceNameItem);
61
+
62
+ this.keysFilterCount += 1;
63
+ this.keysList.append(listItem);
64
+ }
65
+ this.keysFilterCounter.html(this.keysFilterCount);
66
+ resizeWrapper('keys-wrapper', 'keys-list');
67
+ this.filterService();
68
+ }
69
+
70
+ filterService() {
71
+ var filter = new RegExp(consulKeys.keysFilter.val());
72
+ consulKeys.keysFilterCount = 0;
73
+ consulKeys.keysList.children('button').each(function (){
74
+ var ui = $(this);
75
+ if(keyMatcher(this, filter)) {
76
+ ui.removeClass('d-none');
77
+ ui.addClass('d-block');
78
+ consulKeys.keysFilterCount += 1;
79
+ consulKeys.keysFilterCounter.html(consulKeys.keysFilterCount);
80
+ } else {
81
+ ui.removeClass('d-block');
82
+ ui.addClass('d-none');
83
+ }
84
+ })
85
+ }
86
+
87
+ onClickServiceName(source) {
88
+ this.selectKey(source);
89
+ this.updateURL($(source).find(".key-name").html());
90
+ }
91
+
92
+ updateURL(link) {
93
+ var newUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
94
+ if (link) {
95
+ newUrl += '?key=' + link
96
+ }
97
+ window.history.pushState({},"",newUrl);
98
+ }
99
+
100
+ selectKey(source) {
101
+ if (this.selectedKey) {
102
+ $(this.selectedKey).removeClass('active');
103
+ }
104
+ var serviceName = $(source).find(".key-name").html()
105
+ this.selectedKey = source.closest( "button" );
106
+ $(this.selectedKey).addClass('active');
107
+ this.displayKey([serviceName]);
108
+ }
109
+
110
+ displayKey(key) {
111
+ $("#kv-title").html(key);
112
+ if(this.data.kv[key] != null) {
113
+ var dataToDisplay = atob(this.data.kv[key]);
114
+ } else {
115
+ var dataToDisplay = 'NO DATA';
116
+ }
117
+
118
+ $("#kv-data").html(dataToDisplay);
119
+ $("#kv-data").removeClass();
120
+
121
+ $('pre code').each(function(i, block) {
122
+ hljs.highlightBlock(block);
123
+ });
124
+ resizeWrapper('data-wrapper', 'kv-data');
125
+ }
126
+ }
127
+
128
+ $( window ).resize(resizeData);
129
+ resizeData();
@@ -0,0 +1,120 @@
1
+ class ConsulNodes {
2
+ constructor(ressourceURL, refresh) {
3
+ this.ressourceURL = ressourceURL;
4
+ this.fetchRessource();
5
+ this.instanceFilter = $("#instance-filter");
6
+ this.instanceFilter.keyup(function (e) {
7
+ clearTimeout(consulNodes.timeout);
8
+ consulNodes.timeout = setTimeout(consulNodes.filterInstances, 400);
9
+ });
10
+ this.refresh = parseInt(refresh);
11
+ this.filterStatus = null;
12
+ this.maxDisplayed = 100;
13
+ this.displayedCount = 0;
14
+ this.servicesStatus = {};
15
+ }
16
+
17
+ fetchRessource() {
18
+ $.ajax({url: this.ressourceURL, cache: false, dataType: "json", sourceObject: this, success: function(result){
19
+ consulNodes.initRessource(result);
20
+ }});
21
+ }
22
+
23
+ initRessource(data) {
24
+ this.data = data;
25
+ this.displayInstances(this.data['nodes']);
26
+ console.log('Data generated at: ' + data['generated_at']);
27
+ }
28
+
29
+ onClickFilter(source) {
30
+ var status = $(source).attr('status');
31
+ this.filterStatus = (this.filterStatus == status) ? null : status;
32
+ this.filterInstances();
33
+ }
34
+
35
+ filterInstances() {
36
+ updateFilterDisplay(consulNodes.filterStatus);
37
+ consulNodes.displayedCount = 0;
38
+ consulNodes.servicesStatus = {};
39
+ var filter = new RegExp(consulNodes.instanceFilter.val());
40
+ $('#instances-list').children('div').each(function() {
41
+ var status = $(this).attr('status');
42
+ var limitNotReached = (consulNodes.displayedCount < consulNodes.maxDisplayed);
43
+
44
+ if(nodeMatcher(this, filter)) {
45
+ if (consulNodes.filterStatus == null || consulNodes.filterStatus == status) {
46
+ if (limitNotReached) {
47
+ $(this).removeClass('d-none');
48
+ $(this).addClass('d-flex');
49
+ consulNodes.displayedCount++;
50
+ }
51
+ var state = this.getAttribute('status');
52
+ consulNodes.servicesStatus[state] = (consulNodes.servicesStatus[state] || 0) + 1;
53
+ consulNodes.servicesStatus['total'] = (consulNodes.servicesStatus['total'] || 0) + 1;
54
+ updateStatusItem(consulNodes.servicesStatus);
55
+ } else {
56
+ $(this).removeClass('d-flex');
57
+ $(this).addClass('d-none');
58
+ }
59
+ } else {
60
+ $(this).removeClass('d-flex');
61
+ $(this).addClass('d-none');
62
+ }
63
+ })
64
+ }
65
+
66
+ displayInstances(instances) {
67
+ $("#instances-list").html("");
68
+
69
+ // var serviceStatus = buildServiceStatus(service);
70
+ this.displayedCount = 0;
71
+
72
+ for (var key in instances) {
73
+ var instance = instances[key];
74
+
75
+ var instanceHtml = document.createElement('div');
76
+ if(this.displayedCount > this.maxDisplayed) {
77
+ instanceHtml.setAttribute('class','list-group-item d-none');
78
+ } else {
79
+ instanceHtml.setAttribute('class','list-group-item');
80
+ }
81
+
82
+ var sidebar = document.createElement('div');
83
+ sidebar.setAttribute('class','status-sidebar');
84
+ var state = getGeneralNodeStatus(instance['Service']);
85
+ switch(state) {
86
+ case 'passing': sidebar.classList.add('bg-success'); break;
87
+ case 'warning': sidebar.classList.add('bg-warning'); break;
88
+ case 'critical': sidebar.classList.add('bg-danger'); break;
89
+ }
90
+ this.servicesStatus[state] = (this.servicesStatus[state] || 0) + 1;
91
+ this.servicesStatus['total'] = (this.servicesStatus['total'] || 0) + 1;
92
+
93
+ var content = document.createElement('div');
94
+ content.setAttribute('class','instance-content');
95
+ var contentHead = document.createElement('div');
96
+ contentHead.setAttribute('class','instance-content-header');
97
+ contentHead.appendChild(nodeNameGenator(instance['Node']['Name'],instance['Node']['Address']));
98
+ contentHead.appendChild(nodeAddressGenator(instance['Node']['Address']));
99
+ contentHead.appendChild(nodeMetaGenator(instance['Node']['Meta']));
100
+ content.appendChild(contentHead);
101
+ content.appendChild(servicesGenerator(instance['Service']));
102
+ content.appendChild(tagsGenerator(getTagsNode(instance)));
103
+
104
+ instanceHtml.setAttribute('status', state);
105
+ instanceHtml.appendChild(sidebar)
106
+ instanceHtml.appendChild(content)
107
+
108
+ $("#instances-list").append(instanceHtml);
109
+
110
+ this.displayedCount++;
111
+ }
112
+
113
+ resizeInstances();
114
+ $('#instances-list .list-group-item').resize(resizeInstances);
115
+ this.filterInstances();
116
+ }
117
+ }
118
+
119
+ $( window ).resize(resizeInstances);
120
+ resizeInstances();
@@ -5,6 +5,8 @@ class ConsulService {
5
5
  this.serviceList = $("#service-list");
6
6
  this.serviceFilter = $("#service-filter");
7
7
  this.serviceFilter.keyup(this.filterService);
8
+ this.instanceFilter = $("#instance-filter");
9
+ this.instanceFilter.keyup(this.filterInstances);
8
10
  this.refresh = parseInt(refresh);
9
11
  this.filterStatus = null;
10
12
  this.serviceFilterCounter = $("#service-counter");
@@ -18,7 +20,7 @@ class ConsulService {
18
20
  }
19
21
 
20
22
  fetchRessource() {
21
- $.ajax({url: "consul_template.json", cache: false, dataType: "json", sourceObject: this, success: function(result){
23
+ $.ajax({url: this.ressourceURL, cache: false, dataType: "json", sourceObject: this, success: function(result){
22
24
  consulService.initRessource(result);
23
25
  }});
24
26
  }
@@ -54,25 +56,45 @@ class ConsulService {
54
56
  for (var serviceName in this.data.services) {
55
57
  var service = this.data.services[serviceName];
56
58
  var serviceStatus = buildServiceStatus(service);
57
- var listItem = '<button type="button" onfocus="consulService.onClickServiceName(this)" onclick="consulService.onClickServiceName(this)" value="' + serviceName + '" class="list-group-item list-group-item-action">';
58
- listItem += '<div class="statuses" style="float:right">'
59
+
60
+ var listItem = document.createElement('button');
61
+ listItem.setAttribute('type','button');
62
+ listItem.setAttribute('onfocus','consulService.onClickServiceName(this)');
63
+ listItem.setAttribute('onclick','consulService.onClickServiceName(this)');
64
+ listItem.setAttribute('value',serviceName);
65
+ listItem.setAttribute('class','list-group-item list-group-item-action');
66
+
67
+ var statuses = document.createElement('div');
68
+ statuses.setAttribute('class','statuses float-right');
69
+
59
70
  if (!!serviceStatus['passing']) {
60
- listItem += '<span class="badge badge-pill badge-success passing" style="margin-right:10px;">' + serviceStatus['passing'] + '</span>';
71
+ statuses.appendChild(createBadge('badge-success passing', serviceStatus['passing']));
61
72
  }
73
+
62
74
  if (!!serviceStatus['warning']) {
63
- listItem += '<span class="badge badge-pill badge-warning warning" style="margin-right:10px;">' + serviceStatus['warning'] + '</span>';
75
+ statuses.appendChild(createBadge('badge-warning warning', serviceStatus['warning']));
64
76
  }
77
+
65
78
  if (!!serviceStatus['critical']) {
66
- listItem += '<span class="badge badge-pill badge-danger critical" style="margin-right:10px;">' + serviceStatus['critical'] + '</span>';
79
+ statuses.appendChild(createBadge('badge-danger critical', serviceStatus['critical']));
67
80
  }
68
- listItem+= ' / <span class="badge badge-pill badge-dark">' + (serviceStatus['total'] || 0) + '</span></div>';
69
- listItem += '<div class="service-name">' + serviceName + '</div>';
70
- listItem += '<div class="service-tags">'
81
+
82
+ statuses.appendChild(createBadge('badge-dark', (serviceStatus['total'] || 0)));
83
+ listItem.appendChild(statuses);
84
+
85
+ var serviceNameItem = document.createElement('div');
86
+ serviceNameItem.setAttribute('class', 'service-name');
87
+ serviceNameItem.appendChild(document.createTextNode(serviceName));
88
+ listItem.appendChild(serviceNameItem);
89
+
90
+ var serviceTagsItem = document.createElement('div');
91
+ serviceTagsItem.setAttribute('class', 'service-tags');
92
+
71
93
  for (var i = 0; i < service.tags.length; i++) {
72
- listItem += '<span title="' + service.tags[i] + '" class="badge badge-pill badge-' + (i%2?'secondary':'info') + '" style="float:right;">' + (service.tags[i]) + '</span> ';
94
+ serviceTagsItem.appendChild(createBadge('float-right badge-' + (i%2?'secondary':'info') , service.tags[i]));
73
95
  }
74
- listItem += '</div>'
75
- listItem += '</button>';
96
+
97
+ listItem.appendChild(serviceTagsItem);
76
98
  this.serviceFilterCount += 1;
77
99
  this.serviceList.append(listItem);
78
100
  }
@@ -85,14 +107,13 @@ class ConsulService {
85
107
  var filter = new RegExp(consulService.serviceFilter.val());
86
108
  consulService.serviceFilterCount = 0;
87
109
  consulService.serviceList.children('button').each(function (){
88
- if($(this).html().match(filter)) {
89
- var ui = $(this).closest( "button" )
110
+ var ui = $(this);
111
+ if(serviceMatcher(this, filter)) {
90
112
  ui.removeClass('d-none');
91
113
  ui.addClass('d-block');
92
114
  consulService.serviceFilterCount += 1;
93
115
  consulService.serviceFilterCounter.html(consulService.serviceFilterCount);
94
116
  } else {
95
- var ui = $(this).closest( "button" )
96
117
  ui.removeClass('d-block');
97
118
  ui.addClass('d-none');
98
119
  }
@@ -111,24 +132,21 @@ class ConsulService {
111
132
  }
112
133
 
113
134
  filterInstances() {
114
- $('.progress-status').each(function() {
115
- var status = $(this).attr('status');
116
- if (consulService.filterStatus == null) {
117
- $(this).removeClass('progress-deactivated');
118
- } else if(consulService.filterStatus == status) {
119
- $(this).removeClass('progress-deactivated');
120
- } else {
121
- $(this).addClass('progress-deactivated');
122
- }
123
- })
135
+ updateFilterDisplay(consulService.filterStatus);
136
+ var filter = new RegExp(consulService.instanceFilter.val());
124
137
  $('#instances-list').children('div').each(function() {
125
138
  var status = $(this).attr('status');
126
- if (consulService.filterStatus == null) {
127
- $(this).removeClass('d-none');
128
- $(this).addClass('d-block');
129
- } else if (consulService.filterStatus == status) {
130
- $(this).removeClass('d-none');
131
- $(this).addClass('d-block');
139
+ if(instanceMatcher(this, filter)) {
140
+ if (consulService.filterStatus == null) {
141
+ $(this).removeClass('d-none');
142
+ $(this).addClass('d-block');
143
+ } else if (consulService.filterStatus == status) {
144
+ $(this).removeClass('d-none');
145
+ $(this).addClass('d-block');
146
+ } else {
147
+ $(this).removeClass('d-block');
148
+ $(this).addClass('d-none');
149
+ }
132
150
  } else {
133
151
  $(this).removeClass('d-block');
134
152
  $(this).addClass('d-none');
@@ -167,9 +185,9 @@ class ConsulService {
167
185
  serviceHtml.setAttribute('class','list-group-item');
168
186
 
169
187
  serviceHtml.appendChild(serviceTitleGenerator(instance));
170
- serviceHtml.appendChild(tagsGenerator(instance));
171
- serviceHtml.appendChild(checksStatusGenerator(instance));
172
- var state = nodeState(instance);
188
+ serviceHtml.appendChild(tagsGenerator(instance.tags));
189
+ serviceHtml.appendChild(checksStatusGenerator(instance.checks));
190
+ var state = nodeState(instance.checks);
173
191
  serviceHtml.setAttribute('status', state);
174
192
  $("#instances-list").append(serviceHtml);
175
193
  }
@@ -183,153 +201,9 @@ class ConsulService {
183
201
 
184
202
  resizeWrapper('instances-wrapper', 'instances-list');
185
203
  $('#instances-list .list-group-item').resize(resizeAll);
204
+ this.filterInstances();
186
205
  }
187
206
  }
188
207
 
189
- function buildServiceStatus(service) {
190
- var serviceStatus = {};
191
-
192
- for (var key in service['instances']) {
193
- var instance = service['instances'][key];
194
- var state = nodeState(instance);
195
-
196
- serviceStatus[state] = (serviceStatus[state] || 0) + 1;
197
- serviceStatus['total'] = (serviceStatus['total'] || 0) + 1;
198
- }
199
-
200
- return serviceStatus;
201
- }
202
-
203
- function nodeState(instance) {
204
- status='passing';
205
- for (var checkKey in instance.checks) {
206
- switch(instance.checks[checkKey]['status']) {
207
- case 'passing': break;
208
- case 'warning': status='warning'; break;
209
- case 'critical': return 'critical'; break;
210
- }
211
- }
212
- return status;
213
- }
214
-
215
- supported_protocols = ['https', 'http', 'sftp', 'ftp', 'ssh', 'telnet']
216
-
217
- function serviceTitleGenerator(instance) {
218
- var protocol = null;
219
- for (i in supported_protocols) {
220
- var protoc = supported_protocols[i]
221
- if (instance.tags.includes(protoc)) {
222
- protocol = protoc + '://';
223
- break;
224
- }
225
- }
226
-
227
- var htmlTitle = document.createElement('h5');
228
-
229
- var instanceLink = document.createElement('a');
230
- if (protocol != null) {
231
- instanceLink.setAttribute('href', protocol + instance.addr + ':' + instance.port);
232
- instanceLink.setAttribute('target', '_blank');
233
- }
234
- instanceLink.appendChild(document.createTextNode(instance.name + ':' + instance.port));
235
- htmlTitle.appendChild(instanceLink);
236
-
237
- return htmlTitle;
238
- }
239
-
240
- function tagsGenerator(instance) {
241
- var tags = document.createElement('div');
242
-
243
- tags.className = 'tags';
244
- tags.appendChild(document.createTextNode("Tags: "));
245
- tags.appendChild(document.createElement('br'));
246
-
247
- for (var tagKey in instance.tags) {
248
- var tag = document.createElement('span');
249
- tag.setAttribute('class', 'badge badge-secondary mx-1');
250
- tag.appendChild(document.createTextNode(instance.tags[tagKey]));
251
- tags.appendChild(tag);
252
- }
253
- return tags;
254
- }
255
-
256
- function checksStatusGenerator(instance) {
257
- var checks = document.createElement('div');
258
- checks.className = 'checks';
259
- checks.appendChild(document.createTextNode("Checks: "));
260
- checks.appendChild(document.createElement('br'));
261
-
262
- for (var checkKey in instance.checks) {
263
- checkId = Math.floor(Math.random()*10000);
264
- switch(instance.checks[checkKey]['status']) {
265
- case 'passing': var btn = 'btn-success'; break;
266
- case 'warning': var btn = 'btn-warning'; break;
267
- case 'critical': var btn = 'btn-danger'; break;
268
- }
269
- var check = document.createElement('div');
270
-
271
- var btnCheck = document.createElement('button');
272
- btnCheck.setAttribute('class','btn ' + btn + ' btn-sm m-1');
273
- btnCheck.setAttribute('type', 'button');
274
- btnCheck.setAttribute('data-toggle', 'collapse');
275
- btnCheck.setAttribute('data-target', '#' + checkId);
276
- btnCheck.setAttribute('aria-expanded', 'false');
277
-
278
- btnCheck.appendChild(document.createTextNode(instance.checks[checkKey]['name']));
279
-
280
- check.appendChild(btnCheck);
281
-
282
- var collapseCheck = document.createElement('div');
283
- collapseCheck.setAttribute('class', 'collapse')
284
- collapseCheck.setAttribute('id', checkId)
285
-
286
- var cardCheck = document.createElement('div');
287
- cardCheck.setAttribute('class', 'card card-body p-3 m-1 mb-2');
288
-
289
- var notes = document.createElement('table');
290
- notes.setAttribute('class', 'table table-hover mb-0');
291
-
292
- var dataToDisplay = ['notes', 'output'];
293
- for (var index in dataToDisplay) {
294
- var tr = document.createElement('tr');
295
- var td1 = document.createElement('td');
296
- var td2 = document.createElement('td');
297
- var fieldName = dataToDisplay[index].replace(/\b\w/g, l => l.toUpperCase());
298
- td1.appendChild(document.createTextNode(fieldName + ': '));
299
- var target = td2
300
- if (index != 1) {
301
- target = document.createElement('div');
302
- target.setAttribute("class", "check-notes")
303
- } else {
304
- // Notes are rendered as plain text
305
- target = document.createElement('pre');
306
- target.setAttribute("class", "check-output")
307
- }
308
- target.appendChild(document.createTextNode(instance.checks[checkKey][dataToDisplay[index]]));
309
- td2.appendChild(target)
310
- tr.appendChild(td1);
311
- tr.appendChild(td2);
312
- notes.appendChild(tr);
313
- }
314
-
315
- cardCheck.appendChild(notes);
316
- collapseCheck.appendChild(cardCheck);
317
- check.appendChild(collapseCheck);
318
- checks.appendChild(check)
319
- }
320
-
321
- return checks;
322
- }
323
-
324
- function resizeAll() {
325
- resizeWrapper('service-wrapper', 'service-list');
326
- resizeWrapper('instances-wrapper', 'instances-list');
327
- }
328
-
329
- function resizeWrapper(wrapperId, wrapped) {
330
- var size = $(window).height() - $('#' + wrapperId).offset()["top"] - 20;
331
- $('#' + wrapperId).css("height", size);
332
- }
333
-
334
208
  $( window ).resize(resizeAll);
335
209
  resizeAll();