fix: a watched mint must move — unbuffer the dots, name the log after the box
Operator watched /tmp/new.log through a claude mint and saw not one message: cloud-init's progress dots are block-buffered the moment stdout is not a tty, so a redirected mint shows nothing for the whole install and then one burst — which reads exactly like a hang, on the very night three real hangs happened. PYTHONUNBUFFERED=1 on the cloud-init wait makes the dots arrive as dots; box new also prints how to watch the box's own full narration (incus exec <box> -- tail -f /var/log/cloud-init-output.log); and the drill's logs are named for the box being minted (/tmp/mint-drill.log), not for the verb that mints it.
This commit is contained in:
parent
0c87911cb1
commit
c033a26979
2 changed files with 14 additions and 9 deletions
7
bin/box
7
bin/box
|
|
@ -599,6 +599,7 @@ cmd_new() {
|
||||||
"${extra[@]}"
|
"${extra[@]}"
|
||||||
wait_agent "$instance"
|
wait_agent "$instance"
|
||||||
echo "box: waiting for phase-1 (cloud-init)..."
|
echo "box: waiting for phase-1 (cloud-init)..."
|
||||||
|
echo "box: (its full narration, live: incus exec $name -- tail -f /var/log/cloud-init-output.log)"
|
||||||
# A failed cloud-init used to print a screen of dots and the word "error",
|
# A failed cloud-init used to print a screen of dots and the word "error",
|
||||||
# with nothing to act on — the box's own log holds the reason, and nobody
|
# with nothing to act on — the box's own log holds the reason, and nobody
|
||||||
# was told it existed. Show it, and leave the box up to inspect.
|
# was told it existed. Show it, and leave the box up to inspect.
|
||||||
|
|
@ -607,7 +608,11 @@ cmd_new() {
|
||||||
# drill), the session can wedge open after the remote command has exited,
|
# drill), the session can wedge open after the remote command has exited,
|
||||||
# blocking forever on a websocket that will never close. Caught live: a
|
# blocking forever on a websocket that will never close. Caught live: a
|
||||||
# mint stuck at 'status: done'. Only shell/exec/tmux may own the terminal.
|
# mint stuck at 'status: done'. Only shell/exec/tmux may own the terminal.
|
||||||
if ! incus exec "$instance" -- cloud-init status --wait </dev/null; then
|
# PYTHONUNBUFFERED: cloud-init's progress dots are block-buffered the
|
||||||
|
# moment stdout is not a tty — a redirected mint (a script, the drill)
|
||||||
|
# shows NOTHING for the whole install and then one burst at the end,
|
||||||
|
# which reads exactly like a hang. Unbuffered, the dots arrive as dots.
|
||||||
|
if ! incus exec "$instance" -- env PYTHONUNBUFFERED=1 cloud-init status --wait </dev/null; then
|
||||||
echo >&2
|
echo >&2
|
||||||
echo "box: cloud-init FAILED in $name. What it says:" >&2
|
echo "box: cloud-init FAILED in $name. What it says:" >&2
|
||||||
incus exec "$instance" -- cloud-init status --long </dev/null 2>&1 | sed 's/^/ /' >&2
|
incus exec "$instance" -- cloud-init status --long </dev/null 2>&1 | sed 's/^/ /' >&2
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ rm -rf "$badt"
|
||||||
|
|
||||||
printf '\n minting a blank box (the DEFAULT template — no tooling, fast)…\n'
|
printf '\n minting a blank box (the DEFAULT template — no tooling, fast)…\n'
|
||||||
t0=$SECONDS
|
t0=$SECONDS
|
||||||
if mint_box /tmp/tpl.log --name tpl; then
|
if mint_box /tmp/mint-tpl.log --name tpl; then
|
||||||
ok "box new --name tpl, no --template ($((SECONDS - t0))s)"
|
ok "box new --name tpl, no --template ($((SECONDS - t0))s)"
|
||||||
tt="$(incus config get tpl user.box.template 2>/dev/null)"
|
tt="$(incus config get tpl user.box.template 2>/dev/null)"
|
||||||
[ "$tt" = blank ] && ok "the default template is blank (user.box.template=blank)" \
|
[ "$tt" = blank ] && ok "the default template is blank (user.box.template=blank)" \
|
||||||
|
|
@ -424,15 +424,15 @@ if mint_box /tmp/tpl.log --name tpl; then
|
||||||
|| no "blank box cannot resolve — DNS parity broken"
|
|| no "blank box cannot resolve — DNS parity broken"
|
||||||
box rm tpl --force >/dev/null 2>&1 && ok "blank box removed" || no "could not remove the blank box"
|
box rm tpl --force >/dev/null 2>&1 && ok "blank box removed" || no "could not remove the blank box"
|
||||||
else
|
else
|
||||||
no "blank mint FAILED — tail: $(tail -3 /tmp/tpl.log | tr '\n' ' ')"
|
no "blank mint FAILED — tail: $(tail -3 /tmp/mint-tpl.log | tr '\n' ' ')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '\n minting a claude box (cold, ~10 min)…\n'
|
printf '\n minting a claude box (cold, ~10 min)…\n'
|
||||||
t0=$SECONDS
|
t0=$SECONDS
|
||||||
if mint_box /tmp/new.log --name drill --template claude; then
|
if mint_box /tmp/mint-drill.log --name drill --template claude; then
|
||||||
ok "box new --name drill --template claude ($((SECONDS - t0))s)"
|
ok "box new --name drill --template claude ($((SECONDS - t0))s)"
|
||||||
else
|
else
|
||||||
no "box new FAILED — tail: $(tail -3 /tmp/new.log | tr '\n' ' ')"
|
no "box new FAILED — tail: $(tail -3 /tmp/mint-drill.log | tr '\n' ' ')"
|
||||||
echo; echo "── cannot continue without a box"; printf ' %s\n' "${findings[@]}"; exit 1
|
echo; echo "── cannot continue without a box"; printf ' %s\n' "${findings[@]}"; exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -486,11 +486,11 @@ box info archive | grep -q authed && ok "the snapshot followed the rename" || no
|
||||||
|
|
||||||
# --- clone from a snapshot of a renamed box --------------------------------
|
# --- clone from a snapshot of a renamed box --------------------------------
|
||||||
printf '\n cloning from the snapshot…\n'
|
printf '\n cloning from the snapshot…\n'
|
||||||
if mint_box /tmp/clone.log --name clone --from archive/authed; then
|
if mint_box /tmp/mint-clone.log --name clone --from archive/authed; then
|
||||||
ok "new --from archive/authed (clone of a snapshot of a renamed box)"
|
ok "new --from archive/authed (clone of a snapshot of a renamed box)"
|
||||||
box exec clone -- true >/dev/null 2>&1 && ok "the clone is alive and enterable" || no "the clone is not enterable"
|
box exec clone -- true >/dev/null 2>&1 && ok "the clone is alive and enterable" || no "the clone is not enterable"
|
||||||
else
|
else
|
||||||
no "clone FAILED — tail: $(tail -3 /tmp/clone.log | tr '\n' ' ')"
|
no "clone FAILED — tail: $(tail -3 /tmp/mint-clone.log | tr '\n' ' ')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- the escape hatch ------------------------------------------------------
|
# --- the escape hatch ------------------------------------------------------
|
||||||
|
|
@ -517,10 +517,10 @@ wait_box archive && ok "archive is back up (agent answering)" \
|
||||||
|
|
||||||
# Sibling isolation needs a sibling. Clone from the snapshot — fast, no cold mint.
|
# Sibling isolation needs a sibling. Clone from the snapshot — fast, no cold mint.
|
||||||
printf '\n cloning a peer for the sibling probes…\n'
|
printf '\n cloning a peer for the sibling probes…\n'
|
||||||
if mint_box /tmp/peer.log --name peer --from archive/authed && wait_box peer; then
|
if mint_box /tmp/mint-peer.log --name peer --from archive/authed && wait_box peer; then
|
||||||
ok "peer minted from archive/authed and answering"
|
ok "peer minted from archive/authed and answering"
|
||||||
else
|
else
|
||||||
no "peer clone failed or never answered — tail: $(tail -3 /tmp/peer.log | tr '\n' ' ')"
|
no "peer clone failed or never answered — tail: $(tail -3 /tmp/mint-peer.log | tr '\n' ' ')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# C1 — public egress (#15 A1; resolving the hostname also proves A5, gateway DNS)
|
# C1 — public egress (#15 A1; resolving the hostname also proves A5, gateway DNS)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue