From 266a80181a4dab7189005019616e1c4d5479a8ec Mon Sep 17 00:00:00 2001 From: Garrett Allen <98648590+Gerrrt@users.noreply.github.com> Date: Sat, 5 Sep 2026 04:45:20 +0000 Subject: [PATCH] fix(validate): the homelab-* timers are the estate's, not every host's (#263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `make validate` on `alexander` failed the moment the lab stack came up: FAIL the stack runs here but no homelab-* units are installed — run 'make install-timers' (#215) Both halves of that are wrong on that host. #263 widened the deployment-host test from "is the observability stack running" to stack_running(), which asks whether ANY stack is — correct for the question it was given, and the wrong question. The timers are the estate's maintenance: converge runs `make up`, which is STACK=observability; snmp-verify polls devices the lab does not have; backup-firewall ships to a host 30 -> 99 cannot reach; dashboards-drift exports the estate's seven dashboards. None of them are work the lab guest should do. And the advice cannot be followed. Every unit's ExecStart hardcodes /home/robo/code/Gerrrt/HomeLab, and install-timers.sh refuses to install anywhere but that checkout — so the fix the failure names is refused by the next command. A dead end pointing at work that should never happen there. The gate is the path the units already carry. install-timers.sh asserts every ExecStart and WorkingDirectory agrees with its DEPLOY_ROOT, so that path IS the definition of "the host these timers belong to" and can be read out of systemd/*.service rather than restated here as a third literal that would drift from the other two. On the monitoring host's deploy checkout the check is unchanged and still fails when the stack runs with no units installed, which is what #215 asked for. On the lab guest, and in a worktree, it now skips and says whose jobs those are. Found by following the build runbook on the real guest. Co-Authored-By: Claude Opus 5 --- scripts/validate.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scripts/validate.sh b/scripts/validate.sh index 86462d5..6d787bc 100755 --- a/scripts/validate.sh +++ b/scripts/validate.sh @@ -56,6 +56,27 @@ have_docker() { have docker && docker info >/dev/null 2>&1; } # deployment host, which was previously "is the observability stack running". # The lab stack runs on its own guest, and a host running only that one is # still a deployment host with timers to install. +# The checkout the committed units point at. +# +# Every ExecStart in systemd/*.service is an absolute path into the deployment +# checkout, and install-timers.sh asserts they all agree with its DEPLOY_ROOT — +# so the path baked into the units IS the definition of "the host these timers +# belong to", and it can be read rather than restated as a third literal. +# +# This gate was missing, and the check below therefore fired on `alexander` the +# first time the lab stack came up: stack_running() asks whether ANY stack runs +# here, which #263 widened it to do, and the timers are the ESTATE's — converge +# runs `make up` (STACK=observability), snmp-verify polls devices the lab does +# not have, backup-firewall ships to a host 30 -> 99 cannot reach. So a +# perfectly healthy lab guest was told to run `make install-timers`, which +# install-timers.sh then refuses because the units name a checkout that is not +# there. A failure whose advice is refused by the next command is a dead end, +# and it was pointing at work that should never happen on that host. +unit_deploy_root() { + sed -n 's|^ExecStart=\(.*\)/scripts/run-scheduled\.sh .*|\1|p' \ + "${REPO_ROOT}"/systemd/*.service | head -1 +} + stack_running() { local stack for stack in "${STACKS[@]}"; do @@ -543,6 +564,8 @@ if ! have systemctl; then skip "systemctl absent — cannot tell whether the schedule is installed" elif ! have_docker; then skip "docker unavailable — cannot tell whether this is the deployment host" +elif [[ "${REPO_ROOT}" != "$(unit_deploy_root)" ]]; then + skip "the homelab-* units name $(unit_deploy_root), not this checkout — their jobs are not this host's" elif ! stack_running; then skip "no stack is running here — this is not a deployment host" elif systemctl list-unit-files 'homelab-*' --no-legend 2>/dev/null | grep -q .; then