Fallback coverage: colour the wait, group by tier, and lock the stacks the partner already runs

This commit is contained in:
Gmer4Lfe
2026-08-22 09:33:06 -04:00
parent 5d42a28d34
commit 1c38abe1d0
2 changed files with 172 additions and 29 deletions
+45
View File
@@ -88,6 +88,30 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
}
sort($containers, SORT_NATURAL | SORT_FLAG_CASE);
// Containers the partner already runs continuously, because onboard deployed them there.
// They cannot be failover material: there is nothing to start during an outage that is not
// already up, and a tier assignment for one would be a delay applied to a running container.
//
// The stacks store XML template filenames, and their case does not have to agree with the
// container's — this conf ships "my-prowlarr.xml" against a container named "Prowlarr" — so
// the mapping is done case-insensitively, once, here.
$stackOf = [];
$byLower = [];
foreach ($containers as $n) $byLower[strtolower($n)] = $n;
foreach ([
'auth' => "{$hostUp}_PARTNERSHIP_AUTH_STACK",
'arrs' => "{$hostUp}_PARTNERSHIP_ARR_STACK",
'services' => "{$hostUp}_PARTNERSHIP_SERVICES_STACK",
] as $label => $var) {
foreach (vv_parse_conf_list($raw, $var) as $xml) {
$n = preg_replace('/^my-|\.xml$/', '', trim($xml));
if ($n === '') continue;
// The container's real name where this host has one, the template's otherwise: a
// stack entry for something not installed here is still a stack entry.
$stackOf[$byLower[strtolower($n)] ?? $n] = $label;
}
}
// Named in a tier but not installed here. Reported rather than filtered: a tier entry for a
// container that does not exist is a line fallback.sh fails on during an outage, which is
// the worst possible moment to find a typo.
@@ -100,6 +124,7 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
'host' => $hostUp,
'containers' => $containers,
'cover' => (object)$cover,
'stacks' => (object)$stackOf,
'missing' => $missing,
'tier_vars' => array_map($tierVar, $TIERS),
]);
@@ -125,6 +150,22 @@ foreach ($TIERS as $t) {
}
}
// Stack containers refused here, not only greyed out in the picker. The card disables their
// selects, but a disabled input is a courtesy to the operator, not a constraint on the endpoint —
// and a tier assignment for a container the partner already runs permanently is a delay attached
// to something that never stops.
$stackNames = [];
foreach ([
"{$hostUp}_PARTNERSHIP_AUTH_STACK",
"{$hostUp}_PARTNERSHIP_ARR_STACK",
"{$hostUp}_PARTNERSHIP_SERVICES_STACK",
] as $var) {
foreach (vv_parse_conf_list($existingRaw, $var) as $xml) {
$n = preg_replace('/^my-|\.xml$/', '', trim($xml));
if ($n !== '') $stackNames[strtolower($n)] = true;
}
}
$map = json_decode((string)($_POST['tiers'] ?? ''), true);
if (!is_array($map)) { echo json_encode(['ok' => false, 'error' => 'tiers must be an object']); exit; }
@@ -137,6 +178,10 @@ foreach ($map as $name => $tier) {
if (!isset($known[strtolower((string)$name)])) {
echo json_encode(['ok' => false, 'error' => "No container named $name on this host"]); exit;
}
if (isset($stackNames[strtolower((string)$name)])) {
echo json_encode(['ok' => false,
'error' => "$name is deployed to the partner as part of a stack — it already runs there, so it cannot be given a fallback tier"]); exit;
}
$byTier[$t][] = $known[strtolower((string)$name)];
}