fix: no silent gap between first boot screens; keep a root password set at creation #35

Merged
marcos-mendez merged 4 commits from fix/firstboot-wait-and-keep-password into master 2026-10-02 12:18:53 -03:00
marcos-mendez commented 2026-10-02 10:50:19 -03:00 (Migrated from github.com)

What the maintainer saw

Proxmox VE 9.2.11, an LXC container from the step8 Web image, root password set in pct create. On the console he chose Generate and pressed . The console then stayed on "Did you save the password?" for a while and came back by itself.

What runs in that gap

I reproduced it on LXC (freeze-test on the test VM, root password set with chpasswd in the rootfs before first boot, tty1 driven with lxc-console -t 1 in tmux). Nothing hangs and no dialog goes to a pipe: ps -ef --forest at the gap shows run > 80keel-cloud > keelfirstboot.py cloud > dialog, with dialog's fds 0 and 1 on /dev/lxc/tty1. The gap is time in which nothing draws:

step after full CPU 0.25 CPU
boot wait before 30turnkey-init-fence, 75keel-role, 80keel-cloud (11 systemctl is-system-running each, up to 10 s of sleep each while the system is still starting) ~0.1 s ~3.5 s
75keel-role: keel inspect to find a database engine the Web image does not have 2 s 7.7 s
80keel-cloud up to its screen <1 s ~3 s
total, to Keel Cloud 2 s 15 s

On a host where the system is still starting when the wizard runs (slow units, DHCP), the boot wait adds 10 s before every hook from 30 on, 30 s before the Keel Cloud screen.

