--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_http_host_status_check/mod_http_host_status_check.lua Tue Jun 28 22:33:13 2016 +0100
@@ -0,0 +1,101 @@
+local heartbeats = module:shared("/*/host_status_check/heartbeats");
+local events = module:shared("/*/host_status_check/connection_events");
+
+local time = require "socket".gettime;
+local template = require "util.interpolation".new("%b{}", function (s) return s end)
+local st = require "util.stanza";
+
+module:depends "http"
+
+local threshold = module:get_option_number("status_check_heartbeat_threshold", 5);
+
+local function status_string(status, duration, comment)
+ local string_timestamp = "";
+ if duration then
+ string_timestamp = ("(%0.2fs%s)"):format(duration, comment or "");
+ elseif comment then
+ string_timestamp = ("(%s)"):format(comment);
+ else
+ return status and "UP" or "DOWN";
+ end
+ return (status and "UP " or "DOWN ")..string_timestamp;
+end
+
+local function string_pad(s, len)
+ return s..(" "):rep(len-#s);
+end
+
+local status_page_template = [[
+STATUS {status}
+{host_statuses%HOST {item} {idx}
+}]];
+
+function status_page()
+ local host_statuses = {};
+ local current_time = time();
+
+ local all_ok = true;
+
+ for host in pairs(hosts) do
+ local last_heartbeat_time = heartbeats[host];
+
+ local ok, status_text = true, "OK";
+
+ local is_component = hosts[host].type == "component" and hosts[host].modules.component;
+
+ if is_component then
+ local current_status = hosts[host].modules.component.connected;
+ if events[host] then
+ local tracked_status = events[host].connected;
+ if tracked_status == current_status then
+ status_text = status_string(current_status, time() - events[host].timestamp);
+ else
+ status_text = status_string(current_status, nil, "!");
+ end
+ else
+ status_text = status_string(current_status, nil, "?");
+ end
+ if not current_status then
+ ok = false;
+ end
+ else
+ local event_info = events[host];
+ local connected = true;
+ if event_info then
+ connected = event_info.connected;
+ end
+ status_text = status_string(connected, event_info and (time() - events[host].timestamp), not event_info and "?");
+ end
+
+ if last_heartbeat_time then
+ local time_since_heartbeat = current_time - last_heartbeat_time;
+ if ok then
+ if time_since_heartbeat > threshold then
+ status_text = ("TIMEOUT (%0.2fs)"):format(time_since_heartbeat);
+ ok = false;
+ else
+ status_text = status_text:gsub("^%S+", "GOOD");
+ end
+ end
+ end
+
+ if not ok then
+ all_ok = false;
+ end
+
+ if not ok or is_component or last_heartbeat_time then
+ host_statuses[host] = string_pad(status_text, 20);
+ end
+ end
+ local page = template(status_page_template, {
+ status = all_ok and "OK" or "FAIL";
+ host_statuses = host_statuses;
+ });
+ return page;
+end
+
+module:provides("http", {
+ route = {
+ GET = status_page;
+ };
+})