Admin: freier Speicher pro Docker-Host anzeigen

Die Karte Docker-Hosts zeigt den freien Speicher unter /var/lib/docker, per SSH
mit df gemessen und eine Minute zwischengespeichert. Unter 20 GB wird die
Zeile rot.
This commit is contained in:
mregosar committed 2026-10-29 10:30:01 +01:00
1 parent 844da4713d
commit 1243e9c852
6 files changed
+66 -4

No files matched your search

+41
View File
@@ -4,6 +4,16 @@ import { configureViaRcon, listRoundBackups, loadRoundBackup, rconStatus } from
import { runRcon } from './rcon.js';
const exec = promisify(execFile);
const DISK_CACHE_MS = 60_000;
/** Liest Gesamt- und freien Speicher aus einer Zeile von `df -B1` (Spalten: Filesystem, 1B-blocks, Used, Available …). */
export function parseDf(output) {
const parts = String(output).trim().split(/\s+/);
const totalBytes = Number(parts[1]);
const freeBytes = Number(parts[3]);
if (!Number.isFinite(totalBytes) || !Number.isFinite(freeBytes)) return null;
return { totalBytes, freeBytes };
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Diese Zeile schreibt das Image, sobald SteamCMD fertig ist und der Spielserver startet.
@@ -236,6 +246,37 @@ export class DockerHostPool {
getUsedPorts: () => (getUsedPorts ? getUsedPorts(h.publicHost) : new Set()),
runDocker,
})]));
this.diskCache = new Map();
this.diskInflight = new Map();
}
/**
* Freier Speicher unter /var/lib/docker auf einem Host, per SSH. Ergebnis wird eine Minute lang
* zwischengespeichert, weil die Admin-Seite alle paar Sekunden abfragt. Ohne ssh:// gibt es null.
*/
async diskUsage(name) {
const host = this.hosts.find((h) => h.name === name);
if (!host?.dockerHost?.startsWith('ssh://')) return null;
const cached = this.diskCache.get(name);
if (cached && Date.now() - cached.at < DISK_CACHE_MS) return cached.value;
if (!this.diskInflight.has(name)) {
this.diskInflight.set(name, (async () => {
let value = null;
try {
const { stdout } = await exec('ssh', [
'-o', 'BatchMode=yes', '-o', 'ConnectTimeout=5', host.dockerHost.slice('ssh://'.length),
'df -B1 /var/lib/docker 2>/dev/null || df -B1 /',
], { timeout: 10_000 });
value = parseDf(stdout.trim().split('\n').pop());
} catch {
value = null;
}
this.diskCache.set(name, { at: Date.now(), value });
this.diskInflight.delete(name);
return value;
})());
}
return this.diskInflight.get(name);
}
/** Freie Port-Paare auf einem Host. */