Files
Varaverk/Plugin/unraid/api/monitor_remote.php
T
Gmer4Lfe 987313e7dc Document the PHP api layer and fix what documenting it exposed
Writing down what each endpoint actually guarantees made the places it
didn't obvious — shell arguments reaching a crontab or a bash -c
unescaped, master.conf written without tmp+rename, and conf edits that
could be saved without ever being parsed.
2026-08-02 10:11:39 -04:00

67 lines
3.5 KiB
PHP

<?php
// ═══════════════════════════════════════════════════════════════════════════════════════════════
// PURPOSE
// Remote node metrics endpoint. The monitor page's partner cards — CPU, memory, storage,
// uptime and container counts for every host other than this one.
//
// OPERATIONAL MODEL
// Split from monitor.php on cost, not on subject. Local metrics are cheap file reads;
// remote metrics are SSH round trips to every partner. Keeping them on separate URLs lets
// the page poll local stats often and remote stats rarely, and lets a dark partner slow
// only its own request. Served from a 1-hour cache by default; ?live bypasses it for the
// page's explicit refresh button.
//
// DESIGN PRINCIPLES
// The cache is the default and the live call is the exception.
// An hour is deliberately long. Partner hardware stats do not move fast enough to
// justify paying SSH latency on every page load, and the refresh button exists for the
// moment someone actually needs current numbers.
//
// Every payload carries its own timestamp.
// ts is written into the cached document, so the page can render the age rather than
// presenting hour-old numbers as current.
//
// The live path writes the cache too.
// A manual refresh benefits every subsequent visitor instead of being discarded.
//
// OPERATIONAL SAFEGUARDS
// Cache miss is distinguished from empty payload.
// vv_cache_read() returns null on a miss, expiry, or unparseable file, and the check is
// an explicit !== null. A legitimately empty result — the single-host case, where there
// are no remote hosts at all — is served from cache rather than being mistaken for a
// miss and forced onto the SSH path on every single poll.
//
// Read-only over SSH. The remote commands are stat collection only; nothing is started,
// stopped, or written on a partner.
//
// Unreachable partners degrade per node inside vv_remote_hosts_stats(), so one dark host
// cannot empty the other cards.
//
// HTTP caching is disabled even though the payload is cached server-side.
// The two are not the same lever. The server-side cache has an age the page can see and
// a bypass it can trigger; a browser or proxy cache has neither, and would defeat ?live
// entirely.
//
// REQUEST
// GET served from the 3600s cache when one is present
// GET ?live bypass the cache, collect fresh, and rewrite it
//
// RESPONSE
// {"remote_hosts":{…},"ts":epoch}
//
// DEPENDS ON
// include/monitor.php vv_remote_hosts_stats(), vv_cache_read(), vv_cache_write()
// ═══════════════════════════════════════════════════════════════════════════════════════════════
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store');
require_once dirname(__DIR__) . '/include/monitor.php';
if (!isset($_GET['live'])) {
$cached = vv_cache_read('monitor_remote', 3600);
if ($cached !== null) { echo json_encode($cached); exit; }
}
$data = ['remote_hosts' => vv_remote_hosts_stats(), 'ts' => time()];
vv_cache_write('monitor_remote', $data);
echo json_encode($data);