Implement quota-aware disk metrics (PR#16)

The system page showed the disk of the host volume, not the budget the
instance can actually fill — on a Hostsharing Managed Webspace that is a
group quota, tighter than the volume by an order of magnitude, so the
warn/critical highlighting could never fire before a build failed with
"Disk quota exceeded".

DiskQuota parses `quota -u -g --no-wrap --raw-grace` and picks the
tightest of the user quota, the group quota, and the volume itself;
SystemMetricsCollector reports whichever binds, resets the disk
min/max/avg when the binding source changes, and the system page names
the source in its info line. A host without a binding quota (Docker
hosts, developer machines) renders exactly as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-09-03 17:23:39 +02:00
co-authored by Claude Sonnet 5
parent be965617cd
commit 61c235313f
12 changed files with 574 additions and 27 deletions
+15 -1
View File
@@ -599,6 +599,20 @@ function initCurrentBuilds() {
/** The total each utilization metric is compared against for the critical highlighting. */
const UTILIZATION_TOTALS = { cpuUsed: "cpuCount", ramUsedGib: "ramTotalGib", diskUsedGib: "diskTotalGib" };
/** Mirrors UiFormats.diskTotal exactly, since both render the same field from GET /api/system. */
function formatDiskTotal(metrics) {
if (metrics.diskTotalGib == null) {
return "n/a";
}
const totalText = formatMetric(metrics.diskTotalGib) + " GiB";
const source = metrics.diskSource;
if (!source || source.kind === "volume") {
return metrics.quotasPresent ? totalText + " (volume, tighter than the quotas)" : totalText;
}
const hardLimit = formatMetric(source.hardLimitGib);
return totalText + " (" + source.kind + " quota " + source.subject + ", hard limit " + hardLimit + " GiB)";
}
/** Same thresholds as UiFormats.utilizationClass: warn from 80% of the total, critical from 90%. */
function utilizationClass(used, total) {
if (used == null || total == null || !(total > 0)) {
@@ -647,7 +661,7 @@ function initSystemTable() {
});
setText("info-cpu-count", metrics.cpuCount != null ? metrics.cpuCount + " cores" : "n/a");
setText("info-ram-total", metrics.ramTotalGib != null ? formatMetric(metrics.ramTotalGib) + " GiB" : "n/a");
setText("info-disk-total", metrics.diskTotalGib != null ? formatMetric(metrics.diskTotalGib) + " GiB" : "n/a");
setText("info-disk-total", formatDiskTotal(metrics));
setText("info-updated", formatTimeOfDay(metrics.timestamp));
}