consul-templaterb 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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();