consul-templaterb 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|