diff --git a/bin/malpd b/bin/malpd index 1122fc4..3875ed5 100755 --- a/bin/malpd +++ b/bin/malpd @@ -213,6 +213,18 @@ def read_server_info info end +def read_backups + paths = [ + ["rsync", "/backup/last-backup"], + ["gmail", "/backup/gmail/new"] + ] + entries = paths.map do |label, path| + mtime = (File.mtime(path).to_i rescue nil) + { "label" => label, "path" => path, "mtime" => mtime } + end + { "type" => "backup", "entries" => entries } +end + def read_mail users = [] @@ -308,6 +320,7 @@ def handle_info(conn) info << read_server_info info << read_mail + info << read_backups if (ups = read_ups) info << ups diff --git a/cgi-bin/malp.rb b/cgi-bin/malp.rb index 293d228..8be0289 100755 --- a/cgi-bin/malp.rb +++ b/cgi-bin/malp.rb @@ -7,6 +7,14 @@ require "json" require "securerandom" require "socket" +def human_age(seconds) + return "unknown" if seconds.nil? + return "just now" if seconds < 60 + return "#{seconds / 60} min ago" if seconds < 3600 + return "#{seconds / 3600} h ago" if seconds < 86400 + "#{seconds / 86400} d ago" +end + def human_capacity(bytes) units = ["B", "KB", "MB", "GB", "TB", "PB"] i = 0 @@ -371,8 +379,10 @@ if cgi.params.key?("content") upses = info.select { |e| e["type"] == "ups" } mail = info.find { |e| e["type"] == "mail" } mail_visible = mail && (mail["users"] || []).any? + backup = info.find { |e| e["type"] == "backup" } + backup_visible = backup && (backup["entries"] || []).any? - if drives.any? || upses.any? || mail_visible + if drives.any? || upses.any? || mail_visible || backup_visible html << %(
) end @@ -414,7 +424,7 @@ if cgi.params.key?("content") html << %(
) end - if upses.any? || mail_visible + if upses.any? || mail_visible || backup_visible html << %(
) upses.each do |ups| @@ -497,10 +507,44 @@ if cgi.params.key?("content") html << %(
) end + if backup_visible + now = Time.now.to_i + classified = backup["entries"].map do |e| + mtime = e["mtime"] + cls = if mtime.nil? + "bad" + else + age = now - mtime + age < 2 * 86400 ? "ok" : age < 7 * 86400 ? "warn" : "bad" + end + [e, cls] + end + + backup_card_cls = if classified.any? { |_, c| c == "bad" } then "bad" + elsif classified.any? { |_, c| c == "warn" } then "warn" + else "ok" + end + + html << %(
Backups
) + html << %(
Backups
) + + classified.each do |e, cls| + age_label = e["mtime"] ? human_age(now - e["mtime"]) : "missing" + html << <<~HTML +
+
#{CGI.escapeHTML(e["label"].to_s)}
+ #{CGI.escapeHTML(age_label)} +
+ HTML + end + + html << %(
) + end + html << %() end - if drives.any? || upses.any? || mail_visible + if drives.any? || upses.any? || mail_visible || backup_visible html << %() end