ask what the machine is for, once, in pre-flight
MACHINE_ROLE is homelab, vps or dev, and several steps have a different right answer per role with no way to work it out themselves: whether the address is yours to pin (static IP), whether the box faces the open internet (fail2ban, SSH hardening, UFW), and whether it is allowed to sleep (suspend, logind). Asked in pre-flight rather than at each point of use. The steps that care run from swap through to the firewall, and being asked "is this a VPS?" for the fourth time halfway down a provisioning run is how people start answering without reading. The default offered is guessed from whether this machine's own address is in RFC1918 space, which beats asking whether it is virtualised — a homelab is very often a VM on Proxmox and would be misread as rented — and is the same fact most of the branches turn on anyway. A graphical session means dev; so does macOS. It is only ever a suggestion the user confirms. MACHINE_ROLE in the environment answers it ahead of time for an unattended run, which is why it is declared with :- rather than a plain assignment. The first version wiped the caller's value before ask_machine_role ever saw it; caught by running with MACHINE_ROLE=vps and watching the menu appear anyway. Verified: guesses vps on this host (public IPv4, no DISPLAY, no display manager), env override takes, and a bad value fails with the three valid ones named. Nothing consumes the role yet — the steps get wired as each is worked through. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,19 @@ PM="" # apt | pacman | dnf | brew
|
|||||||
ARCH="" # amd64 | arm64, normalised — upstream tarballs disagree on spelling
|
ARCH="" # amd64 | arm64, normalised — upstream tarballs disagree on spelling
|
||||||
IS_WSL=false
|
IS_WSL=false
|
||||||
|
|
||||||
|
# What this box is FOR. Asked once in pre-flight and consulted by the steps
|
||||||
|
# afterwards, because several of them have a different right answer per role and
|
||||||
|
# no way to work it out on their own:
|
||||||
|
#
|
||||||
|
# homelab a machine you physically control on a network you own
|
||||||
|
# vps rented, public IP, someone else's DHCP and console
|
||||||
|
# dev a laptop or desktop you sit at
|
||||||
|
#
|
||||||
|
# Set MACHINE_ROLE in the environment to answer it ahead of time — hence the
|
||||||
|
# :- default rather than a plain assignment, which would wipe what the caller
|
||||||
|
# passed in before ask_machine_role ever looked at it.
|
||||||
|
MACHINE_ROLE="${MACHINE_ROLE:-}"
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Output
|
# Output
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -207,3 +220,87 @@ detect_os() {
|
|||||||
[[ -n "$OS" ]] || fail "Could not identify this distribution (no readable /etc/os-release)."
|
[[ -n "$OS" ]] || fail "Could not identify this distribution (no readable /etc/os-release)."
|
||||||
[[ -n "$OS_NAME" ]] || OS_NAME="$OS${OS_VERSION:+ $OS_VERSION}"
|
[[ -n "$OS_NAME" ]] || OS_NAME="$OS${OS_VERSION:+ $OS_VERSION}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Machine role
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# The interface packets actually leave by, which is not always the first one up.
|
||||||
|
default_iface() {
|
||||||
|
ip route get 8.8.8.8 2>/dev/null | awk '{for (i = 1; i <= NF; i++) if ($i == "dev") {print $(i + 1); exit}}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# A default for the question below — a suggestion the user confirms, never a
|
||||||
|
# decision taken on their behalf.
|
||||||
|
#
|
||||||
|
# The signal that separates homelab from vps is whether this machine's own
|
||||||
|
# address is in RFC1918 space. That is a better test than asking whether it is
|
||||||
|
# virtualised, because a homelab is very often a VM on Proxmox and would be
|
||||||
|
# misread as rented; and it is the same fact that decides most of what the role
|
||||||
|
# is consulted for — whether the address is yours to pin, and whether the box is
|
||||||
|
# exposed to the open internet.
|
||||||
|
guess_machine_role() {
|
||||||
|
# Nothing here is a server. It is the machine you are sitting at.
|
||||||
|
if [[ "$OS" == "macos" ]]; then
|
||||||
|
echo dev
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A graphical session means someone sits at this one too.
|
||||||
|
if [[ -n "${DISPLAY:-}" ]] || systemctl list-unit-files 2>/dev/null | grep -qE '^(gdm3?|sddm|lightdm)\.service'; then
|
||||||
|
echo dev
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local ip
|
||||||
|
ip="$(ip -4 addr show "$(default_iface)" 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)"
|
||||||
|
case "$ip" in
|
||||||
|
10.* | 192.168.* | 172.1[6-9].* | 172.2[0-9].* | 172.3[01].*) echo homelab ;;
|
||||||
|
"") echo homelab ;; # no address to judge by: assume the safer of the two
|
||||||
|
*) echo vps ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ask what this machine is, unless the environment already said.
|
||||||
|
#
|
||||||
|
# Asked in pre-flight rather than at the point of use so that the run knows its
|
||||||
|
# own shape before it starts: the steps that care are spread from swap through to
|
||||||
|
# the firewall, and being asked "is this a VPS?" for the fourth time halfway down
|
||||||
|
# a provisioning run is how people start answering without reading.
|
||||||
|
ask_machine_role() {
|
||||||
|
if [[ -n "$MACHINE_ROLE" ]]; then
|
||||||
|
case "$MACHINE_ROLE" in
|
||||||
|
homelab | vps | dev) return ;;
|
||||||
|
*) fail "MACHINE_ROLE must be homelab, vps or dev — got '$MACHINE_ROLE'" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
local guess choice
|
||||||
|
guess="$(guess_machine_role)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
info "What is this machine?"
|
||||||
|
echo " [1] homelab — yours, on a network you control"
|
||||||
|
echo " [2] vps — rented, public IP, provider's DHCP and console"
|
||||||
|
echo " [3] dev — a laptop or desktop you sit at"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
case "$guess" in
|
||||||
|
homelab) choice=1 ;;
|
||||||
|
vps) choice=2 ;;
|
||||||
|
dev) choice=3 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
prompt_value MACHINE_ROLE_CHOICE "Pick a number" "$choice"
|
||||||
|
|
||||||
|
case "$MACHINE_ROLE_CHOICE" in
|
||||||
|
1 | homelab) MACHINE_ROLE=homelab ;;
|
||||||
|
2 | vps) MACHINE_ROLE=vps ;;
|
||||||
|
3 | dev) MACHINE_ROLE=dev ;;
|
||||||
|
*) fail "Not one of the options: '$MACHINE_ROLE_CHOICE'" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convenience for the steps that branch on it.
|
||||||
|
is_role() { [[ "$MACHINE_ROLE" == "$1" ]]; }
|
||||||
|
is_server() { [[ "$MACHINE_ROLE" == "homelab" || "$MACHINE_ROLE" == "vps" ]]; }
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ case "$PM" in
|
|||||||
*) fail "${OS_NAME} uses ${PM}, which this script does not implement yet — apt-based systems only, so far." ;;
|
*) fail "${OS_NAME} uses ${PM}, which this script does not implement yet — apt-based systems only, so far." ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
ask_machine_role
|
||||||
|
info "Role: ${MACHINE_ROLE}"
|
||||||
|
|
||||||
if [[ -f "$PROGRESS_FILE" ]]; then
|
if [[ -f "$PROGRESS_FILE" ]]; then
|
||||||
DONE_COUNT=$(wc -l < "$PROGRESS_FILE")
|
DONE_COUNT=$(wc -l < "$PROGRESS_FILE")
|
||||||
echo -e "${YELLOW} Resuming — $DONE_COUNT step(s) already completed${NC}"
|
echo -e "${YELLOW} Resuming — $DONE_COUNT step(s) already completed${NC}"
|
||||||
|
|||||||
Reference in New Issue
Block a user