consul-templaterb 1.0.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 +7 -0
- data/.gitignore +25 -0
- data/.gitreview +5 -0
- data/.rspec +2 -0
- data/.rubocop.yml +43 -0
- data/.ruby_app +0 -0
- data/.travis.yml +13 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +201 -0
- data/README.md +270 -0
- data/Rakefile +6 -0
- data/bin/consul-templaterb +246 -0
- data/consul-templaterb.gemspec +37 -0
- data/lib/consul/async/consul_endpoint.rb +279 -0
- data/lib/consul/async/consul_template.rb +323 -0
- data/lib/consul/async/consul_template_engine.rb +57 -0
- data/lib/consul/async/consul_template_render.rb +80 -0
- data/lib/consul/async/process_handler.rb +64 -0
- data/lib/consul/async/utilities.rb +17 -0
- data/lib/consul/async/version.rb +5 -0
- data/samples/checks.html.erb +96 -0
- data/samples/common/footer.html.erb +10 -0
- data/samples/common/header.html.erb +51 -0
- data/samples/consul_template.html.erb +94 -0
- data/samples/consul_template.json.erb +77 -0
- data/samples/consul_template.txt.erb +45 -0
- data/samples/consul_template.xml.erb +70 -0
- data/samples/criteo/haproxy.cfg.erb +163 -0
- data/samples/criteo_choregraphies.html.erb +91 -0
- data/samples/ha_proxy.cfg.erb +127 -0
- data/samples/keys.html.erb +38 -0
- data/samples/nodes.html.erb +17 -0
- data/samples/services.html.erb +89 -0
- metadata +189 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
module Consul
|
2
|
+
module Async
|
3
|
+
class ProcessDoesNotExist < StandardError
|
4
|
+
end
|
5
|
+
class ProcessHandler
|
6
|
+
attr_reader :command, :sig_reload, :sig_term, :pid, :exit_status
|
7
|
+
def initialize(command, sig_reload: 'HUP', sig_term: 'TERM')
|
8
|
+
raise 'empty sig_term is not supported' unless sig_term
|
9
|
+
@command = command
|
10
|
+
@sig_reload = sig_reload
|
11
|
+
@sig_term = sig_term
|
12
|
+
@pid = nil
|
13
|
+
@exit_status = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
return pid unless pid.nil?
|
18
|
+
@pid = Process.spawn(command)
|
19
|
+
end
|
20
|
+
|
21
|
+
def reload
|
22
|
+
return if sig_reload.nil?
|
23
|
+
STDERR.puts "Sending SIG #{sig_reload} to #{pid}..."
|
24
|
+
begin
|
25
|
+
Process.kill(sig_reload, pid)
|
26
|
+
rescue Errno::ESRCH => e
|
27
|
+
STDERR.puts "*** Process #{pid} has already been killed: #{e.inspect}"
|
28
|
+
raise e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def kill
|
33
|
+
return exit_status if pid.nil?
|
34
|
+
the_pid = pid
|
35
|
+
@pid = nil
|
36
|
+
STDERR.puts "[KILL] Sending SIG #{sig_term} to #{the_pid}..."
|
37
|
+
begin
|
38
|
+
STDERR.puts "[KILL] waiting for #{the_pid}..."
|
39
|
+
Process.kill(sig_term, the_pid)
|
40
|
+
rescue Errno::ESRCH
|
41
|
+
STDERR.puts "[KILL] *** Process #{the_pid} has already been killed"
|
42
|
+
end
|
43
|
+
begin
|
44
|
+
_pid, @exit_status = Process.waitpid2 the_pid
|
45
|
+
rescue SystemCallError
|
46
|
+
STDERR.puts "[KILL] *** UNEXPECTED ERROR *** Failed to get return code for #{the_pid}"
|
47
|
+
end
|
48
|
+
exit_status
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_status
|
52
|
+
raise ProcessDoesNotExist, 'No child process' if pid.nil?
|
53
|
+
begin
|
54
|
+
cpid, result = Process.waitpid2(pid, Process::WNOHANG)
|
55
|
+
raise ProcessDoesNotExist, "Unexpected PID: #{cpid}, was expecting #{pid}" unless cpid.nil? || cpid == pid
|
56
|
+
result
|
57
|
+
rescue Errno::ECHILD => e
|
58
|
+
e2 = ProcessDoesNotExist.new e
|
59
|
+
raise e2, "ChildProcess has been killed: #{e.message}", e.backtrace
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Consul
|
2
|
+
module Async
|
3
|
+
class Utilities
|
4
|
+
def self.bytes_to_h(bytes)
|
5
|
+
if bytes < 1024
|
6
|
+
"#{bytes} b"
|
7
|
+
elsif bytes < 1_048_576
|
8
|
+
"#{(bytes / 1024).round(2)} Kb"
|
9
|
+
elsif bytes < 1_073_741_824
|
10
|
+
"#{(bytes / 1_048_576.0).round(2)} Mb"
|
11
|
+
else
|
12
|
+
"#{(bytes / 1_073_741_824.0).round(2)} Gb"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,96 @@
|
|
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
|
+
services_tag_filter = ENV['SERVICES_TAG_FILTER']
|
6
|
+
def status_to_class(status)
|
7
|
+
if status == 'passing'
|
8
|
+
'success'
|
9
|
+
elsif status == 'warning'
|
10
|
+
'warning'
|
11
|
+
elsif status == 'critical'
|
12
|
+
'danger'
|
13
|
+
else
|
14
|
+
'info'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
%>
|
18
|
+
<%= render_file 'common/header.html.erb' %>
|
19
|
+
<style type="text/css">
|
20
|
+
.check {
|
21
|
+
transition: opacity 1s ease-out;
|
22
|
+
}
|
23
|
+
</style>
|
24
|
+
<script type="text/javascript">
|
25
|
+
function updateStates() {
|
26
|
+
states = ['passing', 'warning', 'critical']
|
27
|
+
stylesheet = document.getElementById('css-states');
|
28
|
+
txt = "";
|
29
|
+
for (var i in states) {
|
30
|
+
var s = states[i];
|
31
|
+
is_checked = document.getElementById('show_'+s).checked
|
32
|
+
var to_append = "." + s + " { ";
|
33
|
+
if (is_checked) {
|
34
|
+
to_append += "opacity: 1; height: auto;"
|
35
|
+
} else {
|
36
|
+
to_append += "opacity: 0; height: 0; overflow: hidden;"
|
37
|
+
}
|
38
|
+
to_append += " }\r\n"
|
39
|
+
txt += to_append;
|
40
|
+
}
|
41
|
+
stylesheet.textContent = txt;
|
42
|
+
}
|
43
|
+
</script>
|
44
|
+
<div class="container-fluid">
|
45
|
+
<div class="row">
|
46
|
+
<nav class="col-2">
|
47
|
+
<ul>
|
48
|
+
<%
|
49
|
+
all_services = services(tag: services_tag_filter)
|
50
|
+
all_services.each do |service_name, tags|
|
51
|
+
%>
|
52
|
+
<li><a href="#service_<%= service_name %>"><%= service_name %></a></li>
|
53
|
+
<% end %>
|
54
|
+
</ul>
|
55
|
+
</nav>
|
56
|
+
<main class="col-10">
|
57
|
+
<div class="float-right">
|
58
|
+
<div class="state-selector">
|
59
|
+
<input id="show_passing" type="checkbox" class="checks-visibility" value="passing" checked="checked" onchange="updateStates()"/>
|
60
|
+
<label for="show_passing"><span class="badge badge-success">Passing</span></label>
|
61
|
+
</div>
|
62
|
+
<div class="state-selector">
|
63
|
+
<input id="show_warning" type="checkbox" class="checks-visibility" value="warning" checked="checked" onchange="updateStates()"/>
|
64
|
+
<label for="show_warning"><span class="badge badge-warning">Warning</span></label>
|
65
|
+
</div>
|
66
|
+
<div class="state-selector">
|
67
|
+
<input id="show_critical" type="checkbox" class="checks-visibility" value="critical" checked="checked" onchange="updateStates()"/>
|
68
|
+
<label for="show_critical"><span class="badge badge-danger">Critical</span></label>
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
|
72
|
+
<h1 id="services">Services <%= services_tag_filter ? " tag: #{services_tag_filter}" : 'No filtering' %></h1>
|
73
|
+
<% all_services.each do |service_name, tags| %>
|
74
|
+
<div class="service" id="service_<%= service_name %>">
|
75
|
+
<h2>Service <%= service_name %></h2>
|
76
|
+
<div class="list-group">
|
77
|
+
<% checks_for_service(service_name).each do |check| %>
|
78
|
+
<div class="list-group-item check <%= check['Status'] %>" id="<%= check['CheckID'] %>">
|
79
|
+
<div class="d-flex align-items-center justify-content-between">
|
80
|
+
<h5>
|
81
|
+
<%= check['Name'] %> / <%= check['Node'] %>
|
82
|
+
</h5>
|
83
|
+
<span class="badge badge-pill badge-<%= status_to_class(check['Status']) %>"><%= check['Status'] %></span>
|
84
|
+
</div>
|
85
|
+
<p><%= ERB::Util.html_escape(check['Notes']) %></p>
|
86
|
+
<code><%= ERB::Util.html_escape(check['Output']) %></code>
|
87
|
+
</div>
|
88
|
+
<% end %>
|
89
|
+
</div>
|
90
|
+
</div>
|
91
|
+
<% end %>
|
92
|
+
</main>
|
93
|
+
</div>
|
94
|
+
</div>
|
95
|
+
<script type="text/javascript">updateStates();</script>
|
96
|
+
<%= render_file 'common/footer.html.erb' %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
</div>
|
2
|
+
</main>
|
3
|
+
<!-- Bootstrap core JavaScript
|
4
|
+
================================================== -->
|
5
|
+
<!-- Latest compiled and minified JavaScript -->
|
6
|
+
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
7
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
8
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
9
|
+
</body>
|
10
|
+
</html>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%
|
2
|
+
# This template can be configure the following way with environment variables
|
3
|
+
# CONSUL_TOOLS_SUFFIX: suffix for the address of consul tools
|
4
|
+
# CONSUL_TOOLS_PREFIX: prefix for the address of consul tools
|
5
|
+
# CONSUL_TOOLS: comma sperated list of consul tools
|
6
|
+
tools = (ENV['CONSUL_TOOLS'] || 'criteo_choregraphies,checks,services,nodes,keys').split(",")
|
7
|
+
suffix = ENV['CONSUL_TOOLS_PREFIX'] || '.html'
|
8
|
+
prefix = ENV['CONSUL_TOOLS_SUFFIX'] || ''
|
9
|
+
%>
|
10
|
+
<!DOCTYPE html>
|
11
|
+
<html lang="en">
|
12
|
+
<head>
|
13
|
+
<meta charset="utf-8">
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
15
|
+
<meta name="description" content="Display Consul information">
|
16
|
+
<meta name="author" content="Criteo">
|
17
|
+
<meta http-equiv="refresh" content="<%= ENV['REFRESH'] || '600' %>"/>
|
18
|
+
|
19
|
+
<title><%= ENV['TITLE'] || 'Consul Real Time information'%></title>
|
20
|
+
|
21
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
22
|
+
<style type="text/css">
|
23
|
+
body {
|
24
|
+
padding-top: 5rem;
|
25
|
+
}
|
26
|
+
.check {
|
27
|
+
transition: opacity 1s ease-out;
|
28
|
+
}
|
29
|
+
</style>
|
30
|
+
<style type="text/css" id="css-states">
|
31
|
+
</style>
|
32
|
+
</head>
|
33
|
+
|
34
|
+
<body>
|
35
|
+
|
36
|
+
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
|
37
|
+
<a class="navbar-brand" href="#">Consul</a>
|
38
|
+
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
39
|
+
<span class="navbar-toggler-icon"></span>
|
40
|
+
</button>
|
41
|
+
|
42
|
+
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
43
|
+
<ul class="navbar-nav mr-auto">
|
44
|
+
<% tools.each do |tool| %>
|
45
|
+
<li class="nav-item">
|
46
|
+
<a class="nav-link" href="<%= prefix + tool + suffix %>"><%= tool.gsub('_', ' ') %></a>
|
47
|
+
</li>
|
48
|
+
<% end %>
|
49
|
+
</ul>
|
50
|
+
</div>
|
51
|
+
</nav>
|
@@ -0,0 +1,94 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="fr">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8"/>
|
5
|
+
<meta http-equiv="refresh" content="300"/>
|
6
|
+
<title>Consul Full Info</title>
|
7
|
+
<style type="text/css">
|
8
|
+
.passing {
|
9
|
+
color:green;
|
10
|
+
}
|
11
|
+
.warning {
|
12
|
+
color: orange;
|
13
|
+
}
|
14
|
+
.critical {
|
15
|
+
color: red;
|
16
|
+
}
|
17
|
+
.qlink {
|
18
|
+
text-decoration: none;
|
19
|
+
}
|
20
|
+
</style>
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
<% require 'base64'
|
24
|
+
require 'json'
|
25
|
+
require 'date'
|
26
|
+
%>
|
27
|
+
<nav>
|
28
|
+
<ul>
|
29
|
+
<li><a href="#datacenters">DataCenters</a></li>
|
30
|
+
<li><a href="#list_services">List of services</a></li>
|
31
|
+
<li><a href="#services">Services with instances</a></li>
|
32
|
+
<li><a href="#nodes">All Nodes</a></li>
|
33
|
+
<li><a href="#kv">Key/Value Store</a></li>
|
34
|
+
</ul>
|
35
|
+
</nav>
|
36
|
+
<h1 id="datacenters">List of all datacenters</h1>
|
37
|
+
<ul>
|
38
|
+
<% datacenters.each do |dc| %>
|
39
|
+
<li id="dc_<%=dc %>%"><%= dc %> with <%= services(dc:dc).keys.count %> services, <%= nodes(dc:dc).count %> nodes</li>
|
40
|
+
<% end %>
|
41
|
+
</ul>
|
42
|
+
|
43
|
+
<h1 id="list_services">List of all services in current DC</h1>
|
44
|
+
<ul>
|
45
|
+
<% services.each do |service_name, tags|
|
46
|
+
%>
|
47
|
+
<li><a href="#service_<%= service_name %>"><%= service_name %></a> <%= tags.sort %></li>
|
48
|
+
<% end %>
|
49
|
+
</ul>
|
50
|
+
|
51
|
+
<h1 id="services">List all services instances sorted by node name</h1>
|
52
|
+
<% services.each do |service_name, tags|
|
53
|
+
%><h2 id="service_<%= service_name %>" title="<%= tags %>"><%= service_name %> <a class="qlink" href="#service_<%= service_name %>">🔗</a></h2>
|
54
|
+
<ul>
|
55
|
+
<% service(service_name).sort {|a,b| a['Node']['Node'] <=> b['Node']['Node'] }.each do |snode|
|
56
|
+
tags = snode['Service']['Tags'].sort
|
57
|
+
addr = snode['Node']['Address']
|
58
|
+
port_num = snode['Service']['Port'].to_i
|
59
|
+
port = port_num && port_num > 0 ? ":#{port_num}" : ''
|
60
|
+
url = if tags.include? 'https'
|
61
|
+
"https://#{addr}#{port}"
|
62
|
+
elsif tags.include? 'http'
|
63
|
+
"http://#{addr}#{port}"
|
64
|
+
elsif tags.include? 'ftp'
|
65
|
+
"ftp://#{addr}#{port}"
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
%><li><a <%= url ? "href=\"#{url}\"" : nil %>><%=
|
70
|
+
snode['Node']['Node'] %><%= port %></a>
|
71
|
+
<span class="tags"><%= snode['Service']['Tags'].sort %></tag>
|
72
|
+
<span class="statuses"><%
|
73
|
+
snode['Checks'].each do |c| %> <span title="<%= c['Name']%>" class="<%= c['Status'] %>"><%= c['Status']
|
74
|
+
%></span><% end if snode['Checks'] %></span></li>
|
75
|
+
<% end%>
|
76
|
+
</ul>
|
77
|
+
<% end%>
|
78
|
+
|
79
|
+
|
80
|
+
<h1 id="nodes">List all nodes for DC, sorted by name</h1>
|
81
|
+
<ul>
|
82
|
+
<% nodes.sort {|a,b| a['Node'] <=> b['Node'] }.each do |snode|
|
83
|
+
%> <li id="node_#{snode['ID']"><%= snode['Address'].ljust(16) %> <%= snode['Node'] %></li>
|
84
|
+
<% end %>
|
85
|
+
</ul>
|
86
|
+
|
87
|
+
<h1 id="kv">KV of Current DC</h1>
|
88
|
+
<ul>
|
89
|
+
<% kv(keys:true).each do |key|
|
90
|
+
%><li id="kv_#{key}"><%= key %></li>
|
91
|
+
<% end %>
|
92
|
+
</ul>
|
93
|
+
</body>
|
94
|
+
</html>
|
@@ -0,0 +1,77 @@
|
|
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'] || 'http'
|
10
|
+
instance_must_tag = ENV['INSTANCE_MUST_TAG'] || service_tag_filter
|
11
|
+
instance_exclude_tag = ENV['INSTANCE_EXCLUDE_TAG'] || 'canary'
|
12
|
+
|
13
|
+
# Services to hide
|
14
|
+
services_blacklist = (ENV['EXCLUDE_SERVICES'] || 'consul-agent-http,mesos-slave,mesos-agent-watcher,mesos-exporter-slave').split(',')
|
15
|
+
# Compute the health of a Service
|
16
|
+
def compute_state(snode)
|
17
|
+
states = ['passing', []]
|
18
|
+
snode['Checks'].each do |chk|
|
19
|
+
st = chk['Status']
|
20
|
+
states[1] << st
|
21
|
+
if st == 'critical'
|
22
|
+
states[0] = st
|
23
|
+
elsif st == 'warning' && states[0] == 'passing'
|
24
|
+
states[0] = st
|
25
|
+
end
|
26
|
+
end
|
27
|
+
states
|
28
|
+
end
|
29
|
+
def compute_attributes(snode)
|
30
|
+
w = 100
|
31
|
+
snode['Service']['Tags'].each do |tag|
|
32
|
+
match = /^weight-([1-9][0-9])*$/.match(tag)
|
33
|
+
w = match[1].to_i if match
|
34
|
+
end
|
35
|
+
attributes = ""
|
36
|
+
states = compute_state(snode)
|
37
|
+
attributes = "#{attributes} disabled" if states[0] == 'critical'
|
38
|
+
if states[0] == 'warning'
|
39
|
+
w = w / 8
|
40
|
+
end
|
41
|
+
attributes = "#{attributes} weight #{w}" if w.positive?
|
42
|
+
end
|
43
|
+
backends = {}
|
44
|
+
services(tag: service_tag_filter).each do |service_name, tags|
|
45
|
+
if !services_blacklist.include?(service_name) && tags.include?(instance_must_tag)
|
46
|
+
the_backends = []
|
47
|
+
service(service_name, tag:'http').sort {|a,b| a['Node']['Node'] <=> b['Node']['Node'] }.each do |snode|
|
48
|
+
tags_of_instance = snode['Service']['Tags']
|
49
|
+
if tags_of_instance.include?(instance_must_tag) && !tags_of_instance.include?(instance_exclude_tag)
|
50
|
+
the_backends << snode if snode['Service']['Port']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
# We add the backend ONLY if at least one valid instance does exists
|
54
|
+
backends[service_name] = the_backends
|
55
|
+
end
|
56
|
+
end
|
57
|
+
%><%
|
58
|
+
json_backends = {}
|
59
|
+
backends.each_pair do |service_name, nodes|
|
60
|
+
service = {
|
61
|
+
name: service_name,
|
62
|
+
count: nodes.count,
|
63
|
+
instances: []
|
64
|
+
}
|
65
|
+
json_backends[service_name] = service
|
66
|
+
nodes.each do |snode|
|
67
|
+
server = { frontend_id: "backend_http__#{service_name}",
|
68
|
+
id: snode['Service']['ID'],
|
69
|
+
addr: snode['Node']['Address'],
|
70
|
+
port: snode['Service']['Port'],
|
71
|
+
tags: snode['Service']['Tags'],
|
72
|
+
}
|
73
|
+
service[:instances] << server
|
74
|
+
end
|
75
|
+
end
|
76
|
+
json = { services: json_backends}
|
77
|
+
%><%= JSON.pretty_generate(json) %>
|
@@ -0,0 +1,45 @@
|
|
1
|
+
+ List of all datacenters
|
2
|
+
-------------------------
|
3
|
+
<% datacenters. each do |dc| %>
|
4
|
+
* <%= dc %> with <%= services(dc:dc).keys.count %> services, <%= nodes(dc:dc).count %> nodes
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
===========
|
8
|
+
|
9
|
+
+ List of all services in current DC
|
10
|
+
------------------------------------
|
11
|
+
<% services.each do |service_name, tags|
|
12
|
+
%> * <%= service_name %> [ <%= tags %> ]
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
===========
|
16
|
+
|
17
|
+
+ List all services instances with http tag on current DC, instances sorted by node name
|
18
|
+
----------------------------------------------------------------------------------------
|
19
|
+
<% services.each do |service_name, tags|
|
20
|
+
if tags.include? 'http'
|
21
|
+
%> ++ Service <%= service_name %>
|
22
|
+
<% service(service_name, tag:'http').sort {|a,b| a['Node']['Node'] <=> b['Node']['Node'] }.each do |snode|
|
23
|
+
%> * <%= service_name %> -> <%=
|
24
|
+
snode['Node']['Node'] %>:<%= snode['Service']['Port'] %> <%=
|
25
|
+
snode['Service']['Tags'] %> status: <%
|
26
|
+
snode['Checks'].each do |c| %> <%= c['Status']
|
27
|
+
%><% end if snode['Checks'] %>
|
28
|
+
<% end
|
29
|
+
end
|
30
|
+
end %>
|
31
|
+
|
32
|
+
===========
|
33
|
+
|
34
|
+
+ List all nodes for DC, sorted by name
|
35
|
+
---------------------------------------
|
36
|
+
<% nodes.sort {|a,b| a['Node'] <=> b['Node'] }.each do |snode|
|
37
|
+
%> * <%= snode['Address'].ljust(16) %> <%= snode['Node'] %>
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
+ KV of Current DC
|
41
|
+
------------------
|
42
|
+
|
43
|
+
<% kv(keys:true).each do |key|
|
44
|
+
%> * <%= key %>
|
45
|
+
<% end %>
|