Changes

  • run: waits for a starting system once per run and stops as soon as it is up. Each first boot hook is named on the terminal while it runs, in an infobox with the first boot backtitle ("Configuring keel-role... please wait"), and so is the wait. Nothing is drawn off a terminal or with REDIRECT_OUTPUT; a notice that cannot be drawn is not an error.
  • setpass.py / Dialog.get_password(keep=...): when root can already log in with a password at first boot (passwd -S says P), the menu offers Keep first, as the default and recommendation ("Password set when the container was created (recommended)"), with Generate and Manual below. Keep is offered only for a password the image did not ship (review finding): passwd -S says P, the image carries /etc/keel/build-date (Keel-Linux/common#31, whose seal-root fails any build that does not ship root locked) and the shadow last-change day is on or after it, and the shadow field is neither empty nor U6aMy0wojraho. The field is compared, never printed or logged (asserted in every setpass test); an image without the date, such as every image built before common#31, gets no Keep. The same day counts because shadow keeps whole days and a container is often created on its image's build day. No prior password, preseeded ROOT_PASS, secrets.root_password and keel-init are unchanged. The image already ships root as * (checked in the step8 Web tar.zst).
  • Menus are drawn wide enough for their longest entry, up to 76 columns (measured on an 80 column tty1).
  • 30rootpass reads INITHOOKS_DEFAULT like the other hooks.

With the fix and confconsole's companion PR, at 0.25 CPU the gap from to Keel Cloud is 7.7 s (was 15 s), and the screen reads "Configuring ... please wait" throughout.

Tests (written first, RED on master)

  • tests/test-firstboot-pty.bats (new): run, the real 30rootpass, setpass.py and dialog on a pty under script; keys are typed when their screen reaches the pty, with a timeout on the whole run. Generate then Saved, New, Manual, Keep, Generate below Keep and a preseeded password each reach the next hook's screen. It fails on a hang and on a screen drawn into a pipe (both guards have their own test). On master, the Keep test and the notice check fail. CI installs dialog python3-dialog for it.
  • tests/test-run.bats: the boot wait happens once and ends when the system is up; notices on a terminal only, not for everyboot hooks, not with REDIRECT_OUTPUT, and a failing notice does not stop the run.
  • tests/test_setpass.py, tests/test_dialog_wrapper.py: Keep offered only for status P, first and the only recommendation, None returned, chpasswd not run, passwd failures mean no Keep, no file read, keel-init and preseed unchanged, text fits the menu.

Run: Python 405 passed locally; bats 260 locally (pty file skipped without dialog) and the pty file 8/8 inside the container.

Test plan

  • CI green (shell coverage with the pty test, Python coverage, changelog)
  • Build an image with this and confconsole keel12; first boot with pct create --password: Keep is first, Enter goes to Keel Cloud with "please wait" in between
  • Same image without a password: Generate then Saved, and Manual, unchanged and no frozen screen
## What the maintainer saw Proxmox VE 9.2.11, an LXC container from the step8 Web image, root password set in `pct create`. On the console he chose Generate and pressed <Saved>. The console then stayed on "Did you save the password?" for a while and came back by itself. ## What runs in that gap I reproduced it on LXC (freeze-test on the test VM, root password set with chpasswd in the rootfs before first boot, tty1 driven with `lxc-console -t 1` in tmux). Nothing hangs and no dialog goes to a pipe: `ps -ef --forest` at the gap shows `run` > `80keel-cloud` > `keelfirstboot.py cloud` > `dialog`, with dialog's fds 0 and 1 on `/dev/lxc/tty1`. The gap is time in which nothing draws: | step after <Saved> | full CPU | 0.25 CPU | |---|---|---| | boot wait before 30turnkey-init-fence, 75keel-role, 80keel-cloud (11 `systemctl is-system-running` each, up to 10 s of sleep each while the system is still `starting`) | ~0.1 s | ~3.5 s | | 75keel-role: `keel inspect` to find a database engine the Web image does not have | 2 s | 7.7 s | | 80keel-cloud up to its screen | <1 s | ~3 s | | **total, <Saved> to Keel Cloud** | **2 s** | **15 s** | On a host where the system is still `starting` when the wizard runs (slow units, DHCP), the boot wait adds 10 s before *every* hook from 30 on, 30 s before the Keel Cloud screen. ## Changes - `run`: waits for a starting system once per run and stops as soon as it is up. Each first boot hook is named on the terminal while it runs, in an infobox with the first boot backtitle ("Configuring keel-role... please wait"), and so is the wait. Nothing is drawn off a terminal or with `REDIRECT_OUTPUT`; a notice that cannot be drawn is not an error. - `setpass.py` / `Dialog.get_password(keep=...)`: when root can already log in with a password at first boot (`passwd -S` says `P`), the menu offers **Keep** first, as the default and recommendation ("Password set when the container was created (recommended)"), with Generate and Manual below. Keep is offered only for a password the image did not ship (review finding): `passwd -S` says `P`, the image carries `/etc/keel/build-date` (Keel-Linux/common#31, whose seal-root fails any build that does not ship root locked) and the shadow last-change day is on or after it, and the shadow field is neither empty nor `U6aMy0wojraho`. The field is compared, never printed or logged (asserted in every setpass test); an image without the date, such as every image built before common#31, gets no Keep. The same day counts because shadow keeps whole days and a container is often created on its image's build day. No prior password, preseeded `ROOT_PASS`, `secrets.root_password` and keel-init are unchanged. The image already ships root as `*` (checked in the step8 Web tar.zst). - Menus are drawn wide enough for their longest entry, up to 76 columns (measured on an 80 column tty1). - `30rootpass` reads `INITHOOKS_DEFAULT` like the other hooks. With the fix and confconsole's companion PR, at 0.25 CPU the gap from <Saved> to Keel Cloud is 7.7 s (was 15 s), and the screen reads "Configuring ... please wait" throughout. ## Tests (written first, RED on master) - `tests/test-firstboot-pty.bats` (new): `run`, the real `30rootpass`, `setpass.py` and `dialog` on a pty under `script`; keys are typed when their screen reaches the pty, with a timeout on the whole run. Generate then Saved, New, Manual, Keep, Generate below Keep and a preseeded password each reach the next hook's screen. It fails on a hang and on a screen drawn into a pipe (both guards have their own test). On master, the Keep test and the notice check fail. CI installs `dialog python3-dialog` for it. - `tests/test-run.bats`: the boot wait happens once and ends when the system is up; notices on a terminal only, not for everyboot hooks, not with `REDIRECT_OUTPUT`, and a failing notice does not stop the run. - `tests/test_setpass.py`, `tests/test_dialog_wrapper.py`: Keep offered only for status `P`, first and the only recommendation, None returned, chpasswd not run, passwd failures mean no Keep, no file read, keel-init and preseed unchanged, text fits the menu. Run: Python 405 passed locally; bats 260 locally (pty file skipped without dialog) and the pty file 8/8 inside the container. ## Test plan - [ ] CI green (shell coverage with the pty test, Python coverage, changelog) - [ ] Build an image with this and confconsole keel12; first boot with `pct create --password`: Keep is first, Enter goes to Keel Cloud with "please wait" in between - [ ] Same image without a password: Generate then Saved, and Manual, unchanged and no frozen screen
Sign in to join this conversation.
No description provided.