Say what Varaverk itself is using on the System card

The card described the machine and said nothing about the thing whose dashboard
it is. Cache size matters most: VV_CACHE_ROOT is under /tmp, which on Unraid is
RAM, so it is shown against the rootfs percentage it counts against. Jobs are
locks with a live process — four lock files were sitting there and one job was
actually running.
This commit is contained in:
Gmer4Lfe
2026-08-21 09:39:52 -04:00
parent d9c37ac763
commit 96b907acbc
4 changed files with 133 additions and 0 deletions
+1
View File
@@ -112,6 +112,7 @@ if (vv_ai_ui_on()) {
$monitor = [ $monitor = [
'system' => vv_system_info(), 'system' => vv_system_info(),
'varaverk' => vv_varaverk_state(),
'fallback' => vv_fallback_state(), 'fallback' => vv_fallback_state(),
'fallback_active' => vv_fallback_active(), 'fallback_active' => vv_fallback_active(),
'partner' => vv_partner_state(), 'partner' => vv_partner_state(),
+1
View File
@@ -112,6 +112,7 @@ if (vv_ai_ui_on()) {
echo json_encode([ echo json_encode([
'system' => vv_system_info(), 'system' => vv_system_info(),
'varaverk' => vv_varaverk_state(),
'fallback' => vv_fallback_state(), 'fallback' => vv_fallback_state(),
'fallback_active' => vv_fallback_active(), 'fallback_active' => vv_fallback_active(),
'partner' => vv_partner_state(), 'partner' => vv_partner_state(),
+70
View File
@@ -329,6 +329,76 @@ function vv_watchdog_summary(): array {
]; ];
} }
// What Varaverk itself is occupying and doing, as opposed to what the machine is.
//
// The System card described the host — model, uptime, load — and said nothing about the thing
// whose dashboard it is. These are the figures that are Varaverk's own and that nothing else on
// the page reports.
//
// The cache size is the one worth watching. VV_CACHE_ROOT is /tmp/varaverk, and on Unraid /tmp is
// on rootfs, which is RAM — so this directory is memory, not disk, and the arr payload cache is
// most of it. master.conf says never to move these onto flash, which makes the size the thing to
// keep an eye on instead. Reported next to the rootfs percentage it consumes, because 187 MB
// means nothing without the ceiling it counts against.
//
// du rather than a recursive PHP walk: both roots are small and page-cached, measured at 3ms
// each, and this is assembled once a minute by the cache writer rather than per page load.
function vv_varaverk_state(): array {
$du = function (string $path): ?int {
if (!is_dir($path)) return null;
$out = shell_exec('du -sb ' . escapeshellarg($path) . ' 2>/dev/null');
return preg_match('/^(\d+)/', (string)$out, $m) ? (int)$m[1] : null;
};
// Locks whose process is still alive. A lock file alone does not mean a job is running —
// acquire_lock() clears one whose pid is gone, and three were sitting in LOCK_DIR from jobs
// that finished days ago. Counting files would have reported four jobs running and one
// actually was.
$running = [];
$stale = 0;
foreach ((array)@glob('/tmp/unraid_locks/*.lock') as $lock) {
$content = trim((string)@file_get_contents($lock));
if ($content === '') { $stale++; continue; }
[$pid, $name] = array_pad(explode(':', $content, 2), 2, '');
$pid = (int)$pid;
if ($pid > 1 && @posix_kill($pid, 0)) {
$running[] = $name !== '' ? $name : basename($lock, '.lock');
} else {
$stale++;
}
}
sort($running);
// Newest partner conf in the RAM cache. conf_sync fills it; an age climbing past its schedule
// means the mesh has stopped talking, which nothing else on this page would show.
$confAge = null;
foreach ((array)@glob(VV_CONF_RAM_CACHE_DIR . '/host*.conf') as $c) {
$m = @filemtime($c);
if ($m && ($confAge === null || (time() - $m) < $confAge)) $confAge = time() - $m;
}
// Storage mode as a fact about where this install actually is, not as the conf toggle's word
// for it — the toggle is what someone intended and the path is what happened.
//
// "internal", not "flash". /boot is the internal mode in Varaverk's own vocabulary and on this
// hardware it is a mirrored NVMe pool, not a USB stick; calling it flash on the dashboard
// would invite a write-wear worry that does not apply here.
$internal = str_starts_with(SCRIPTS_DIR, '/boot');
return [
'cache_root' => VV_CACHE_ROOT,
'cache_bytes' => $du(VV_CACHE_ROOT),
'data_bytes' => $du(DATA_DIR),
'scripts_dir' => SCRIPTS_DIR,
'storage' => $internal ? 'internal' : 'appdata',
'commit' => trim((string)shell_exec(
'git -C ' . escapeshellarg(SCRIPTS_DIR) . ' rev-parse --short HEAD 2>/dev/null')),
'jobs_running' => $running,
'locks_stale' => $stale,
'conf_age_sec' => $confAge,
];
}
function vv_scripts_status(): array { function vv_scripts_status(): array {
$logDir = LOG_DIR; $logDir = LOG_DIR;
$statFiles = array_merge( $statFiles = array_merge(
+61
View File
@@ -949,6 +949,55 @@ function vvPollMonitor(live) {
: '—'; : '—';
const _coreMeta = _threadInfo ? ` <span style="color:#444;">(${_threadInfo})</span>` : ''; const _coreMeta = _threadInfo ? ` <span style="color:#444;">(${_threadInfo})</span>` : '';
// ── Varaverk's own footprint ────────────────────────────────────────────
// The rows above describe the machine. These describe the thing whose dashboard this is,
// and nothing else on the page reports them.
const vv = d.varaverk ?? {};
const _rootPct = d.watchdog?.stability?.rootfs_pct ?? null;
// The cache is RAM, not disk: VV_CACHE_ROOT is /tmp/varaverk and /tmp lives on rootfs, which
// on Unraid is a memory filesystem. Shown against the rootfs percentage because a size with
// no ceiling beside it is a number nobody can act on.
// Local formatters. vvFmt() is a GB formatter — feeding it megabytes prints "186 GB" — and
// vvRelTime() takes a timestamp where these carry an age in seconds. Both would have been
// silently wrong rather than broken.
const _vvSize = b => b == null ? '—'
: b >= 1073741824 ? (b / 1073741824).toFixed(1) + ' GB' : Math.round(b / 1048576) + ' MB';
const _vvAge = s => s == null ? '—'
: s < 90 ? s + 's' : s < 5400 ? Math.round(s / 60) + 'm'
: s < 172800 ? Math.round(s / 3600) + 'h' : Math.round(s / 86400) + 'd';
const _cacheColor = _rootPct == null ? '#888'
: _rootPct >= 90 ? '#f44336' : _rootPct >= 75 ? '#ff9800' : '#888';
// The suffix belongs to a real figure. "— in RAM" reads as a measurement that came back
// empty rather than one that was never taken.
const _cacheStr = vv.cache_bytes == null
? `<span style="color:#555;">not measured</span>`
: `${_vvSize(vv.cache_bytes)}<span style="color:#444;"> in RAM`
+ (_rootPct != null ? ` · rootfs ${_rootPct}%` : '') + `</span>`;
const _dataStr = vv.data_bytes == null
? `<span style="color:#555;">not measured</span>`
: `${_vvSize(vv.data_bytes)}<span style="color:#444;"> on ${vvEscHtml(vv.storage || '?')}</span>`;
// Jobs actually running — locks whose process is alive. A stale lock is not a running job
// and acquire_lock() clears it on the next run, so it is reported as an aside rather than
// as a fault.
const _jobs = vv.jobs_running ?? [];
const _jobStr = _jobs.length === 0
? `<span style="color:#555;">idle</span>`
: `<span style="color:#4caf50;">${_jobs.length} running</span>`
+ `<span style="color:#444;"> · ${vvEscHtml(_jobs.slice(0, 2).join(', '))}`
+ (_jobs.length > 2 ? ` +${_jobs.length - 2}` : '') + `</span>`;
const _staleStr = (vv.locks_stale ?? 0) > 0
? `<span style="color:#3a3a3a;"> · ${vv.locks_stale} stale lock${vv.locks_stale !== 1 ? 's' : ''}</span>` : '';
// Conf sync freshness. An age climbing past its schedule means the mesh has stopped talking,
// which no other row on this page would show.
const _confAge = vv.conf_age_sec;
const _confStr = _confAge == null ? `<span style="color:#555;">none cached</span>`
: `<span style="color:${_confAge > 172800 ? '#ff9800' : '#888'};">${_vvAge(_confAge)} ago</span>`;
document.getElementById('vv-system-body').innerHTML = document.getElementById('vv-system-body').innerHTML =
`<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:8px;"> `<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:8px;">
<div style="min-width:0;"> <div style="min-width:0;">
@@ -988,6 +1037,18 @@ function vvPollMonitor(live) {
<span style="color:#444;">Load</span> <span style="color:${_loadColor};">${_loadStr}</span> <span style="color:#444;">Load</span> <span style="color:${_loadColor};">${_loadStr}</span>
<span style="color:#444;">Running</span> <span style="color:#888;">${_runningCtrs} ctr${_runningCtrs !== 1 ? 's' : ''}${_runningVMs > 0 ? ` · ${_runningVMs} VM` : ''}</span> <span style="color:#444;">Running</span> <span style="color:#888;">${_runningCtrs} ctr${_runningCtrs !== 1 ? 's' : ''}${_runningVMs > 0 ? ` · ${_runningVMs} VM` : ''}</span>
<span style="color:#444;">Version</span> <span style="color:#3a3a3a;">${ver}</span> <span style="color:#444;">Version</span> <span style="color:#3a3a3a;">${ver}</span>
</div>
<!-- Varaverk's own figures, ruled off from the host's. Same grid so the labels line up,
separate block so it reads as a different subject rather than more of the same. -->
<div style="border-top:1px solid #1e1e1e;margin-top:8px;padding-top:7px;">
<div style="font-size:9px;color:#333;text-transform:uppercase;letter-spacing:.07em;margin-bottom:5px;">Varaverk</div>
<div style="display:grid;grid-template-columns:auto 1fr;gap:3px 8px;font-size:11px;">
<span style="color:#444;">Cache</span> <span style="color:${_cacheColor};">${_cacheStr}</span>
<span style="color:#444;">Data</span> <span style="color:#888;">${_dataStr}</span>
<span style="color:#444;">Jobs</span> <span>${_jobStr}${_staleStr}</span>
<span style="color:#444;">Conf</span> <span>${_confStr}</span>
<span style="color:#444;">Build</span> <span style="color:#3a3a3a;font-family:monospace;">${vvEscHtml(vv.commit || '—')}</span>
</div>
</div>`; </div>`;
// ── Partner ────────────────────────────────────────────────────────────── // ── Partner ──────────────────────────────────────────────────────────────