Files
Varaverk/Plugin/unraid/api/watchdog.php
T

86 lines
4.8 KiB
PHP

<?php
// ═══════════════════════════════════════════════════════════════════════════════════════════════
// PURPOSE
// Watchdog data endpoint. Every watchdog's current state for every node in one document —
// resource, docker, system, storage, network and stability — together with the thresholds
// each one is judging against, for the watchdog tab's poll.
//
// OPERATIONAL MODEL
// Served from a 5-minute cache unless ?live is present. Assembling this payload reads every
// watchdog's state files and resolves every threshold out of master.conf, which is far more
// work than the tab's poll needs — the watchdogs themselves only run every 15 minutes, so a
// fresher answer would describe the same cycle.
//
// The cache is consulted before include/watchdog.php is even loaded, so a cache hit costs one
// file read and nothing else. ?live skips the read, recomputes, and writes the result back, so
// an explicit refresh also benefits the next visitor rather than being discarded.
//
// DESIGN PRINCIPLES
// Thin transport. State-file parsing and threshold resolution live in
// include/watchdog.php; this file only sets the content type and encodes.
//
// Thresholds ship with the state, not separately.
// vv_wd_all() resolves every threshold from master.conf into the same payload as the
// counters they apply to. A strike count means nothing without the limit it is counted
// against, so the page never has to fetch the two independently and risk mismatching
// them across a conf edit.
//
// The only parameter is a freshness override. ?live decides how old an answer may be, never
// what is in it — which watchdogs exist is fixed by the codebase, and no request can select,
// filter or widen the set.
//
// OPERATIONAL SAFEGUARDS
// Read-only. Nothing here clears a strike, lifts a skip-list entry, restarts a container,
// or cancels a pending reboot. The watchdogs own their own state; this endpoint reports it.
//
// Absent counters are reported quiet, not alarming.
// A watchdog that has not yet written state reads as zero rather than unknown, so a
// fresh boot does not light the page up with false strikes.
//
// Thresholds fall back to the shipped defaults.
// Every vv_wd_scalar() lookup has a ?: default, so a master.conf that is mid-edit or
// missing a key still yields a coherent payload instead of comparing counters against
// zero and declaring everything critical.
//
// Remote collection degrades per node — one unreachable partner drops that node's card and
// leaves the local host and every other partner intact.
//
// Served from cache, collected only on a miss.
// vv_wd_all() SSHes to every configured partner, so its cost is set by the slowest node
// rather than by how much data there is. Measured at 8.3s on this host with the partner unreachable —
// paid by every visitor, every 30 seconds, because the tab polls. The cache check happens
// before the heavy include, so a hit costs one file read and no SSH at all.
//
// The window is deliberately wider than the poll. Watchdog state only changes when the
// orchestrator runs, which is every 15 minutes; polling it every 30 seconds was never
// reading anything new, it was just re-paying for the same answer.
//
// REQUEST
// GET served from the 300s cache when one is present
// GET ?live bypass the cache and collect everything fresh
//
// RESPONSE
// vv_wd_all() verbatim — per-node watchdog state plus the resolved threshold set
//
// DEPENDS ON
// include/config.php vv_cache_read()
// include/watchdog.php vv_wd_all() — required only on a miss
// Tools/api_cache_writer.php writes the cache this endpoint normally serves
// ═══════════════════════════════════════════════════════════════════════════════════════════════
header('Content-Type: application/json');
require_once dirname(__DIR__) . '/include/config.php';
if (!isset($_GET['live'])) {
$_vv_cached = vv_cache_read('watchdog', 300);
if ($_vv_cached !== null) { echo json_encode($_vv_cached); exit; }
unset($_vv_cached);
}
require_once dirname(__DIR__) . '/include/watchdog.php';
$_vv_wd = vv_wd_all();
// Written on the miss as well as by the background writer. Without this the first visitor after
// a restart pays the full collection and so does the next one, until the writer's next minute
// happens to land.
vv_cache_write('watchdog', $_vv_wd);
echo json_encode($_vv_wd);