Skip to content

Add unattended USB ISO end-to-end tests for Debian and Ubuntu - #731

Merged
Marketen merged 19 commits into
masterfrom
marc/debian-release-tests
Oct 8, 2026
Merged

Marketen merged 19 commits into
masterfrom
marc/debian-release-tests

Conversation

@Marketen

@Marketen Marketen commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds standalone Debian and Ubuntu workflows that install the unattended ISO end to end in QEMU. Tests only: no installer, preseed or ISO-generation code changes.

Flow

  1. Build the Debian or Ubuntu ISO with UNATTENDED=true (retried, so one mirror hiccup doesn't fail the run).
  2. Boot the exact ISO in QEMU as read-only UEFI USB media, with a blank NVMe target disk.
  3. Complete the unattended OS installation using the ISO's real bootloader and configuration.
  4. Remove the virtual USB and boot the installed system.
  5. Wait for DAppNode's first-boot self-test, then perform the required second reboot.
  6. Verify the OS version, APT repositories, packages, Docker, installation logs, and the running dappmanager container.

Making QEMU behave like real hardware

  • NVMe target disk rather than virtio-blk, matching DAppNode hardware and how the installer enumerates it next to the USB stick.
  • TAP network (test/e2e_network.sh) with DHCP, DNS and NAT. GitHub runners drop outbound ICMP, so the host answers the guest's echo requests and the first-boot ping google.com check works as on a normal LAN.
  • NIC pinned to a fixed PCI slot, so it keeps its name once the installer's USB controller is gone, as on real hardware.
  • On failure, the job uploads the serial logs, screenshots of every console (VT1–VT4), dnsmasq logs, and guest diagnostics over SSH.

The old iso job in test.yml (build both ISOs and ls them) is removed; these workflows build the same ISOs and then install them.

Current status

🤖 Generated with Claude Code

@Marketen
Marketen requested a review from a team as a code owner August 20, 2026 08:41
Comment thread .github/workflows/debian-iso-e2e.yml Fixed
Comment thread .github/workflows/ubuntu-iso-e2e.yml Fixed
Marketen and others added 13 commits August 20, 2026 11:11
This PR should be scoped to the e2e test workflows. The grub-installer/bootdev
override added in f0718d0 is a change to the shipped Debian installer, and it is
very likely a no-op for the test it was added for: the e2e harness is UEFI-only,
where GRUB installs to the ESP and bootdev is the BIOS/i386-pc question.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The preseed sets grub-installer/bootdev to "default", which also marks the
question as seen. grub-installer then takes this path:

    db_fget grub-installer/bootdev seen
    if [ "$RET" = true ] && db_get grub-installer/bootdev && [ "$RET" ]; then
            if [ "$RET" = "default" ]; then
                    bootdev=$default_bootdev

$default_bootdev is the first grub-mkdevicemap entry -- (hd0), the installer
USB itself. The safeguard against installing onto the installation media only
runs in the *:grub-pc branch, so nothing protects a UEFI install.

The EFI install still succeeds, because grub-install writes to the ESP on the
real disk, but the step then exits 1 reading the ISO9660 partition table:

    grub-installer: info: Installing grub on '/dev/sda'
    grub-installer: info: grub-install ran successfully
    main-menu: (process:10646): Can't read partition table from /dev/sda
    main-menu: WARNING **: Configuring 'grub-installer' failed with error code 1

Reuse the non-USB disk list already computed for partman. Verified by a local
QEMU UEFI USB install of the Debian 13.5.0 unattended ISO, which now completes
the installer in ~4 minutes instead of stalling on the failure dialog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A failed run only tailed the serial logs, which hold three lines of EFI stub
output because d-i draws its UI on VT1 and streams its syslog to VT4, and the
first-boot test runs on a virtual terminal via openvt. Both real failures found
so far were invisible in the artifacts.

Screendump every console instead, and dump the guest's install logs, docker
state and connectivity over SSH, which is always up by the time a first-boot
wait times out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The connectivity check was ping-only, so any network that filters ICMP failed
it. error_exit then blocks on `read` forever, .firstboot is never removed, and
the machine sits on "Check installation source. Press enter to continue".

That is not just CI: corporate, hotel and cloud networks filter ICMP too, and a
real DAppNode behind one dies the same way on its first boot. GitHub runners hit
it because Azure drops ICMP egress -- the ping_group_range sysctl in the e2e
workflows lets QEMU open the socket but cannot make the echo come back.

Fall back to an HTTPS probe, then to a bare TCP connect for the case where
neither curl nor wget is installed yet.

Verified on a local QEMU UEFI USB install of the Ubuntu 24.04.3 unattended ISO
with `iptables -A OUTPUT -p icmp --icmp-type echo-request -j DROP` applied in
the guest before the test ran: ping fails, the check passes, and the run
completes instead of stalling for the full 30 minute timeout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Debian only moves a point release into cdimage/archive once it has been
superseded, so the archive URL 404s for the current release. That broke
every automated base ISO bump (e.g. #727, debian-13.7.0). Try debian-cd
first and fall back to the archive, and drop partial downloads so a
failed attempt is not reused on the next build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restore every installer, preseed and ISO-generation file to master so
this PR only adds tests. The harness now reproduces real hardware
instead of patching the installer around QEMU:

- Install onto an NVMe disk rather than virtio-blk.
- Boot the guest on a TAP network with DHCP, DNS and NAT. GitHub
  runners drop outbound ICMP, so the host answers the guest's echo
  requests and the first-boot `ping google.com` check behaves as on a
  normal LAN.
- Read the expected Debian release from the generator and preseed
  instead of a new config file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cdimage.debian.org currently resolves to a dead mirror address part of
the time, and one bad DNS answer should not fail a 15 minute E2E run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The installer VM has a USB controller that later boots do not, which
shifted the NIC to another PCI slot and renamed it. Debian's
/etc/network/interfaces names the interface, so the installed system
never brought up its network. Pin the NIC's PCI address like real
hardware, where removing the USB stick renames nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Marketen Marketen changed the title add debian release tests in CI Add unattended USB ISO end-to-end tests for Debian and Ubuntu Oct 8, 2026
Marketen and others added 3 commits October 8, 2026 15:36
A hung installer used to burn up to 60 minutes, and a stuck first boot
another 30, before failing. Cut the limits to a few times a healthy run
(install 30 min, first-boot test 15 min, core services 10 min) and the
job timeout from 180 to 90 minutes, which still covers the worst case
of every phase plus the retried ISO build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Most of an ISO install comes from live upstream repositories, so master
can break without any PR. A weekly run against master catches that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Marketen
Marketen merged commit e7030fd into master Oct 8, 2026
14 checks passed
@Marketen
Marketen deleted the marc/debian-release-tests branch October 8, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants