From 7b4794211de22585d7aeb04e29a7332c95970ca2 Mon Sep 17 00:00:00 2001 From: beatzaplenty Date: Wed, 29 Jul 2026 13:53:02 +1000 Subject: [PATCH] fix(gc-hosts): fix pve1 PATH and discovery sudo prompts Two bugs: 1. Dynamic discovery used BatchMode=yes for the pct/qm list SSH call, which silently suppressed any sudo password prompt and returned empty output. Fix: split SSH_OPTS into SSH_OPTS (BatchMode, for gc) and SSH_QUERY_OPTS (no BatchMode, for discovery) so sudo can prompt when needed. 2. pve1 gc used a non-login SSH session which doesn't source /etc/profile, so nix-collect-garbage was never on PATH. The Nix installer registers itself via /etc/profile.d/nix-daemon.sh which only runs in login shells. Fix: use "bash -l -c 'nix-collect-garbage -d'" instead. Co-Authored-By: Claude Sonnet 4.6 --- scripts/gc-hosts.sh | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/scripts/gc-hosts.sh b/scripts/gc-hosts.sh index 3a87cd0..e884ad9 100755 --- a/scripts/gc-hosts.sh +++ b/scripts/gc-hosts.sh @@ -14,8 +14,8 @@ # "nix-collect-garbage -d" if sudo needs a password — still collects # unreferenced store paths and old nixos-user profile generations, but leaves # old system generations in place. -# pve1: runs "nix-collect-garbage -d" as the login user (no system generations -# on a non-NixOS host). +# pve1: runs "bash -l -c nix-collect-garbage -d" as the login user so +# /etc/profile is sourced and the Nix daemon's PATH is set up automatically. # # Usage (from repo root): # bash scripts/gc-hosts.sh [--dry-run] @@ -30,7 +30,12 @@ source scripts/lib/nix-eval.sh 2>/dev/null || true : "${MAX_JOBS:=8}" : "${NIXOS_USER:=nixos}" : "${PVE1_SSH_USER:=${PROXMOX_SSH_USER:-wayne}}" + +# GC connections use BatchMode — no interactive prompts, just succeed or fail. SSH_OPTS=(-o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=10) +# Discovery connections do NOT use BatchMode so that sudo can prompt if needed +# (pct/qm list require root access on Proxmox). +SSH_QUERY_OPTS=(-o StrictHostKeyChecking=no -o ConnectTimeout=10) DRY_RUN=0 for arg in "$@"; do @@ -44,7 +49,7 @@ done # ORDERED_HOSTS: names in display/execution order. # HOST_TARGET[name]: SSH target string (user@host). -# HOST_TYPE[name]: "nixos" (try sudo gc, fallback user) | "nix" (user gc only). +# HOST_TYPE[name]: "nixos" (try sudo gc, fallback user) | "nix" (login-shell gc). declare -a ORDERED_HOSTS=() declare -A HOST_TARGET=() declare -A HOST_TYPE=() @@ -78,10 +83,10 @@ if ! hostname_map="$( echo " warning: flake eval failed — skipping dynamic host discovery" >&2 fi -# Get names of all currently running guests from pve1. -if ssh "${SSH_OPTS[@]}" "${PVE1_SSH_USER}@${PVE1_HOST}" "true" 2>/dev/null; then +# SSH_QUERY_OPTS (no BatchMode) so sudo can prompt if wayne's sudo needs a password. +if ssh "${SSH_QUERY_OPTS[@]}" "${PVE1_SSH_USER}@${PVE1_HOST}" "true" 2>/dev/null; then running_guests="$( - ssh "${SSH_OPTS[@]}" "${PVE1_SSH_USER}@${PVE1_HOST}" bash <<'REMOTE' + ssh "${SSH_QUERY_OPTS[@]}" "${PVE1_SSH_USER}@${PVE1_HOST}" bash <<'REMOTE' { sudo pct list 2>/dev/null | awk 'NR>1 && $2=="running" { print $NF }'; sudo qm list 2>/dev/null | awk 'NR>1 && $3=="running" { print $2 }'; } | sort -u REMOTE @@ -95,7 +100,7 @@ REMOTE | jq -r --arg g "$guest" '.[$g] // empty' 2>/dev/null || true)" [[ -z "$hostname" ]] && continue - # Exclude nix-cache and any target whose hostname is already in our list. + # Exclude nix-cache and any hostname already in the list. case "$hostname" in nix-cache) continue ;; esac if [[ -n "${_SEEN_HOSTNAMES[$hostname]+_}" ]]; then continue; fi @@ -121,7 +126,7 @@ if [[ "$DRY_RUN" -eq 1 ]]; then echo " ssh ${SSH_OPTS[*]} $target 'sudo -n nix-collect-garbage -d'" echo " # fallback: ssh ... $target 'nix-collect-garbage -d'" else - echo " ssh ${SSH_OPTS[*]} $target '. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && nix-collect-garbage -d'" + echo " ssh ${SSH_OPTS[*]} $target 'bash -l -c nix-collect-garbage -d'" fi done exit 0 @@ -147,10 +152,10 @@ gc_one() { echo "ok(user)"; return fi else - # Non-NixOS node: BatchMode SSH doesn't source the Nix daemon profile, so - # nix-collect-garbage won't be on PATH unless we source it explicitly. - local nix_profile='. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh 2>/dev/null || true' - if ssh "${SSH_OPTS[@]}" "$target" "$nix_profile && nix-collect-garbage -d" \ + # Non-NixOS node: use a login shell so /etc/profile is sourced and the + # Nix daemon's bin dir is on PATH (set up by /etc/profile.d/nix-daemon.sh + # which the Nix installer adds to /etc/profile). + if ssh "${SSH_OPTS[@]}" "$target" "bash -l -c 'nix-collect-garbage -d'" \ >>"$logfile" 2>>"$logfile"; then echo "ok"; return fi