consul-templaterb 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,5 @@
1
+ module Consul
2
+ module Async
3
+ VERSION = '1.0.3'.freeze
4
+ end
5
+ 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 %>">&#128279;</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 %>