pixie-lab 0.3.1__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/.github/workflows/cicd.yaml +68 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/CHANGELOG.md +142 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/Makefile +10 -1
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/PKG-INFO +1 -1
- pixie_lab-0.4.0/cijoe/configs/test-usb-ventoy.toml +48 -0
- pixie_lab-0.4.0/cijoe/scripts/usb_iso_verify.py +92 -0
- pixie_lab-0.4.0/cijoe/scripts/usb_ventoy_guest_start.py +48 -0
- pixie_lab-0.4.0/cijoe/scripts/usb_ventoy_stage.py +231 -0
- pixie_lab-0.4.0/cijoe/tasks/test-usb-ventoy.yaml +119 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/src/boot-modes.md +63 -23
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/src/deployment.md +4 -3
- pixie_lab-0.4.0/docs/src/quickstart.md +97 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pyproject.toml +1 -1
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/deploy/_main.py +25 -3
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/events/_kinds.py +21 -19
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/exports/_store.py +118 -80
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/machines/_routes.py +23 -7
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/machines/_store.py +56 -30
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/pxe/_renderer.py +62 -82
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/pxe/_routes.py +13 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_bind_preview.py +13 -9
- pixie_lab-0.4.0/src/pixie/web/_fsutil.py +36 -0
- pixie_lab-0.4.0/src/pixie/web/_images.py +194 -0
- pixie_lab-0.4.0/src/pixie/web/_overlay_bind.py +101 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_overlays.py +68 -50
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_settings_store.py +7 -5
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/catalog.html +21 -57
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/catalog_detail.html +1 -1
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/dashboard.html +66 -76
- pixie_lab-0.4.0/src/pixie/web/_templates/image_detail.html +108 -0
- pixie_lab-0.4.0/src/pixie/web/_templates/images.html +139 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/layout.html +3 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/machine_detail.html +88 -69
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/machines.html +16 -5
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/overlays.html +36 -29
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/main.py +303 -114
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_deploy_unit.py +36 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_exports_unit.py +88 -33
- pixie_lab-0.4.0/tests/test_images_ui.py +223 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_machines_unit.py +130 -24
- pixie_lab-0.4.0/tests/test_overlays_ui.py +361 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_pxe_plan_json.py +44 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_settings.py +4 -1
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_ui_pages.py +44 -6
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_web_bind_preview.py +11 -7
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/uv.lock +1 -1
- pixie_lab-0.3.1/docs/src/quickstart.md +0 -66
- pixie_lab-0.3.1/tests/test_overlays_ui.py +0 -255
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/.dockerignore +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/.github/workflows/docs.yml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/.gitignore +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/Containerfile +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/LICENSE +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/PLAN.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/README.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/netboot-pc.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-flash-always.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-flash.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-inventory.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-nbdboot.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-tui.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/test-pxe.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/configs/usbboot-pc.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/live_build.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/pixie_ipxe_build.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/pixie_wheel_stage.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/pxe_flash_stage.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/pxe_inventory_stage.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/pxe_prepare.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/pxe_run_chain_test.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/scripts/usb_iso_build.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/netboot-pc.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-flash-always.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-flash.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-inventory.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-nbdboot.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-tui.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/cijoe/tasks/usbboot-pc.yaml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/audit.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/src/conf.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/src/hardware-quirks.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/src/index.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/tooling/README.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/tooling/pyproject.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/tooling/src/pixie_docs/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/docs/tooling/src/pixie_docs/cli.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/README.md +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/auxiliary/cloudinit-metadata.meta +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/auxiliary/ipxe-embed.ipxe +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/auxiliary/ipxe-local-general.h +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/auto/config +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/archives/backports.list.binary +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/archives/backports.list.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/bootloaders/grub-efi/splash.png +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/bootloaders/syslinux/splash.png +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0500-pixie-install.hook.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0500-pixie-skip-bootloader-menu.hook.binary +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0600-pixie-r8125-dkms.hook.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0700-pixie-clock-from-http.hook.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0800-pixie-ssh-live.hook.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0900-pixie-enable-services.hook.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0980-pixie-apt-validate.hook.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/issue +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/modprobe.d/zz-pixie-blacklist-nouveau.conf +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/motd +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/profile.d/pixie-version.sh +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/getty@.service.d/zzz-pixie-autologin-root.conf +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-early.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-late.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-mid.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-clock-from-http.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-images-discover.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-on-tty1.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-usb-grow.service +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/var-lib-pixie-images.mount +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/udev/rules.d/70-pixie-realtek-2g5-offloads.rules +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/lib/systemd/system-generators/pixie-skip-usb-only-units-on-netboot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-boot-banner +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-clock-from-http +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-images-discover +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-on-tty1 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-trace +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-usb-grow +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/package-lists/pixie-base.list.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/package-lists/pixie-flash.list.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/preferences/backports.pref.binary +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/pixie-media/live-build/config/preferences/backports.pref.chroot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/_partition.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/_util.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/_fetcher.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/_live_env.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/_routes.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/_schema.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/_store.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/catalog/catalog.toml +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/deploy/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/deploy/_templates.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/disks.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/events/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/events/_log.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/events/_routes.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/exports/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/exports/_routes.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/exports/_supervisor.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/flash.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/images.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/machines/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/oras.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/pivot/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/pivot/nbdboot +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/pxe/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/tftp/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/tftp/_supervisor.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/tui/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/tui/_app.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/tui_catalog.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_auth.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_inventory.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/.gitkeep +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/bootstrap-icons.min.css +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/bootstrap.min.css +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/fonts/bootstrap-icons.woff +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/fonts/bootstrap-icons.woff2 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/htmx.min.js +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/pixie-favicon.png +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_static/sse.js +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_table_state.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/_partials/page_description.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/_partials/recent_events.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/_partials/table_helpers.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/events.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/bootstrap.j2 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/exit.j2 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/nbdboot.j2 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/pixie-live-env.j2 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/unavailable.j2 +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/live_env.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/login.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/src/pixie/web/_templates/settings.html +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/conftest.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/__init__.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/conftest.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/test_catalog_fetch.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/test_deploy.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/test_exports.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/test_inventory.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/test_pxe.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/integration/test_tftp.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_auth.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_catalog_api.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_catalog_seed.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_event_kinds.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_events_unit.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_fetch_progress.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_healthz.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_live_env_fetch.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_pivot.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_schema.py +0 -0
- {pixie_lab-0.3.1 → pixie_lab-0.4.0}/tests/test_web_inventory.py +0 -0
|
@@ -10,6 +10,11 @@ name: cicd
|
|
|
10
10
|
# * ``build-media``: build the live-env media (netboot-pc + usbboot-pc
|
|
11
11
|
# variants) via the cijoe pipelines under cijoe/tasks/. Requires
|
|
12
12
|
# live-build + passwordless sudo; the runner has both.
|
|
13
|
+
# * ``verify-usbboot``: structurally verify the usbboot-pc .iso
|
|
14
|
+
# (hybrid ISO + El Torito BIOS & UEFI entries + sha256), then boot
|
|
15
|
+
# it via a real Ventoy stick in QEMU and assert the pixie live env
|
|
16
|
+
# comes up. Gates the publish jobs so a broken / non-Ventoy .iso
|
|
17
|
+
# never ships.
|
|
13
18
|
# * ``build-wheel``: sdist + wheel for PyPI. Runs on every push +
|
|
14
19
|
# PR so the packaging story is exercised regardless of tag state.
|
|
15
20
|
# * ``publish-pypi``: trusted publishing of the wheel + sdist,
|
|
@@ -556,6 +561,66 @@ jobs:
|
|
|
556
561
|
path: cijoe/_build/test-pxe
|
|
557
562
|
if-no-files-found: warn
|
|
558
563
|
|
|
564
|
+
verify-usbboot:
|
|
565
|
+
name: Verify usbboot .iso (structural + Ventoy boot in QEMU)
|
|
566
|
+
# Downloads the usbboot-pc bake, structurally verifies the hybrid
|
|
567
|
+
# ISO (ISO 9660 + isohybrid MBR + El Torito BIOS & UEFI entries +
|
|
568
|
+
# sha256), then boots it via a real Ventoy stick in QEMU and asserts
|
|
569
|
+
# the pixie live env comes up: pixie-usb-grow skips (no PIXIE_IMGS
|
|
570
|
+
# under a loop-mounted ISO), pixie-images-discover bind-mounts the
|
|
571
|
+
# operator drop, pixie-on-tty1 renders the CLI wizard. Gates the
|
|
572
|
+
# release -- a broken / non-bootable / non-Ventoy-compatible ISO
|
|
573
|
+
# must not ship.
|
|
574
|
+
needs: build-media
|
|
575
|
+
runs-on: ubuntu-latest
|
|
576
|
+
timeout-minutes: 40
|
|
577
|
+
steps:
|
|
578
|
+
- uses: actions/checkout@v6
|
|
579
|
+
|
|
580
|
+
- name: Install host tools (qemu, ovmf, exfat, xorriso)
|
|
581
|
+
run: |
|
|
582
|
+
set -eu
|
|
583
|
+
sudo apt-get update
|
|
584
|
+
sudo apt-get install -y --no-install-recommends \
|
|
585
|
+
qemu-system-x86 \
|
|
586
|
+
qemu-utils \
|
|
587
|
+
ovmf \
|
|
588
|
+
exfat-fuse \
|
|
589
|
+
exfatprogs \
|
|
590
|
+
xorriso \
|
|
591
|
+
file
|
|
592
|
+
sudo chmod a+rw /dev/kvm
|
|
593
|
+
ls -la /dev/kvm
|
|
594
|
+
|
|
595
|
+
- name: Install cijoe
|
|
596
|
+
run: pipx install --force cijoe
|
|
597
|
+
|
|
598
|
+
- name: Install uv
|
|
599
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
600
|
+
|
|
601
|
+
- name: Download usbboot-pc artifact
|
|
602
|
+
uses: actions/download-artifact@v7
|
|
603
|
+
with:
|
|
604
|
+
name: pixie-usbboot-pc-x86_64
|
|
605
|
+
path: ~/system_imaging/disk/
|
|
606
|
+
|
|
607
|
+
- name: Show downloaded artifact contents
|
|
608
|
+
run: |
|
|
609
|
+
set -eu
|
|
610
|
+
echo "--- ~/system_imaging/disk (recursive) ---"
|
|
611
|
+
find ~/system_imaging/disk -maxdepth 5 -print
|
|
612
|
+
|
|
613
|
+
- name: Verify + Ventoy-boot the usbboot .iso
|
|
614
|
+
run: make test-usb-ventoy
|
|
615
|
+
|
|
616
|
+
- name: Upload cijoe output
|
|
617
|
+
if: always()
|
|
618
|
+
uses: actions/upload-artifact@v7
|
|
619
|
+
with:
|
|
620
|
+
name: cijoe-output-test-usb-ventoy
|
|
621
|
+
path: cijoe/cijoe-output
|
|
622
|
+
if-no-files-found: warn
|
|
623
|
+
|
|
559
624
|
build-wheel:
|
|
560
625
|
name: Build wheel + sdist
|
|
561
626
|
needs: test
|
|
@@ -591,6 +656,7 @@ jobs:
|
|
|
591
656
|
- test-pxe-tui
|
|
592
657
|
- test-pxe-flash
|
|
593
658
|
- test-pxe-flash-always
|
|
659
|
+
- verify-usbboot
|
|
594
660
|
runs-on: ubuntu-latest
|
|
595
661
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
596
662
|
environment:
|
|
@@ -632,6 +698,7 @@ jobs:
|
|
|
632
698
|
- test-pxe-tui
|
|
633
699
|
- test-pxe-flash
|
|
634
700
|
- test-pxe-flash-always
|
|
701
|
+
- verify-usbboot
|
|
635
702
|
runs-on: ubuntu-latest
|
|
636
703
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
637
704
|
permissions:
|
|
@@ -676,6 +743,7 @@ jobs:
|
|
|
676
743
|
- test-pxe-tui
|
|
677
744
|
- test-pxe-flash
|
|
678
745
|
- test-pxe-flash-always
|
|
746
|
+
- verify-usbboot
|
|
679
747
|
runs-on: ubuntu-latest
|
|
680
748
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
681
749
|
permissions:
|
|
@@ -11,6 +11,148 @@ operator-facing summary.
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.4.0] - 2026-07-24
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
**Machines list Image column reads like the new model.** The bound
|
|
19
|
+
image now shows the catalog name linked to its Images page (short sha
|
|
20
|
+
for an orphan blob whose entry was deleted), instead of a bare hash,
|
|
21
|
+
and is blank for boot modes that don't consume an image (ipxe-exit /
|
|
22
|
+
inventory / tui) rather than showing a stale sha.
|
|
23
|
+
|
|
24
|
+
**Catalog table is leaner.** The sources listing drops the inline
|
|
25
|
+
content sha + byte size (image facts that live on the linked Image
|
|
26
|
+
page); the fetched/error/in-flight readiness state stays.
|
|
27
|
+
|
|
28
|
+
**Default timestamp format drops the timezone suffix.** Operator-facing
|
|
29
|
+
timestamps now default to `%Y-%m-%d %H:%M:%S` (24-hour, no ` %Z`); the
|
|
30
|
+
display timezone is still an operator setting, just not repeated on
|
|
31
|
+
every row. Set `PIXIE_DATETIME_FORMAT` or the Settings override to add
|
|
32
|
+
it back.
|
|
33
|
+
|
|
34
|
+
**Overlays are now globally-named single-writer volumes.** A persistent
|
|
35
|
+
nbdboot overlay is no longer a per-`(machine, image, profile)` triple; it
|
|
36
|
+
is a globally-unique named writable volume (`alias`) over ONE base image,
|
|
37
|
+
and the base image is implied by the alias. At most one machine may hold
|
|
38
|
+
an alias at a time: attaching one already held by a different machine is
|
|
39
|
+
rejected in the app ("held by <mac>; detach first"), with qemu-nbd's
|
|
40
|
+
qcow2 image-lock as the backstop. On a machine's detail page the picker
|
|
41
|
+
now offers the aliases that are free (or already held here) plus a
|
|
42
|
+
create-new flow; attaching an existing alias binds the machine to that
|
|
43
|
+
alias's base image. The Overlays page keys on the alias, shows an
|
|
44
|
+
**Attached to** column (a MAC or "free"), and classifies each row as
|
|
45
|
+
serving / held / free / orphaned / missing; Prune still reclaims only the
|
|
46
|
+
orphaned + file-missing rows and leaves a free alias (a deliberate keep)
|
|
47
|
+
alone. On-disk overlays move from
|
|
48
|
+
`overlays/<mac>/<image_sha>/<profile>.qcow2` to a flat
|
|
49
|
+
`overlays/<alias>.qcow2`. Existing state.db rows migrate in place on
|
|
50
|
+
first start: each old overlay becomes `alias = <profile>-<mac_slug>`
|
|
51
|
+
holding its original MAC, its qcow2 path is kept as-is (no large-file
|
|
52
|
+
move), and each machine's binding is rewritten to the same derived alias.
|
|
53
|
+
|
|
54
|
+
**Dashboard speaks the new model.** The tiles now mirror the
|
|
55
|
+
storage/lifecycle vocabulary + the nav: **Machines**, **Catalog**
|
|
56
|
+
(sources you can fetch, with a not-yet-fetched count), **Images** (the
|
|
57
|
+
materialised entities, with on-disk footprint + how many are
|
|
58
|
+
reclaimable), **Overlays** (alias-keyed writable volumes, with disk-used
|
|
59
|
+
+ serving), and **Events** -- instead of the old catalog-images /
|
|
60
|
+
NBD-exports framing. The Acknowledge button was removed from the
|
|
61
|
+
dashboard (it's an action; the dashboard is output-only -- ack lives on
|
|
62
|
+
the Events page).
|
|
63
|
+
|
|
64
|
+
**Catalog is sources-only now.** With Images owning the materialised
|
|
65
|
+
view, the Catalog page drops the NBD-serving column and the
|
|
66
|
+
Stop-export / blob-delete actions (those live on Images). It keeps
|
|
67
|
+
source management -- add, import, Fetch, delete-entry -- and a fetched
|
|
68
|
+
disk-image row now links to its **Image** for footprint, live NBD /
|
|
69
|
+
overlay usage, and GC.
|
|
70
|
+
|
|
71
|
+
**Legacy `/ui/exports` lands on Images.** The kept-alive redirect for
|
|
72
|
+
the old exports URL (and the Stop-export action) now points at the
|
|
73
|
+
Images view, where NBD export usage is surfaced per content sha, rather
|
|
74
|
+
than at Catalog.
|
|
75
|
+
|
|
76
|
+
**Overlay picker shows aliases held elsewhere, disabled.** The
|
|
77
|
+
machine-detail overlay dropdown used to hide any alias held by another
|
|
78
|
+
machine, so an operator searching for it assumed it didn't exist and
|
|
79
|
+
tried to create a duplicate (which the single-writer bind then
|
|
80
|
+
rejected). Held-elsewhere aliases are now shown as a disabled option
|
|
81
|
+
labelled with the holder MAC ("held by `<mac>`") -- visible, but not
|
|
82
|
+
selectable.
|
|
83
|
+
|
|
84
|
+
**Overlays distinguish "pending" from "file missing".** A reserved
|
|
85
|
+
overlay alias whose qcow2 hasn't been lazy-created yet (never booted)
|
|
86
|
+
previously read as *file missing* -- the same alarming state as a
|
|
87
|
+
booted-then-lost overlay -- and Prune would reclaim it as junk. Such an
|
|
88
|
+
overlay is now classified **pending** (benign, awaiting its first
|
|
89
|
+
nbdboot) and is left alone by Prune; *missing* is reserved for an
|
|
90
|
+
overlay whose qcow2 vanished after a prior boot (real data loss). The
|
|
91
|
+
`last_boot_at` timestamp is the discriminator.
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
**First-contact machines emit a `machine.discovered` audit event.** The
|
|
96
|
+
first time an unknown MAC hits `GET /pxe/<mac>` and is auto-registered,
|
|
97
|
+
pixie now records one `machine.discovered` event (carrying the
|
|
98
|
+
auto-registered boot mode + the client IP); repeat contacts do not
|
|
99
|
+
re-emit. The kind was reserved but never fired before.
|
|
100
|
+
|
|
101
|
+
**Images: the materialised content behind Catalog sources.** A new
|
|
102
|
+
**Images** page (`/ui/images`) separates the *source* (a Catalog entry,
|
|
103
|
+
a URL you can fetch) from the *entity* it produces once fetched (an
|
|
104
|
+
image, identity = the disk content sha). Machines, NBD exports, and
|
|
105
|
+
overlays all key off that sha, so each image rolls up its on-disk
|
|
106
|
+
footprint (raw disk + rootfs + boot bundle + overlays) and every live
|
|
107
|
+
usage -- machines bound, the ephemeral nbdkit export, and per-machine
|
|
108
|
+
qemu-nbd overlays -- with counts that link into the per-usage admin
|
|
109
|
+
surfaces. An **image detail hub** (`/ui/images/<sha>`) lays out the
|
|
110
|
+
artifacts + every usage inline and offers a **guarded delete / blob GC**:
|
|
111
|
+
allowed only when the usage count (the refcount) is zero, it removes the
|
|
112
|
+
whole `blobs/<sha>/` dir (raw disk **and** the `rootfs.raw` the old
|
|
113
|
+
per-entry delete leaked) and clears the sha off every entry that
|
|
114
|
+
resolved to it. The list also surfaces **orphan blobs** -- sha dirs on
|
|
115
|
+
disk with no catalog entry -- which is where the un-GC'd disk pressure
|
|
116
|
+
actually hides; they delete straight through. Catalog is unchanged for
|
|
117
|
+
now.
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
|
|
121
|
+
**Live-env artifacts are served after a post-startup fetch, no restart
|
|
122
|
+
needed.** The `/boot/pixie-live-env/` mount was created at app startup
|
|
123
|
+
only if the directory already existed, so on a fresh deploy -- where the
|
|
124
|
+
operator stages the netboot-pc bake later via "Fetch live env" -- the
|
|
125
|
+
plan pointed targets at `/boot/pixie-live-env/vmlinuz` and friends that
|
|
126
|
+
then 404'd until pixie was restarted, silently breaking every
|
|
127
|
+
`pixie-inventory` / `-tui` / `-flash` boot. The mount is now created
|
|
128
|
+
unconditionally (dir ensured, `check_dir=False`), so a fetched live-env
|
|
129
|
+
is served immediately.
|
|
130
|
+
|
|
131
|
+
**`pixie-lab purge --all` no longer tracebacks on a root-owned parent.**
|
|
132
|
+
When the deploy dir lives under a directory the operator can't write
|
|
133
|
+
(the common `/opt/pixie` case), purge could empty the dir but not
|
|
134
|
+
remove the dir itself, and surfaced the failure as a raw Python
|
|
135
|
+
traceback. It now clears the state, prints a plain one-line caveat
|
|
136
|
+
("emptied `<dir>`, but could not remove the directory itself ..."), and
|
|
137
|
+
exits 0 -- the purge did its job; only the empty-dir removal was blocked
|
|
138
|
+
by the parent's permissions.
|
|
139
|
+
|
|
140
|
+
## [0.3.2] - 2026-07-24
|
|
141
|
+
|
|
142
|
+
### Added
|
|
143
|
+
|
|
144
|
+
**CI verifies the usbboot `.iso` boots via Ventoy.** A new
|
|
145
|
+
`verify-usbboot` job structurally checks the bake (valid ISO 9660 +
|
|
146
|
+
isohybrid MBR + El Torito BIOS *and* UEFI boot entries + sha256), then
|
|
147
|
+
installs Ventoy onto a QEMU disk, drops the `.iso` + a sentinel image
|
|
148
|
+
catalog onto it, and boots it -- asserting the pixie live env comes up
|
|
149
|
+
correctly on the Ventoy loop-boot path (`pixie-usb-grow` skips with no
|
|
150
|
+
`PIXIE_IMGS` partition, `pixie-images-discover` bind-mounts the
|
|
151
|
+
operator drop at `/var/lib/pixie/images`, and `pixie-on-tty1` renders
|
|
152
|
+
the CLI wizard). The job gates the publish jobs, so a broken,
|
|
153
|
+
non-bootable, or non-Ventoy-compatible ISO can never ship. Ported from
|
|
154
|
+
bty's `test-usb-ventoy`.
|
|
155
|
+
|
|
14
156
|
## [0.3.1] - 2026-07-24
|
|
15
157
|
|
|
16
158
|
### Fixed
|
|
@@ -23,7 +23,7 @@ endif
|
|
|
23
23
|
|
|
24
24
|
.PHONY: help \
|
|
25
25
|
deps test lint format format-check typecheck ci wheel \
|
|
26
|
-
media-deps build ipxe test-pxe \
|
|
26
|
+
media-deps build ipxe test-pxe test-usb-ventoy \
|
|
27
27
|
clean
|
|
28
28
|
|
|
29
29
|
help:
|
|
@@ -56,6 +56,8 @@ help:
|
|
|
56
56
|
@echo " (same deps as test-pxe-flash; asserts no /done flip)"
|
|
57
57
|
@echo " test-pxe-tui end-to-end PXE pixie-tui chain test"
|
|
58
58
|
@echo " (same deps as test-pxe-flash; asserts wizard entry)"
|
|
59
|
+
@echo " test-usb-ventoy structural + Ventoy-boot verify of the usbboot .iso"
|
|
60
|
+
@echo " (needs a prior VARIANT=usbboot-pc bake + qemu/KVM/OVMF + ventoy deps)"
|
|
59
61
|
@echo ""
|
|
60
62
|
@echo "Variant: $(VARIANT) (override with VARIANT=netboot-pc, ...)"
|
|
61
63
|
@echo " usbboot-pc - bootable USB live ISO via live-build (.iso, x86_64)"
|
|
@@ -166,6 +168,13 @@ test-pxe-flash-always:
|
|
|
166
168
|
test-pxe-tui:
|
|
167
169
|
cd cijoe && cijoe tasks/test-pxe-tui.yaml --monitor -c configs/test-pxe-tui.toml
|
|
168
170
|
|
|
171
|
+
# Structural + Ventoy-boot verification of the usbboot .iso. Needs a
|
|
172
|
+
# prior VARIANT=usbboot-pc bake staged under ~/system_imaging/disk/ (or
|
|
173
|
+
# a downloaded pixie-usbboot-pc-x86_64 CI artifact) + qemu/KVM/OVMF +
|
|
174
|
+
# ventoy tooling deps (losetup, exfat-fuse, passwordless sudo).
|
|
175
|
+
test-usb-ventoy:
|
|
176
|
+
cd cijoe && cijoe tasks/test-usb-ventoy.yaml --monitor -c configs/test-usb-ventoy.toml
|
|
177
|
+
|
|
169
178
|
# ---------- Cleanup ------------------------------------------------------
|
|
170
179
|
|
|
171
180
|
clean:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pixie-lab
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Bare-metal netboot appliance: catalog + fetch + NBD + PXE + TFTP + operator TUI in one container
|
|
5
5
|
Project-URL: Homepage, https://github.com/safl/pixie
|
|
6
6
|
Project-URL: Repository, https://github.com/safl/pixie
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# pixie USB Ventoy-boot test - cijoe config
|
|
2
|
+
#
|
|
3
|
+
# Verifies an operator's realistic Ventoy workflow:
|
|
4
|
+
# 1. Install Ventoy onto a USB stick.
|
|
5
|
+
# 2. Drop pixie-usbboot-pc-x86_64-v*.iso + image files + a catalog.toml
|
|
6
|
+
# onto the Ventoy data partition (under pixie-images/).
|
|
7
|
+
# 3. Boot the stick; Ventoy menu auto-selects the only ISO + chains
|
|
8
|
+
# into the pixie live env.
|
|
9
|
+
# 4. ``pixie-usb-grow.service`` skips correctly (no PIXIE_IMGS
|
|
10
|
+
# partition on the booted device -- the .iso is loop-mounted, not
|
|
11
|
+
# dd'd).
|
|
12
|
+
# 5. ``pixie-images-discover.service`` finds the operator's drop on the
|
|
13
|
+
# Ventoy data partition and bind-mounts ``pixie-images/`` at
|
|
14
|
+
# ``/var/lib/pixie/images``.
|
|
15
|
+
# 6. ``pixie-on-tty1.service`` renders the pixie CLI wizard on tty1.
|
|
16
|
+
|
|
17
|
+
[cijoe.task]
|
|
18
|
+
fail_fast = true
|
|
19
|
+
|
|
20
|
+
[qemu]
|
|
21
|
+
img_bin = "qemu-img"
|
|
22
|
+
|
|
23
|
+
[qemu.systems.x86_64]
|
|
24
|
+
bin = "qemu-system-x86_64"
|
|
25
|
+
|
|
26
|
+
[qemu.guests.usb-ventoy]
|
|
27
|
+
path = "{{ local.env.HOME }}/system_imaging/usb-ventoy"
|
|
28
|
+
system_label = "x86_64"
|
|
29
|
+
system_args.kwa = { cpu = "host", smp = 2, m = "1G", accel = "kvm" }
|
|
30
|
+
# IDE-hd: Ventoy's bootloader (a chainloaded GRUB) reads via BIOS
|
|
31
|
+
# INT13 -- virtio-blk is invisible to it. Present the Ventoy stick as
|
|
32
|
+
# an IDE hard disk so the BIOS sees a bootable disk. ``-no-reboot`` so
|
|
33
|
+
# a failed boot exits instead of looping.
|
|
34
|
+
system_args.raw = "-drive file={{ local.env.HOME }}/system_imaging/usb-ventoy/disk.img,format=raw,if=ide -no-reboot"
|
|
35
|
+
system_args.tcp_forward = { host = 12223, guest = 22 }
|
|
36
|
+
|
|
37
|
+
[cijoe.transport.usb_ventoy_guest]
|
|
38
|
+
username = "root"
|
|
39
|
+
password = "pixie"
|
|
40
|
+
hostname = "localhost"
|
|
41
|
+
port = 12223
|
|
42
|
+
|
|
43
|
+
[test.usb_ventoy]
|
|
44
|
+
iso_dir = "{{ local.env.HOME }}/system_imaging/disk"
|
|
45
|
+
# Pinned Ventoy version so the test is reproducible. Bump deliberately
|
|
46
|
+
# when validating a newer release; this is the Ventoy2Disk.sh version
|
|
47
|
+
# the test installs with, not what an operator must use in production.
|
|
48
|
+
ventoy_version = "1.1.05"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Structurally verify the pixie usbboot .iso
|
|
3
|
+
===========================================
|
|
4
|
+
|
|
5
|
+
Fast, no-boot sanity checks on ``pixie-usbboot-pc-x86_64-v*.iso`` before
|
|
6
|
+
the Ventoy boot test spends ~10 min proving it actually boots. Catches a
|
|
7
|
+
broken / non-hybrid / single-firmware bake immediately:
|
|
8
|
+
|
|
9
|
+
1. ``file`` reports an ISO 9660 filesystem with a DOS/MBR boot sector
|
|
10
|
+
(the isohybrid MBR that makes ``dd`` to a USB stick BIOS-bootable).
|
|
11
|
+
2. The El Torito catalog carries BOTH a BIOS and a UEFI/EFI boot
|
|
12
|
+
image -- i.e. the ISO boots on legacy BIOS AND UEFI firmware.
|
|
13
|
+
3. The published ``.iso.sha256`` sidecar matches the image.
|
|
14
|
+
|
|
15
|
+
Retargetable: False (host-side; needs ``file`` + ``xorriso`` +
|
|
16
|
+
``sha256sum`` on the initiator, which the workflow installs).
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import errno
|
|
22
|
+
import logging as log
|
|
23
|
+
from argparse import ArgumentParser
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
ISO_BASENAME_GLOB = "pixie-usbboot-pc-x86_64-v*.iso"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def add_args(parser: ArgumentParser):
|
|
30
|
+
del parser
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _out(res) -> str:
|
|
34
|
+
return res.output() if hasattr(res, "output") else str(res)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def main(args, cijoe):
|
|
38
|
+
del args
|
|
39
|
+
cfg = cijoe.getconf("test.usb_ventoy", {})
|
|
40
|
+
iso_dir = Path(cfg.get("iso_dir") or (Path.home() / "system_imaging" / "disk"))
|
|
41
|
+
candidates = sorted(iso_dir.glob(ISO_BASENAME_GLOB))
|
|
42
|
+
if not candidates:
|
|
43
|
+
log.error(f"no {ISO_BASENAME_GLOB} found in {iso_dir} (did usbboot-pc build run?)")
|
|
44
|
+
return errno.ENOENT
|
|
45
|
+
iso = candidates[-1]
|
|
46
|
+
log.info(f"verifying {iso.name} ({iso.stat().st_size} bytes)")
|
|
47
|
+
|
|
48
|
+
# 1. Valid ISO 9660 + isohybrid MBR (BIOS-bootable when dd'd).
|
|
49
|
+
err, res = cijoe.run_local(f"file -- {iso}")
|
|
50
|
+
if err:
|
|
51
|
+
log.error("`file` failed")
|
|
52
|
+
return errno.EIO
|
|
53
|
+
file_out = _out(res)
|
|
54
|
+
if "ISO 9660" not in file_out:
|
|
55
|
+
log.error(f"not an ISO 9660 image: {file_out}")
|
|
56
|
+
return errno.EINVAL
|
|
57
|
+
if "DOS/MBR boot sector" not in file_out and "bootable" not in file_out.lower():
|
|
58
|
+
log.error(f"no isohybrid MBR boot sector (not USB-dd bootable?): {file_out}")
|
|
59
|
+
return errno.EINVAL
|
|
60
|
+
log.info("OK: ISO 9660 + DOS/MBR boot sector")
|
|
61
|
+
|
|
62
|
+
# 2. El Torito catalog has both a BIOS and a UEFI/EFI boot image.
|
|
63
|
+
err, res = cijoe.run_local(f"xorriso -indev {iso} -report_el_torito plain 2>&1")
|
|
64
|
+
if err:
|
|
65
|
+
log.error("`xorriso -report_el_torito` failed")
|
|
66
|
+
return errno.EIO
|
|
67
|
+
et = _out(res)
|
|
68
|
+
log.info(f"El Torito report:\n{et}")
|
|
69
|
+
boot_lines = [ln for ln in et.splitlines() if "boot img" in ln.lower()]
|
|
70
|
+
has_bios = any("BIOS" in ln for ln in boot_lines)
|
|
71
|
+
has_uefi = any(("UEFI" in ln) or ("EFI" in ln) for ln in boot_lines)
|
|
72
|
+
if not has_bios:
|
|
73
|
+
log.error("El Torito catalog has no BIOS boot image")
|
|
74
|
+
return errno.EINVAL
|
|
75
|
+
if not has_uefi:
|
|
76
|
+
log.error("El Torito catalog has no UEFI/EFI boot image")
|
|
77
|
+
return errno.EINVAL
|
|
78
|
+
log.info("OK: El Torito has both BIOS and UEFI boot images")
|
|
79
|
+
|
|
80
|
+
# 3. sha256 sidecar matches.
|
|
81
|
+
sha = iso.with_name(iso.name + ".sha256")
|
|
82
|
+
if not sha.is_file():
|
|
83
|
+
log.error(f"missing sha256 sidecar: {sha}")
|
|
84
|
+
return errno.ENOENT
|
|
85
|
+
err, _ = cijoe.run_local(f"sh -c 'cd {iso_dir} && sha256sum -c {sha.name}'")
|
|
86
|
+
if err:
|
|
87
|
+
log.error("sha256 mismatch")
|
|
88
|
+
return errno.EIO
|
|
89
|
+
log.info("OK: sha256 sidecar matches")
|
|
90
|
+
|
|
91
|
+
log.info(f"{iso.name}: structural verification passed")
|
|
92
|
+
return 0
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Start the Ventoy QEMU guest WITHOUT the is_up wait
|
|
3
|
+
==================================================
|
|
4
|
+
|
|
5
|
+
Thin wrapper around ``cijoe.qemu.wrapper.Guest.start()`` that returns
|
|
6
|
+
immediately after the guest is daemonised, skipping the upstream
|
|
7
|
+
``qemu.guest_start`` step's hardcoded 180-second ``is_up`` check
|
|
8
|
+
(which waits for the literal string ``login:`` on the serial console).
|
|
9
|
+
|
|
10
|
+
Why a local copy: Ventoy adds a chainload phase (menu -> grub ->
|
|
11
|
+
.iso -> initrd -> squashfs) on top of the pixie live env's normal
|
|
12
|
+
boot, which routinely pushes the time-to-login past the 180-second
|
|
13
|
+
ceiling baked into the upstream script. The YAML's
|
|
14
|
+
``core.wait_for_transport`` step already polls SSH readiness with
|
|
15
|
+
its own (configurable) timeout, so this script intentionally splits
|
|
16
|
+
"start the guest" from "wait for it to be reachable" -- the latter
|
|
17
|
+
is the only concern that needs a tunable timeout.
|
|
18
|
+
|
|
19
|
+
Retargetable: False (host-side; same constraints as the upstream
|
|
20
|
+
script).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import logging as log
|
|
26
|
+
from argparse import ArgumentParser
|
|
27
|
+
|
|
28
|
+
from cijoe.qemu.wrapper import Guest
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def add_args(parser: ArgumentParser):
|
|
32
|
+
parser.add_argument("--guest_name", type=str, help="Name of the qemu guest.")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main(args, cijoe):
|
|
36
|
+
if "guest_name" not in args:
|
|
37
|
+
log.error("missing argument: guest_name")
|
|
38
|
+
return 1
|
|
39
|
+
|
|
40
|
+
guest = Guest(cijoe, cijoe.config, args.guest_name)
|
|
41
|
+
|
|
42
|
+
err = guest.start()
|
|
43
|
+
if err:
|
|
44
|
+
log.error(f"guest.start() : err({err})")
|
|
45
|
+
return err
|
|
46
|
+
|
|
47
|
+
log.info(f"guest '{args.guest_name}' started; readiness handled by wait_for_transport")
|
|
48
|
+
return 0
|