Add drive SMART attributes and health status
This commit is contained in:
1 parent
40109b5c62
commit
23d7e79605
3 files changed
+128
-6
No files matched your search
+68
-2
@@ -97,18 +97,84 @@ if cgi.params.key?("content")
|
||||
exit
|
||||
end
|
||||
|
||||
thousands = ->(n) { n.to_s.gsub(/(\d)(?=(\d{3})+$)/, '\1,') }
|
||||
|
||||
drive_stats = lambda do |dt, smart|
|
||||
stats = []
|
||||
|
||||
case smart["passed"]
|
||||
when true then stats << ["ok", "SMART PASSED"]
|
||||
when false then stats << ["bad", "SMART FAILED"]
|
||||
end
|
||||
|
||||
if (t = smart["temperature"])
|
||||
cls = t >= 60 ? "bad" : t >= 50 ? "warn" : "ok"
|
||||
stats << [cls, "🌡 #{t} °C"]
|
||||
end
|
||||
|
||||
if (poh = smart["power_on_hours"])
|
||||
stats << ["ok", "POH #{thousands.(poh)} h"]
|
||||
end
|
||||
|
||||
if dt == "nvme"
|
||||
if (p = smart["percentage_used"])
|
||||
cls = p >= 90 ? "bad" : p >= 70 ? "warn" : "ok"
|
||||
stats << [cls, "Wear #{p}%"]
|
||||
end
|
||||
if (m = smart["media_errors"])
|
||||
stats << [m > 0 ? "bad" : "ok", "Media err #{m}"]
|
||||
end
|
||||
if (cw = smart["critical_warning"]) && cw != 0
|
||||
stats << ["bad", "Crit warn 0x#{cw.to_s(16)}"]
|
||||
end
|
||||
else
|
||||
if (r = smart["reallocated_sectors"])
|
||||
stats << [r > 0 ? "warn" : "ok", "Realloc #{r}"]
|
||||
end
|
||||
if (s = smart["spin_retry"])
|
||||
stats << [s > 0 ? "warn" : "ok", "Spin retry #{s}"]
|
||||
end
|
||||
if (p = smart["pending_sectors"])
|
||||
stats << [p > 0 ? "warn" : "ok", "Pending #{p}"]
|
||||
end
|
||||
if (c = smart["crc_errors"])
|
||||
stats << [c > 0 ? "warn" : "ok", "CRC #{c}"]
|
||||
end
|
||||
end
|
||||
|
||||
stats
|
||||
end
|
||||
|
||||
info.each do |entry|
|
||||
case entry["type"]
|
||||
when "drive"
|
||||
dt = entry["drivetype"]
|
||||
name = CGI.escapeHTML(entry["name"].to_s)
|
||||
model = CGI.escapeHTML(entry["model"])
|
||||
capacity = CGI.escapeHTML(entry["capacity"])
|
||||
smart = entry["smart"]
|
||||
|
||||
stats = smart ? drive_stats.(dt, smart) : []
|
||||
card_cls = if stats.any? { |c, _| c == "bad" } then "bad"
|
||||
elsif stats.any? { |c, _| c == "warn" } then "warn"
|
||||
else "ok"
|
||||
end
|
||||
|
||||
stats_html = stats.map { |c, txt|
|
||||
%(<span class="stat #{c}">#{CGI.escapeHTML(txt)}</span>)
|
||||
}.join
|
||||
stats_block = stats.empty? ? "" :
|
||||
%(<div class="drive-stats" style="margin-top:0.6rem;">#{stats_html}</div>)
|
||||
|
||||
title = name.empty? ? model : "#{name} · #{model}"
|
||||
|
||||
html << <<~HTML
|
||||
<div class="card ok">
|
||||
<div class="card #{card_cls} span-2">
|
||||
<div class="card-header">
|
||||
<span class="card-title">#{model} <span class="drive-type #{dt}">#{dt.upcase}</span></span>
|
||||
<span class="card-title">#{title} <span class="drive-type #{dt}">#{dt.upcase}</span></span>
|
||||
</div>
|
||||
<div class="card-sub">#{capacity}</div>
|
||||
#{stats_block}
|
||||
</div>
|
||||
HTML
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user