R-300: uninstall no longer leaves dnsmasq blocking the next install
gates / gates (push) Successful in 18s
gates / gates (push) Successful in 18s
Removing the snippet and restarting left dnsmasq enabled and unconstrained on 0.0.0.0:53, so the next byo install's preflight refused and the customer went debugging a home network that was never at fault. Ownership is recorded at preflight (the only moment it is a fact - the package is installed by the agent, not this script) and honoured at removal. Boxes already in the field carry no record and fail safe to restart-only, with the reason and the command logged; the preflight message covers them instead. Not observed live - no installer-v1.27.0 tag is cut. Files R-299..R-301.
This commit is contained in:
@@ -184,7 +184,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_VERSION="1.26.0" # the SINGLE version source (F-1): -h and the run banners follow it.
|
||||
SCRIPT_VERSION="1.27.0" # the SINGLE version source (F-1): -h and the run banners follow it.
|
||||
# The hub used to carry a copy for its Setup tab; R-94 DELETED it
|
||||
# (2026-08-02) because the hub cannot know which version a box runs —
|
||||
# the Setup command fetches this script at run time. scripts/
|
||||
@@ -1077,8 +1077,42 @@ run_uninstall() {
|
||||
[[ -e "$dconf" ]] || continue
|
||||
run rm -f "$dconf"; _dnsmasq_touched=true
|
||||
done
|
||||
if $_dnsmasq_touched && systemctl is-active --quiet dnsmasq 2>/dev/null; then
|
||||
run systemctl restart dnsmasq || true
|
||||
# R-300 — OUR OWN REMOVAL USED TO LEAVE THE THING THAT MAKES OUR OWN REINSTALL REFUSE.
|
||||
#
|
||||
# Removing the snippet and RESTARTING dnsmasq leaves it running UNCONSTRAINED, so it binds
|
||||
# 0.0.0.0:53 — and the next install's byo preflight hard-refuses with "a resolver is already bound
|
||||
# to :53". The customer then reads a message that looks like it is about their home network, which
|
||||
# was never at fault. Measured on demo-hp 2026-08-09; stopping and disabling it made the preflight
|
||||
# pass with nothing else changed.
|
||||
#
|
||||
# Ownership is honoured, never inferred: `dnsmasq_preexisting` is recorded at PREFLIGHT, before
|
||||
# anything is installed, which is the only moment it is a fact. Three cases, and the third is the
|
||||
# one that matters for the field:
|
||||
# no → Felhom's. Stop + disable, so a reinstall is not blocked by our own leftover.
|
||||
# yes → the owner's. Restart only (today's behaviour) — we never stop a resolver we did not install.
|
||||
# "" → NO RECORD. Every box installed before this change is here. FAIL SAFE to the owner's case:
|
||||
# restart only, exactly as before, and say why. Silently disabling a resolver on a host we
|
||||
# cannot prove we own is the one outcome worse than the wall this fixes; the preflight's
|
||||
# new message covers these boxes instead, by naming the leftover and the command.
|
||||
local _dnsmasq_owner; _dnsmasq_owner=$(_state_get dnsmasq_preexisting)
|
||||
if $_dnsmasq_touched || systemctl is-enabled --quiet dnsmasq 2>/dev/null; then
|
||||
case "$_dnsmasq_owner" in
|
||||
no)
|
||||
log_info " dnsmasq was installed by Felhom (recorded at install) — stopping + disabling it"
|
||||
run systemctl disable --now dnsmasq || true
|
||||
;;
|
||||
yes)
|
||||
log_info " dnsmasq pre-dates Felhom (recorded at install) — leaving it running, restarting only"
|
||||
systemctl is-active --quiet dnsmasq 2>/dev/null && run systemctl restart dnsmasq || true
|
||||
;;
|
||||
*)
|
||||
log_warn " dnsmasq: no ownership record for this box (installed before that was recorded)."
|
||||
log_warn " Leaving it RUNNING — we do not stop a resolver we cannot prove we installed."
|
||||
log_warn " If this host had no dnsmasq before Felhom, a reinstall will refuse on the :53"
|
||||
log_warn " gate; clear it yourself with: systemctl disable --now dnsmasq"
|
||||
systemctl is-active --quiet dnsmasq 2>/dev/null && run systemctl restart dnsmasq || true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 5. pveum removal (presence-checked; tolerate-absent; roles deleted only after their grants).
|
||||
@@ -1138,7 +1172,10 @@ run_uninstall() {
|
||||
_uninstall_statement full
|
||||
log_success "UNINSTALL complete — removed: guest $vmid, the felhom-agent (unit/sudoers/binary/state/config+baks/user + selfupdate-artifacts/shared-parent/mkfs-wrapper/pbs-apply-wrapper/hook-snippet/dnsmasq-snippets), the pveum role/user/token/ACL,$( $pool_removed && printf ' the %s pool,' "$PVE_POOL") and $STATE_FILE."
|
||||
if $REMOVE_GOLDEN; then log_info " golden vzdump: removed."; else log_info " golden vzdump: left in place (--remove-golden to remove)."; fi
|
||||
log_info " NOTE: the 'sudo' and 'dnsmasq' packages were left installed (system packages); the host record still exists in the hub — remove it there if desired."
|
||||
# R-300: the packages are still not PURGED (they are system packages and purging them on a host we
|
||||
# may not own is the wrong blast radius) — but dnsmasq's UNIT is now stopped+disabled when the
|
||||
# install-time record says Felhom installed it, so our own leftover no longer blocks our own reinstall.
|
||||
log_info " NOTE: the 'sudo' and 'dnsmasq' packages were left INSTALLED (system packages, not purged); dnsmasq's unit was stopped+disabled only if Felhom installed it. The host record still exists in the hub — remove it there if desired."
|
||||
$DRY_RUN && log_warn " DRY-RUN: nothing above was actually executed."
|
||||
return 0
|
||||
}
|
||||
@@ -1669,6 +1706,23 @@ step_preflight() {
|
||||
log_info " acl storages all present or pre-positioned: ${PVE_STORAGES[*]}"
|
||||
fi
|
||||
|
||||
# R-300 — RECORD WHETHER dnsmasq PRE-EXISTS US, HERE, BEFORE ANYTHING IS INSTALLED.
|
||||
#
|
||||
# This is the ONLY moment the question is answerable as a fact rather than a guess. The package is
|
||||
# installed later and conditionally, by the AGENT (`internal/lanresolver`, `apt-get install -y -q
|
||||
# dnsmasq`) — not by this script — so "did Felhom install it?" cannot be reconstructed at uninstall
|
||||
# time from anything on the box. Deliberately NOT inferred from a package file's mtime: that is a
|
||||
# heuristic dressed as a fact, and this project has been bitten by exactly that shape.
|
||||
#
|
||||
# Recorded on EVERY mode, because appliance is where the agent actually installs it.
|
||||
if command -v dpkg-query >/dev/null 2>&1 && dpkg-query -W -f='${Status}' dnsmasq 2>/dev/null | grep -q "install ok installed"; then
|
||||
_state_put dnsmasq_preexisting yes
|
||||
log_info " dnsmasq: already installed BEFORE Felhom — recorded; uninstall will not touch it"
|
||||
else
|
||||
_state_put dnsmasq_preexisting no
|
||||
log_info " dnsmasq: not present before Felhom — recorded; uninstall may stop+disable it if we install it"
|
||||
fi
|
||||
|
||||
# Host DNS :53 gate (byo only) — GL-8/F6. In byo the agent's own lan-resolver stays OFF (a config
|
||||
# assert enforces it), so ANY process bound to :53 is the OWNER's — and Felhom needs the guest
|
||||
# reachable by name on the LAN. Felhom must NOT stop/mask/kill a service on a host it does not own
|
||||
@@ -1681,9 +1735,21 @@ step_preflight() {
|
||||
if [[ -n "$_dns53" ]]; then
|
||||
log_error " a resolver is already bound to :53 on this host:"
|
||||
echo "$_dns53" | tr -s '[:space:]' ' ' | cut -c1-200 | sed 's/^/ /' >&2
|
||||
# R-300: the one thing this refusal lacked. A leftover of OUR OWN making reads exactly
|
||||
# like the household's resolver, and the customer goes debugging a home network that was
|
||||
# never at fault. Say so when it looks like ours, and give the exact command.
|
||||
local _hint=""
|
||||
if echo "$_dns53" | grep -q "dnsmasq"; then
|
||||
_hint="
|
||||
THIS LOOKS LIKE OURS. A previous Felhom install leaves the dnsmasq PACKAGE installed and its unit
|
||||
enabled (only our config snippet is removed), and unconstrained it binds 0.0.0.0:53 — which is what
|
||||
this gate is seeing. If this host had no dnsmasq before Felhom, clear it with:
|
||||
systemctl disable --now dnsmasq
|
||||
Then re-run this installer. If dnsmasq is YOURS, leave it and use one of the two routes above."
|
||||
fi
|
||||
die "a resolver is already bound to :53 on this host — Felhom needs the guest reachable by name on your LAN.
|
||||
Stop or reconfigure that resolver, OR point your LAN DNS at the guest's address, then re-run.
|
||||
(Felhom does NOT touch DNS services on a host it does not own — this is a refusal, not a change.)"
|
||||
(Felhom does NOT touch DNS services on a host it does not own — this is a refusal, not a change.)${_hint}"
|
||||
fi
|
||||
log_info " host DNS (:53): free"
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user