Reported: installed from the ISO, files present, but the kiosk setup never appeared on first boot. Cause: kiosk-firstboot.service had After=cloud-final.service, and on 26.04 cloud-final.service is After=multi-user.target - while multi-user.target, which wants kiosk-firstboot, is implicitly After= it. An ordering cycle; systemd breaks it at boot by deleting a job, and kiosk-firstboot's was the one to go. systemd-analyze verify against the 26.04.1 ISO's own units reproduces it: Found ordering cycle: kiosk-firstboot.service/start after cloud-final.service/start after multi-user.target/start - after kiosk-firstboot.service - Drop After=cloud-final.service. The script's `cloud-init status --wait` goes too: cloud-final waits for multi-user.target, which waits for this service - it would deadlock. DPkg::Lock::Timeout already covers what it was guarding against (dpkg lock contention). - Drop Conflicts=getty@tty1.service: getty.target pulls getty@tty1 into the same boot transaction, and a conflict between two wanted jobs is also resolved by dropping one. Before=getty@tty1 alone keeps tty1's login prompt waiting until this oneshot finishes. Verified: systemd-analyze verify of kiosk-firstboot + multi-user.target + cloud-final + cloud-init.target + getty@tty1 + graphical.target in the 26.04.1 server filesystem - old unit reports the cycle, fixed unit is clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cjz8a58eB5P9sUweqd3NHm
44 lines
1.9 KiB
Desktop File
44 lines
1.9 KiB
Desktop File
# Installed by the custom ISO (iso/build-iso.sh) and enabled from its
|
|
# autoinstall late-commands. Runs install.sh once, on tty1, the first
|
|
# time the freshly installed system boots - ordered before getty@tty1,
|
|
# so the login prompt only appears on tty1 once this has finished and
|
|
# an interactive install has the keyboard and screen to itself. /var/lib/kiosk-firstboot/pending is removed once the install
|
|
# finishes, so this is a no-op on every boot after that; an interrupted
|
|
# or failed install leaves it in place and simply runs again next boot.
|
|
#
|
|
# Ordering, learned the hard way on 26.04:
|
|
# - NOT After=cloud-final.service: cloud-final is After=multi-user.target,
|
|
# and multi-user.target (which wants this unit) is After= it - an
|
|
# ordering cycle, which systemd "fixes" at boot by dropping a job: this
|
|
# one, so the install silently never ran. (The script doesn't wait for
|
|
# cloud-init either, for the same reason - it would deadlock.)
|
|
# - NOT Conflicts=getty@tty1: getty.target pulls getty@tty1 into the same
|
|
# boot transaction, and systemd resolves a conflict between two wanted
|
|
# jobs by dropping one. Before= alone is enough - getty@tty1 waits for
|
|
# this oneshot to finish.
|
|
[Unit]
|
|
Description=Ubuntu Based Kiosk first-boot install
|
|
After=network-online.target systemd-user-sessions.service plymouth-quit-wait.service
|
|
Wants=network-online.target
|
|
Before=getty@tty1.service
|
|
ConditionPathExists=/var/lib/kiosk-firstboot/pending
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/sbin/kiosk-firstboot
|
|
# Belt and braces for the temporary sudoers/apt drop-ins when install.sh
|
|
# reboots out from under the script (its own EXIT trap normally does this).
|
|
ExecStopPost=/usr/local/sbin/kiosk-firstboot --cleanup
|
|
StandardInput=tty-force
|
|
StandardOutput=tty
|
|
StandardError=tty
|
|
TTYPath=/dev/tty1
|
|
TTYReset=yes
|
|
TTYVHangup=yes
|
|
TimeoutStartSec=infinity
|
|
TimeoutStopSec=30
|
|
KillMode=mixed
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|