veilor-os/docs/research/2026-05-05-agent-wave/06-anaconda-log-capture.md
veilor-org 49a2e2557e docs: 9-agent research wave findings — v0.5.32 blocker map
Logs the full output of the 9-agent deep-dive run on 2026-05-05 to
docs/research/2026-05-05-agent-wave/. Pulls every actionable finding
into one indexed location so v0.5.32 planning has a paper trail.

Files:
  docs/research/2026-05-05-agent-wave/README.md             — index
  docs/research/2026-05-05-agent-wave/01-...real-hardware.md — Plymouth + LUKS edge cases
  docs/research/2026-05-05-agent-wave/02-...firstboot-ux.md  — SDDM + first-boot UX
  docs/research/2026-05-05-agent-wave/03-...spike-plan.md    — bootc-image-builder 1-week spike
  docs/research/2026-05-05-agent-wave/04-...tier-2.md         — AppArmor + nftables + audit + homed
  docs/research/2026-05-05-agent-wave/05-...launch.md         — threat model + v0.7 launch checklist
  docs/research/2026-05-05-agent-wave/06-...log-capture.md    — virtio-9p host-share for anaconda logs
  docs/research/2026-05-05-agent-wave/07-...skel-branding.md  — /etc/skel gap audit
  docs/research/2026-05-05-agent-wave/08-...ci-hardening.md   — SHA-pin actions + SBOM + SLSA L3
  docs/research/2026-05-05-agent-wave/09-...failure-modes.md  — real-hardware pessimistic audit

Plus the prior linter-applied:
  docs/ROADMAP.md      — Lessons learned section, v0.5.32 active block,
                          v0.6 promotion of veilor-postinstall + veilor-doctor,
                          v0.7 bootc spike scheduled
  docs/THREAT-MODEL.md  — drafted by Agent 5; in/out scope, comparison
                          matrix, v0.7 launch checklist

Top blockers identified for v0.5.32 (cross-cited in README):
  1. Suspend/resume wifi death (kernel.modules_disabled=1)
  2. veilor-firstboot.service WantedBy=graphical.target
  3. kernel-upgrade grub drift
  4. USBGuard hash-rules problem (already learned on onyx)
  5. firewalld blocks tailscale0
  6. /etc/skel/ empty
  7. virtio-9p log capture replaces broken virtio-serial path

Wave + verifier pattern (per ROADMAP lessons learned #4) validated:
9 parallel agents on distinct topics produced converging blocker
list. The same pattern landed v0.5.31 four-bug fix from the prior
4-agent verification wave on v0.5.30 outcome.
2026-05-05 14:52:53 +01:00

3.3 KiB

Anaconda log capture — virtio-9p host-share

Agent 6 of 9-agent wave, 2026-05-05.

Why current setup is silent

v0.5.30 wired:

-chardev file,id=anaclog,path=$ANACONDA_LOG
-device virtio-serial-pci,id=vs1
-device virtserialport,chardev=anaclog,bus=vs1.0,name=org.fedoraproject.anaconda.log.0

Anaconda is supposed to autodetect this port and stream logs. Result: test/anaconda-vm-*.log files are 0 bytes despite multiple full installs.

Root cause: Anaconda's setupVirtio() (anaconda_logging.py:315) doesn't write to the virtio port directly — it adds a forward rule to /etc/rsyslog.conf then calls restart_service("rsyslog"). No inst.virtiolog boot arg is required (--virtiolog defaults to the right port via argument_parsing.py:512).

The veilor live ISO almost certainly lacks rsyslog (minimal Fedora ks), so the forward rule lands in a file no daemon reads. restart_service is a no-op. The QEMU side opens the port and creates the 0-byte file but nothing ever writes to it.

Even with rsyslog present, only LOG_LOCAL1-tagged messages would flow; the rich content lives in /tmp/anaconda.log, /tmp/program.log, /tmp/storage.log, /tmp/packaging.log which never traverse syslog.

Fix — Option C (virtio-9p host-share + post-install copy)

test/run-vm.sh

Add -virtfs 9p export of test/test-runs/<timestamp>/ tagged hostlogs. Keep existing virtio-serial as belt-and-braces fallback.

TS=$(date +%Y%m%d-%H%M%S)
HOSTLOGS_DIR="$TEST_DIR/test-runs/$TS"
mkdir -p "$HOSTLOGS_DIR"
HOSTSHARE_ARGS=(
    -virtfs "local,path=$HOSTLOGS_DIR,mount_tag=hostlogs,security_model=mapped-xattr,id=hostshare"
)
echo "  Logs  : $HOSTLOGS_DIR"

Append "${HOSTSHARE_ARGS[@]}" \ to the exec qemu-system-x86_64 block.

overlay/usr/local/bin/veilor-installer

In run_install(), install an EXIT trap calling _dump_logs_to_host that mounts the 9p share at /mnt/hostlogs and copies:

  • /tmp/{anaconda,program,storage,packaging,dnf,dnf.librepo,anaconda-cmdline}.log
  • /var/log/veilor-installer.log
  • generated kickstart at /run/install/veilor-generated.ks
  • dmesg output
  • journalctl -b output

Runs on success, failure, and ^C. Auto-no-ops on real hardware where 9p isn't loaded.

_dump_logs_to_host() {
    if mount -t 9p -o trans=virtio,version=9p2000.L hostlogs /mnt/hostlogs 2>/dev/null; then
        cp -a /tmp/{anaconda,program,storage,packaging,dnf,dnf.librepo,anaconda-cmdline}.log \
              /var/log/veilor-installer.log \
              /run/install/veilor-generated.ks \
              /mnt/hostlogs/ 2>/dev/null || true
        dmesg > /mnt/hostlogs/dmesg.log 2>/dev/null || true
        journalctl -b > /mnt/hostlogs/journal.log 2>/dev/null || true
        umount /mnt/hostlogs 2>/dev/null || true
    fi
}
trap _dump_logs_to_host EXIT

Why options A/B/D were rejected

  • A (grub kernel arg surgery — inst.virtiolog) and D (host rsyslog TCP listener with inst.syslog=10.0.2.2:5140) both still rely on rsyslog being present in the live ISO.
  • B (anaconda --syslog at CLI) — same dependency.
  • C captures complete file-level fidelity regardless. virtio-9p is in the kernel; mount is two lines; copies the actual files.

Files modified

  • test/run-vm.sh
  • overlay/usr/local/bin/veilor-installer