Make host setup complete in one run, and let the installer run it
box setup-host stopped halfway when it had to add you to incus-admin: it usermod'd, printed a NOTE telling you to re-login and re-run, and exited 0 — a success-shaped no-op with no boxnet, no ACL, no box-net profile and no firewall behind it. It now re-execs itself under 'sg incus-admin' and finishes in that same invocation. The membership check was also asking the wrong question. 'id -nG "$USER"' names a user, so it reads the group database — which lists incus-admin the instant usermod returns, while the shell's own credentials still lack it (supplementary groups are fixed at login). A same-session re-run therefore passed the check and died further down on a bare permission error from incus that mentioned neither the group nor the re-login. Argless 'id -nG' asks the process what it actually holds, which is what incus checks when it opens /var/lib/incus/unix.socket. With one run now sufficient, install.sh runs the setup itself instead of printing a warning and leaving the user a command: the install reported success and 'box new' then failed on a host with no Incus. setup-host is idempotent, so doing this on every install is also how an upgraded host picks up stack changes. BOX_SKIP_SETUP_HOST=1 opts out, and a failed setup leaves the install standing and says what to re-run. Fixes #63 Fixes #64 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
84da78a2c1
commit
aad576a86a
5 changed files with 97 additions and 17 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
|
@ -3,6 +3,30 @@
|
|||
History before 0.5.0 lives in git and in [drill/RUNS.md](drill/RUNS.md),
|
||||
which records not just what changed but what each drill run proved.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`box setup-host` finishes in one run** (#63). When it had to add you to
|
||||
`incus-admin` it stopped there and told you to re-login and re-run — an
|
||||
`exit 0` that reported success having built none of the stack: no `boxnet`,
|
||||
no ACL, no `box-net` profile, no firewall. It now re-execs itself under
|
||||
`sg incus-admin` and completes in that one invocation. The membership check
|
||||
was also asking the wrong question: `id -nG "$USER"` reads the group
|
||||
database, which lists the group the moment `usermod` returns, so a
|
||||
same-session re-run passed the check with credentials that still lacked the
|
||||
group and died further down on a bare permission error from `incus`. Argless
|
||||
`id -nG` asks the process what it actually holds.
|
||||
|
||||
### Changed
|
||||
|
||||
- **`install.sh` runs the host setup itself** (#64) — it printed a warning and
|
||||
left you a command to run, so the install reported success and `box new`
|
||||
failed on a host with no Incus. Since `setup-host` is idempotent, doing this
|
||||
on every install is also how an upgraded host picks up stack changes.
|
||||
`BOX_SKIP_SETUP_HOST=1` opts out; if setup fails, the install still stands
|
||||
and says what to re-run.
|
||||
|
||||
## 0.5.0 — 2026-07-15
|
||||
|
||||
The release the project was renamed in: the repo is `heavy-duty/box`, matching
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -41,13 +41,18 @@ curl -fsSL https://raw.githubusercontent.com/heavy-duty/box/main/install.sh | ba
|
|||
```
|
||||
|
||||
Installs the tree to `~/.local/share/box` and links `box` onto your
|
||||
`PATH`. Re-run any time to upgrade — upgrading from a pre-0.4.0 install also
|
||||
retires the old `claudebox` symlink. (No `git clone` needed.)
|
||||
`PATH`, then runs the host setup below for you (it may ask for `sudo`; set
|
||||
`BOX_SKIP_SETUP_HOST=1` to opt out and run it yourself). Re-run any time to
|
||||
upgrade — upgrading re-applies the host stack, and from a pre-0.4.0 install
|
||||
also retires the old `claudebox` symlink. (No `git clone` needed.)
|
||||
|
||||
## One-time host setup (Ubuntu 24.04 / Debian 13)
|
||||
|
||||
The installer already does this. Run it directly to set up a host you
|
||||
installed with `BOX_SKIP_SETUP_HOST=1`, or to re-apply the stack by hand:
|
||||
|
||||
```sh
|
||||
box setup-host # run twice if it adds you to incus-admin (re-login between)
|
||||
box setup-host # one run is enough
|
||||
```
|
||||
|
||||
Idempotent. Installs Incus and creates the isolation stack: the `boxnet` NAT
|
||||
|
|
|
|||
7
bin/box
7
bin/box
|
|
@ -387,10 +387,11 @@ EOF
|
|||
Prepare this host to mint boxes — one time. Installs Incus and builds the
|
||||
isolation stack: the boxnet NAT bridge (resolver pinned), the box-isolate
|
||||
ACL, the box-net profile, and the firewall rules, all re-applied at boot.
|
||||
Idempotent — safe to re-run after a box upgrade to pick up stack changes.
|
||||
Idempotent — safe to re-run after a box upgrade to pick up stack changes;
|
||||
install.sh runs it for you, so this is for re-applying by hand.
|
||||
|
||||
If it has to add you to the incus-admin group it will say so and exit; log
|
||||
back in (or 'sg incus-admin') and run it again.
|
||||
One run is enough. If it has to add you to the incus-admin group it re-runs
|
||||
itself under that group — no re-login, no second invocation.
|
||||
|
||||
box setup-host
|
||||
EOF
|
||||
|
|
|
|||
|
|
@ -3,17 +3,39 @@
|
|||
# the box-net profile. Idempotent. Ubuntu 24.04 / Debian 13.
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
self="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
|
||||
here="$(dirname "$(dirname "$self")")"
|
||||
|
||||
if ! command -v incus >/dev/null; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y incus
|
||||
fi
|
||||
|
||||
if ! id -nG "$USER" | grep -qw incus-admin; then
|
||||
# Group membership is a property of THIS PROCESS's credentials, not of the group
|
||||
# database — and the two disagree for exactly as long as it matters here.
|
||||
# 'id -nG "$USER"' names a user, so it reads /etc/group and reports incus-admin
|
||||
# the instant usermod returns; the running shell's own credentials still lack
|
||||
# it, because supplementary groups are fixed at login. So the old check passed
|
||||
# on a same-session re-run, sailed into the incus calls below, and died on a
|
||||
# permission error that named neither the group nor the re-login. Argless
|
||||
# 'id -nG' asks the process what it actually holds, which is what incus checks
|
||||
# when it opens /var/lib/incus/unix.socket.
|
||||
if ! id -nG | grep -qw incus-admin; then
|
||||
sudo usermod -aG incus-admin "$USER"
|
||||
echo "NOTE: added $USER to incus-admin — re-login (or 'sg incus-admin') and re-run."
|
||||
exit 0
|
||||
# Then finish the job rather than adjourning it. Exiting 0 here was a
|
||||
# success-shaped no-op: no boxnet, no ACL, no box-net profile, no firewall —
|
||||
# and the burden of knowing that on the reader of a NOTE (#63). 'sg' runs us
|
||||
# again with the new group in our credentials, no re-login, one invocation.
|
||||
# The guard makes that at most one hop: if sg somehow lands without the
|
||||
# group, we fail loudly instead of forking forever.
|
||||
if [ -z "${BOX_SETUP_HOST_REEXEC:-}" ]; then
|
||||
echo "added $USER to incus-admin — re-running under the new group (no re-login needed)"
|
||||
export BOX_SETUP_HOST_REEXEC=1
|
||||
exec sg incus-admin -c "$(printf '%q ' bash "$self" "$@")"
|
||||
fi
|
||||
echo "ERROR: still not in incus-admin after usermod + sg." >&2
|
||||
echo " log out and back in, then re-run: box setup-host" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Storage pool + base config (safe to re-run: skipped once the pool exists).
|
||||
|
|
|
|||
42
install.sh
42
install.sh
|
|
@ -84,16 +84,44 @@ case ":$PATH:" in
|
|||
;;
|
||||
esac
|
||||
|
||||
# --- environment check -----------------------------------------------------
|
||||
if ! command -v incus >/dev/null 2>&1; then
|
||||
warn "incus was not found. box needs Incus on the host."
|
||||
warn " run the one-time host setup: $DEST/host/setup-host.sh"
|
||||
fi
|
||||
|
||||
# Record WHAT was installed, so a caller can assert it got what it asked for.
|
||||
# Without this, an installer invoked with stale env vars (the CLAUDEBOX_* names
|
||||
# retired in 0.5.0) silently falls back to the defaults and installs main —
|
||||
# and the caller drills the wrong tree, believing it drilled its branch.
|
||||
# Written BEFORE host setup: this records the install, which has now happened,
|
||||
# and it must not hinge on whether the host stack came up.
|
||||
printf '%s@%s\n' "$REPO" "$REF" > "$DEST/INSTALLED_FROM"
|
||||
|
||||
log "done ($REPO@$REF) — try: box new --name test"
|
||||
# --- host setup ------------------------------------------------------------
|
||||
# The installer finishes the job (#64). Telling the user to go run setup-host
|
||||
# was a step that read as optional and failed later as mysterious: the install
|
||||
# reports success, 'box' is on PATH, and 'box new' dies on a host with no
|
||||
# Incus, no boxnet, no profile. setup-host is idempotent by design, so doing
|
||||
# this on EVERY install is also how an upgraded host picks up stack changes —
|
||||
# the isolation fixes that ship as new firewall rules land when the tool that
|
||||
# claims them lands, instead of waiting on someone to re-run a command.
|
||||
# BOX_SKIP_SETUP_HOST=1 opts out: CI, image builds, a host set up by hand.
|
||||
setup_ok=""
|
||||
if [ -n "${BOX_SKIP_SETUP_HOST:-}" ]; then
|
||||
log "skipping host setup (BOX_SKIP_SETUP_HOST is set) — run it yourself: box setup-host"
|
||||
elif [ "$(id -u)" -ne 0 ] && ! command -v sudo >/dev/null 2>&1; then
|
||||
warn "host setup needs root and sudo was not found."
|
||||
warn " run this as root to finish: $DEST/host/setup-host.sh"
|
||||
else
|
||||
log "running one-time host setup (installs Incus + the isolation stack; may ask for sudo)"
|
||||
# </dev/null because under 'curl … | bash' this script IS stdin: a child that
|
||||
# reads stdin eats the installer's own remaining lines. sudo is unaffected —
|
||||
# it prompts on /dev/tty, so an interactive host can still authenticate.
|
||||
if bash "$DEST/host/setup-host.sh" </dev/null; then
|
||||
setup_ok=1
|
||||
else
|
||||
warn "host setup did not complete — box is installed, the host is not ready."
|
||||
warn " fix the error above and re-run: box setup-host"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$setup_ok" ]; then
|
||||
log "done ($REPO@$REF) — try: box new --name test"
|
||||
else
|
||||
log "done ($REPO@$REF) — finish with 'box setup-host', then: box new --name test"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in a new issue