diff --git a/.gitea/workflows/build-iso.yml b/.gitea/workflows/build-iso.yml index 9b7bff81..99576cd9 100644 --- a/.gitea/workflows/build-iso.yml +++ b/.gitea/workflows/build-iso.yml @@ -47,11 +47,65 @@ jobs: ISO=$(ls image-recipe/results/archipelago-installer-unbundled-*.iso 2>/dev/null | head -1) if [ -n "$ISO" ]; then DATE=$(date +%Y%m%d-%H%M) - sudo cp "$ISO" "/var/lib/archipelago/filebrowser/Builds/archipelago-unbundled-${DATE}.iso" - sudo chown 1000:1000 "/var/lib/archipelago/filebrowser/Builds/archipelago-unbundled-${DATE}.iso" + DEST="/var/lib/archipelago/filebrowser/Builds/archipelago-unbundled-${DATE}.iso" + sudo cp "$ISO" "$DEST" + sudo chown 1000:1000 "$DEST" echo "ISO: archipelago-unbundled-${DATE}.iso" + echo "Size: $(du -h "$DEST" | cut -f1)" + echo "SHA256: $(sha256sum "$DEST" | cut -d' ' -f1)" fi + - name: Build report + if: always() + run: | + echo "══════════════════════════════════════════" + echo "BUILD REPORT" + echo "══════════════════════════════════════════" + echo "Commit: $(git rev-parse --short HEAD) ($(git log -1 --format=%s))" + echo "Branch: ${GITHUB_REF_NAME:-unknown}" + echo "Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" + echo "Runner: $(hostname)" + echo "" + echo "── Artifacts ──" + ls -lh image-recipe/results/*.iso 2>/dev/null || echo " No ISO produced" + ls -lh /var/lib/archipelago/filebrowser/Builds/archipelago-unbundled-*.iso 2>/dev/null | tail -3 + echo "" + echo "── Rootfs contents check ──" + ROOTFS=$(ls image-recipe/build/auto-installer/rootfs.tar 2>/dev/null) + if [ -n "$ROOTFS" ]; then + echo " rootfs.tar: $(du -h "$ROOTFS" | cut -f1)" + echo " nginx config: $(tar tf "$ROOTFS" ./etc/nginx/sites-available/archipelago 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " SSL cert: $(tar tf "$ROOTFS" ./etc/archipelago/ssl/archipelago.crt 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " keyboard config: $(tar tf "$ROOTFS" ./etc/default/keyboard 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " console-setup: $(tar tf "$ROOTFS" ./etc/default/console-setup 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " kiosk launcher: $(tar tf "$ROOTFS" ./usr/local/bin/archipelago-kiosk-launcher 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " logind lid: $(tar tf "$ROOTFS" ./etc/systemd/logind.conf.d/lid-ignore.conf 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " backend binary: $(tar tf "$ROOTFS" ./usr/local/bin/archipelago 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + echo " web-ui index: $(tar tf "$ROOTFS" ./opt/archipelago/web-ui/index.html 2>/dev/null && echo 'PRESENT' || echo 'MISSING')" + else + echo " rootfs.tar not found in workspace" + fi + echo "" + echo "── ISO contents check ──" + ISO=$(ls image-recipe/results/archipelago-installer-unbundled-*.iso 2>/dev/null | head -1) + if [ -n "$ISO" ]; then + echo " ISO size: $(du -h "$ISO" | cut -f1)" + # Check installer script is present + ISO_MOUNT=$(mktemp -d) + if sudo mount -o loop,ro "$ISO" "$ISO_MOUNT" 2>/dev/null; then + echo " auto-install.sh: $([ -f "$ISO_MOUNT/archipelago/auto-install.sh" ] && echo 'PRESENT' || echo 'MISSING')" + echo " rootfs.tar: $([ -f "$ISO_MOUNT/archipelago/rootfs.tar" ] && echo "PRESENT ($(du -h "$ISO_MOUNT/archipelago/rootfs.tar" | cut -f1))" || echo 'MISSING')" + echo " backend bin: $([ -f "$ISO_MOUNT/archipelago/bin/archipelago" ] && echo "PRESENT ($(du -h "$ISO_MOUNT/archipelago/bin/archipelago" | cut -f1))" || echo 'MISSING')" + echo " frontend: $([ -f "$ISO_MOUNT/archipelago/web-ui/index.html" ] && echo 'PRESENT' || echo 'MISSING')" + echo " image-versions: $([ -f "$ISO_MOUNT/archipelago/scripts/image-versions.sh" ] && echo 'PRESENT' || echo 'MISSING')" + sudo umount "$ISO_MOUNT" 2>/dev/null + else + echo " Could not mount ISO for inspection" + fi + rmdir "$ISO_MOUNT" 2>/dev/null + fi + echo "══════════════════════════════════════════" + - name: Fix workspace permissions if: always() run: sudo chown -R $(id -u):$(id -g) . 2>/dev/null || true diff --git a/image-recipe/build-auto-installer-iso.sh b/image-recipe/build-auto-installer-iso.sh index b77f3e96..f1b1e6c8 100755 --- a/image-recipe/build-auto-installer-iso.sh +++ b/image-recipe/build-auto-installer-iso.sh @@ -1040,6 +1040,10 @@ cat > "$ARCH_DIR/auto-install.sh" <<'INSTALLER_SCRIPT' set -e +# Log everything to a file on the target disk (after mount) and to console +INSTALL_LOG="/tmp/archipelago-install.log" +exec > >(tee -a "$INSTALL_LOG") 2>&1 + # Detect architecture at install time case "$(uname -m)" in x86_64|amd64) @@ -1853,6 +1857,92 @@ chroot /mnt/target systemctl enable archipelago-setup-tor.service 2>/dev/null || chroot /mnt/target systemctl enable archipelago-first-boot-containers.service 2>/dev/null || true chroot /mnt/target systemctl enable archipelago-kiosk.service 2>/dev/null || true +# Install first-boot diagnostic script — runs once after first boot and logs system state +cat > /mnt/target/opt/archipelago/scripts/first-boot-diag.sh <<'DIAGSCRIPT' +#!/bin/bash +LOG="/var/log/archipelago-first-boot-diag.log" +exec > "$LOG" 2>&1 +echo "=== Archipelago First Boot Diagnostics ===" +echo "Date: $(date -u)" +echo "Hostname: $(hostname)" +echo "Kernel: $(uname -r)" +echo "IP: $(hostname -I 2>/dev/null | awk '{print $1}')" +echo "" +echo "=== Build Info ===" +cat /opt/archipelago/build-info.txt 2>/dev/null || echo "No build-info.txt" +echo "" +echo "=== Services ===" +for svc in nginx archipelago archipelago-kiosk archipelago-load-images archipelago-first-boot-containers; do + STATUS=$(systemctl is-active "$svc" 2>/dev/null || echo "missing") + ENABLED=$(systemctl is-enabled "$svc" 2>/dev/null || echo "missing") + printf " %-45s active=%-10s enabled=%s\n" "$svc" "$STATUS" "$ENABLED" +done +echo "" +echo "=== Nginx Test ===" +nginx -t 2>&1 +echo "" +echo "=== SSL Cert ===" +ls -la /etc/archipelago/ssl/ 2>/dev/null || echo " No SSL directory" +echo "" +echo "=== EFI Boot ===" +ls -la /boot/efi/EFI/BOOT/ 2>/dev/null || echo " No EFI/BOOT directory" +echo "" +echo "=== LUKS ===" +ls -la /dev/mapper/archipelago-data 2>/dev/null && echo " LUKS volume open" || echo " No LUKS volume" +cat /etc/crypttab 2>/dev/null +echo "" +echo "=== Podman ===" +podman --version 2>/dev/null || echo " podman not found" +podman ps -a --format "{{.Names}} {{.Status}}" 2>/dev/null | head -20 +echo "" +echo "=== Kiosk ===" +systemctl status archipelago-kiosk --no-pager 2>&1 | head -10 +echo "" +echo "=== Console Setup ===" +systemctl status console-setup --no-pager 2>&1 | head -5 +cat /etc/default/keyboard 2>/dev/null || echo " No keyboard config" +echo "" +echo "=== Logind (Lid) ===" +cat /etc/systemd/logind.conf.d/lid-ignore.conf 2>/dev/null || echo " No lid config" +echo "" +echo "=== Disk ===" +df -h / /boot/efi /var/lib/archipelago 2>/dev/null +echo "" +echo "=== Network ===" +ip addr show | grep -E "inet |link/" | head -10 +echo "" +echo "=== Journal Errors (last boot) ===" +journalctl -b -p err --no-pager 2>/dev/null | tail -30 +echo "" +echo "=== Done ===" +DIAGSCRIPT +chmod +x /mnt/target/opt/archipelago/scripts/first-boot-diag.sh + +# Systemd oneshot service for first-boot diagnostics +cat > /mnt/target/etc/systemd/system/archipelago-diag.service <<'DIAGSVC' +[Unit] +Description=Archipelago First Boot Diagnostics +After=multi-user.target archipelago.service nginx.service +ConditionPathExists=!/var/log/archipelago-first-boot-diag.log + +[Service] +Type=oneshot +ExecStartPre=/bin/sleep 30 +ExecStart=/opt/archipelago/scripts/first-boot-diag.sh +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +DIAGSVC +chroot /mnt/target systemctl enable archipelago-diag.service 2>/dev/null || true + +# Write build info into the installed system +cat > /mnt/target/opt/archipelago/build-info.txt </dev/null && git -C "$BOOT_MEDIA/../" rev-parse --short HEAD 2>/dev/null || echo "unknown") +date=$(date -u '+%Y-%m-%d %H:%M:%S UTC') +type=unbundled +BUILDINFO + # Cleanup sync umount /mnt/target/run 2>/dev/null || true @@ -1919,6 +2009,9 @@ echo "" echo "" echo -e "${YELLOW} >>> REMOVE THE USB DRIVE NOW <<<${NC}" echo "" +# Save install log to target disk for post-install debugging +cp "$INSTALL_LOG" /mnt/target/var/log/archipelago-install.log 2>/dev/null || true + read -p "Press Enter to reboot (make sure USB is removed)..." # Suppress all error output during cleanup and reboot