The Monitor fallback card described a state file without saying whether anything still writes it

This commit is contained in:
Gmer4Lfe
2026-08-22 01:11:00 -04:00
parent 13c221244e
commit 8ce8f0dfbe
2 changed files with 122 additions and 5 deletions
+57 -2
View File
@@ -1,5 +1,6 @@
<?php
require_once __DIR__ . '/common.php';
require_once __DIR__ . '/fallback.php'; // vv_fb_proc(), vv_fb_dryrun_state() — daemon liveness
require_once __DIR__ . '/partnership.php'; // vv_pt_peer_match() — tailnet name vs conf hostname
// ═══════════════════════════════════════════════════════════════════════════════════════════════
@@ -126,6 +127,60 @@ function vv_partner_state(): array {
];
}
// Everything below the state file: whether anything is actually running, what it would do, and
// when it last changed its mind. The card previously showed "✓ Nominal · monitoring · 30s" from
// a state file alone — the same sentence whether a daemon was checking every 30 seconds or
// nothing had run for five days.
function vv_fb_card_extra(): array {
$me = vv_detect_host();
$vars = vv_conf_vars();
// Liveness and mode, read the same way the Fallback tab reads it.
$proc = function_exists('vv_fb_proc')
? vv_fb_proc('fallback')
: ['running' => null, 'pid' => null, 'mode' => null, 'stale_lock' => false];
// A dry run keeps its own state copy, so the live file legitimately stops changing while a
// preview runs. Reported so the card can say which file it is describing.
$preview = ['state' => null, 'age' => null];
if (($proc['mode'] ?? '') === 'dry-run' && !empty($proc['pid']) && function_exists('vv_fb_dryrun_state')) {
$preview = vv_fb_dryrun_state((int)$proc['pid']);
}
$sp = STATE_DIR . '/fallback_state.db';
$lastChg = is_file($sp) ? time() - (int)@filemtime($sp) : null;
// What this host would take on if the partner went dark, and what the partner would take on
// for us. Both are counts, not lists — the card is one column wide and the Fallback tab owns
// the detail. Tier lists always live in the COVERED host's conf.
$partner = null;
foreach (vv_known_hosts() as $slot => $hostname) {
if ($slot !== $me) { $partner = $slot; break; }
}
$weCover = $theyCover = null;
if ($partner !== null && function_exists('vv_read_host_conf_raw')) {
$pRaw = vv_read_host_conf_raw($partner);
$myRaw = vv_read_host_conf_raw($me);
$count = function (string $raw, string $id): int {
$n = 0;
for ($t = 1; $t <= 4; $t++) $n += count(vv_parse_bash_array($raw, "FALLBACK_{$id}_TIER{$t}"));
return $n;
};
$weCover = $count($pRaw, strtoupper($partner)); // partner's tiers = what we start for them
$theyCover = $count($myRaw, strtoupper($me)); // our tiers = what they start for us
}
return [
'daemon' => $proc,
'preview' => $preview,
'last_change' => $lastChg,
'partner_id' => $partner !== null ? strtoupper($partner) : null,
'we_cover' => $weCover,
'they_cover' => $theyCover,
'rsync_on_handback' => ($vars['FALLBACK_RSYNC_ENABLED'] ?? 'false') === 'true',
];
}
function vv_fallback_state(): array {
$vars = vv_conf_vars();
$enabled = ($vars['FALLBACK_ENABLED'] ?? 'false') === 'true';
@@ -135,7 +190,7 @@ function vv_fallback_state(): array {
$stateFile = STATE_DIR . '/fallback_state.db';
if (!file_exists($stateFile)) {
return ['state' => 'UNKNOWN', 'enabled' => $enabled, 'check_interval' => $interval,
return vv_fb_card_extra() + ['state' => 'UNKNOWN', 'enabled' => $enabled, 'check_interval' => $interval,
'handback_strikes' => 0, 'handback_strikes_required' => $reqStrikes,
'partnership_suspended' => false,
'partner_lost_at' => 0, 'partnership_suspend_after' => $suspendAfter];
@@ -145,7 +200,7 @@ function vv_fallback_state(): array {
[$k, $v] = array_pad(explode('=', trim($line), 2), 2, '');
$raw[trim($k)] = trim($v);
}
return [
return vv_fb_card_extra() + [
'state' => $raw['state'] ?? 'UNKNOWN',
'failover_start' => $raw['failover_start'] ?? '0',
'tier2_started' => $raw['tier2_started'] ?? 'false',