pixie-lab 0.3.2__tar.gz → 0.4.1__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.2 → pixie_lab-0.4.1}/CHANGELOG.md +168 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/PKG-INFO +1 -1
- pixie_lab-0.4.1/docs/src/boot-modes.md +173 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/src/deployment.md +11 -3
- pixie_lab-0.4.1/docs/src/quickstart.md +97 -0
- pixie_lab-0.4.1/pixie-media/live-build/config/includes.chroot/etc/initramfs-tools/conf.d/pixie-modules-most +22 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pyproject.toml +1 -1
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/deploy/_main.py +25 -3
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/events/_kinds.py +21 -19
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/exports/_store.py +118 -80
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/machines/_routes.py +31 -13
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/machines/_store.py +85 -34
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/pxe/_renderer.py +62 -82
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/pxe/_routes.py +44 -2
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_bind_preview.py +13 -9
- pixie_lab-0.4.1/src/pixie/web/_fsutil.py +36 -0
- pixie_lab-0.4.1/src/pixie/web/_images.py +194 -0
- pixie_lab-0.4.1/src/pixie/web/_overlay_bind.py +101 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_overlays.py +68 -50
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_settings_store.py +30 -11
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/catalog.html +21 -57
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/catalog_detail.html +1 -1
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/dashboard.html +66 -76
- pixie_lab-0.4.1/src/pixie/web/_templates/image_detail.html +108 -0
- pixie_lab-0.4.1/src/pixie/web/_templates/images.html +139 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/layout.html +3 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/machine_detail.html +88 -69
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/machines.html +16 -5
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/overlays.html +36 -29
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/main.py +333 -114
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_deploy_unit.py +36 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_exports_unit.py +88 -33
- pixie_lab-0.4.1/tests/test_images_ui.py +223 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_machines_unit.py +188 -24
- pixie_lab-0.4.1/tests/test_overlays_ui.py +361 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_pxe_plan_json.py +46 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_settings.py +24 -1
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_ui_pages.py +44 -6
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_web_bind_preview.py +11 -7
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/uv.lock +1 -1
- pixie_lab-0.3.2/docs/src/boot-modes.md +0 -119
- pixie_lab-0.3.2/docs/src/quickstart.md +0 -66
- pixie_lab-0.3.2/tests/test_overlays_ui.py +0 -255
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/.dockerignore +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/.github/workflows/cicd.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/.github/workflows/docs.yml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/.gitignore +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/Containerfile +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/LICENSE +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/Makefile +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/PLAN.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/README.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/netboot-pc.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-pxe-flash-always.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-pxe-flash.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-pxe-inventory.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-pxe-nbdboot.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-pxe-tui.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-pxe.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/test-usb-ventoy.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/configs/usbboot-pc.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/live_build.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/pixie_ipxe_build.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/pixie_wheel_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/pxe_flash_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/pxe_inventory_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/pxe_prepare.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/pxe_run_chain_test.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/usb_iso_build.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/usb_iso_verify.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/usb_ventoy_guest_start.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/scripts/usb_ventoy_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/netboot-pc.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-pxe-flash-always.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-pxe-flash.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-pxe-inventory.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-pxe-nbdboot.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-pxe-tui.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-pxe.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/test-usb-ventoy.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/cijoe/tasks/usbboot-pc.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/audit.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/src/conf.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/src/hardware-quirks.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/src/index.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/tooling/README.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/tooling/pyproject.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/tooling/src/pixie_docs/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/docs/tooling/src/pixie_docs/cli.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/README.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/auxiliary/cloudinit-metadata.meta +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/auxiliary/ipxe-embed.ipxe +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/auxiliary/ipxe-local-general.h +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/auto/config +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/archives/backports.list.binary +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/archives/backports.list.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/bootloaders/grub-efi/splash.png +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/bootloaders/syslinux/splash.png +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0500-pixie-install.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0500-pixie-skip-bootloader-menu.hook.binary +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0600-pixie-r8125-dkms.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0700-pixie-clock-from-http.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0800-pixie-ssh-live.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0900-pixie-enable-services.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/hooks/normal/0980-pixie-apt-validate.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/issue +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/modprobe.d/zz-pixie-blacklist-nouveau.conf +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/motd +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/profile.d/pixie-version.sh +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/getty@.service.d/zzz-pixie-autologin-root.conf +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-early.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-late.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-mid.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-clock-from-http.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-images-discover.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-on-tty1.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-usb-grow.service +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/var-lib-pixie-images.mount +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/etc/udev/rules.d/70-pixie-realtek-2g5-offloads.rules +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/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.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-boot-banner +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-clock-from-http +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-images-discover +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-on-tty1 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-trace +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-usb-grow +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/package-lists/pixie-base.list.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/package-lists/pixie-flash.list.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/preferences/backports.pref.binary +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/pixie-media/live-build/config/preferences/backports.pref.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/_partition.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/_util.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/_fetcher.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/_live_env.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/_routes.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/_schema.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/_store.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/catalog/catalog.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/deploy/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/deploy/_templates.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/disks.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/events/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/events/_log.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/events/_routes.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/exports/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/exports/_routes.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/exports/_supervisor.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/flash.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/images.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/machines/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/oras.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/pivot/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/pivot/nbdboot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/pxe/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/tftp/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/tftp/_supervisor.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/tui/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/tui/_app.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/tui_catalog.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_auth.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_inventory.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/.gitkeep +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/bootstrap-icons.min.css +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/bootstrap.min.css +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/fonts/bootstrap-icons.woff +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/fonts/bootstrap-icons.woff2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/htmx.min.js +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/pixie-favicon.png +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_static/sse.js +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_table_state.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/_partials/page_description.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/_partials/recent_events.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/_partials/table_helpers.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/events.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/ipxe/bootstrap.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/ipxe/exit.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/ipxe/nbdboot.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/ipxe/pixie-live-env.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/ipxe/unavailable.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/live_env.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/login.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/src/pixie/web/_templates/settings.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/conftest.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/conftest.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/test_catalog_fetch.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/test_deploy.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/test_exports.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/test_inventory.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/test_pxe.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/integration/test_tftp.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_auth.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_catalog_api.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_catalog_seed.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_event_kinds.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_events_unit.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_fetch_progress.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_healthz.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_live_env_fetch.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_pivot.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_schema.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.1}/tests/test_web_inventory.py +0 -0
|
@@ -11,6 +11,174 @@ operator-facing summary.
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.4.1] - 2026-07-25
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
**New machines default to `pixie-inventory`, one-shot.** A
|
|
19
|
+
freshly-discovered MAC now auto-registers with `pixie-inventory`
|
|
20
|
+
instead of `ipxe-exit`: non-destructive (boots the live env, collects
|
|
21
|
+
lshw + disks, posts them, exits to firmware) and immediately useful --
|
|
22
|
+
every new machine's hardware shows up and the flash modes (which
|
|
23
|
+
require inventory) become available without a manual pass. It is
|
|
24
|
+
one-shot: the first inventory POST flips the binding to `ipxe-exit`, so
|
|
25
|
+
a PXE-first box inventories itself exactly once and never boot-loops.
|
|
26
|
+
With no live env staged the plan degrades to exit, so a bare deploy
|
|
27
|
+
behaves like before until the operator fetches the live env. Override
|
|
28
|
+
per deploy with `PIXIE_DEFAULT_BOOT_MODE` (e.g. `ipxe-exit` for the old
|
|
29
|
+
behaviour).
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
**Live env boots on arbitrary NICs (netboot-pc initramfs is now
|
|
34
|
+
`MODULES=most`).** The live env fetches its squashfs over HTTP from the
|
|
35
|
+
initramfs before pivot-root, so the target's NIC must be driven from
|
|
36
|
+
inside the initrd. It was built the mkinitramfs default `MODULES=dep` --
|
|
37
|
+
only the build host's drivers (plus the DKMS'd r8125) -- so a target
|
|
38
|
+
with a different NIC came up to `initrd` and then stalled forever at the
|
|
39
|
+
squashfs fetch, silently breaking `pixie-inventory` / `-tui` / `-flash`
|
|
40
|
+
on that box (observed on an ASRock Rack board). The netboot-pc bake now
|
|
41
|
+
sets `MODULES=most`, baking the broad Debian-installer driver set so an
|
|
42
|
+
arbitrary lab machine's NIC (and storage) is alive before the fetch.
|
|
43
|
+
Costs some initramfs size; worth it for an appliance whose job is
|
|
44
|
+
booting unknown hardware.
|
|
45
|
+
|
|
46
|
+
**No more `${PIXIE_LIVE_ENV_EXTRA_CMDLINE:-}` literal on the kernel
|
|
47
|
+
cmdline.** On a deploy whose compose runner doesn't expand `${VAR:-}`
|
|
48
|
+
(podman-compose passes the unset default through verbatim), the
|
|
49
|
+
container env held the literal string `${PIXIE_LIVE_ENV_EXTRA_CMDLINE:-}`,
|
|
50
|
+
which pixie then appended to every live-env / nbdboot kernel cmdline.
|
|
51
|
+
Harmless (the kernel ignores the unknown token) but wrong. The
|
|
52
|
+
extra-cmdline resolver now treats a value that is nothing but an
|
|
53
|
+
unexpanded `${...}` placeholder as unset, so it can't leak -- fixed for
|
|
54
|
+
any deploy without regenerating compose.
|
|
55
|
+
|
|
56
|
+
## [0.4.0] - 2026-07-24
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
|
|
60
|
+
**Machines list Image column reads like the new model.** The bound
|
|
61
|
+
image now shows the catalog name linked to its Images page (short sha
|
|
62
|
+
for an orphan blob whose entry was deleted), instead of a bare hash,
|
|
63
|
+
and is blank for boot modes that don't consume an image (ipxe-exit /
|
|
64
|
+
inventory / tui) rather than showing a stale sha.
|
|
65
|
+
|
|
66
|
+
**Catalog table is leaner.** The sources listing drops the inline
|
|
67
|
+
content sha + byte size (image facts that live on the linked Image
|
|
68
|
+
page); the fetched/error/in-flight readiness state stays.
|
|
69
|
+
|
|
70
|
+
**Default timestamp format drops the timezone suffix.** Operator-facing
|
|
71
|
+
timestamps now default to `%Y-%m-%d %H:%M:%S` (24-hour, no ` %Z`); the
|
|
72
|
+
display timezone is still an operator setting, just not repeated on
|
|
73
|
+
every row. Set `PIXIE_DATETIME_FORMAT` or the Settings override to add
|
|
74
|
+
it back.
|
|
75
|
+
|
|
76
|
+
**Overlays are now globally-named single-writer volumes.** A persistent
|
|
77
|
+
nbdboot overlay is no longer a per-`(machine, image, profile)` triple; it
|
|
78
|
+
is a globally-unique named writable volume (`alias`) over ONE base image,
|
|
79
|
+
and the base image is implied by the alias. At most one machine may hold
|
|
80
|
+
an alias at a time: attaching one already held by a different machine is
|
|
81
|
+
rejected in the app ("held by <mac>; detach first"), with qemu-nbd's
|
|
82
|
+
qcow2 image-lock as the backstop. On a machine's detail page the picker
|
|
83
|
+
now offers the aliases that are free (or already held here) plus a
|
|
84
|
+
create-new flow; attaching an existing alias binds the machine to that
|
|
85
|
+
alias's base image. The Overlays page keys on the alias, shows an
|
|
86
|
+
**Attached to** column (a MAC or "free"), and classifies each row as
|
|
87
|
+
serving / held / free / orphaned / missing; Prune still reclaims only the
|
|
88
|
+
orphaned + file-missing rows and leaves a free alias (a deliberate keep)
|
|
89
|
+
alone. On-disk overlays move from
|
|
90
|
+
`overlays/<mac>/<image_sha>/<profile>.qcow2` to a flat
|
|
91
|
+
`overlays/<alias>.qcow2`. Existing state.db rows migrate in place on
|
|
92
|
+
first start: each old overlay becomes `alias = <profile>-<mac_slug>`
|
|
93
|
+
holding its original MAC, its qcow2 path is kept as-is (no large-file
|
|
94
|
+
move), and each machine's binding is rewritten to the same derived alias.
|
|
95
|
+
|
|
96
|
+
**Dashboard speaks the new model.** The tiles now mirror the
|
|
97
|
+
storage/lifecycle vocabulary + the nav: **Machines**, **Catalog**
|
|
98
|
+
(sources you can fetch, with a not-yet-fetched count), **Images** (the
|
|
99
|
+
materialised entities, with on-disk footprint + how many are
|
|
100
|
+
reclaimable), **Overlays** (alias-keyed writable volumes, with disk-used
|
|
101
|
+
+ serving), and **Events** -- instead of the old catalog-images /
|
|
102
|
+
NBD-exports framing. The Acknowledge button was removed from the
|
|
103
|
+
dashboard (it's an action; the dashboard is output-only -- ack lives on
|
|
104
|
+
the Events page).
|
|
105
|
+
|
|
106
|
+
**Catalog is sources-only now.** With Images owning the materialised
|
|
107
|
+
view, the Catalog page drops the NBD-serving column and the
|
|
108
|
+
Stop-export / blob-delete actions (those live on Images). It keeps
|
|
109
|
+
source management -- add, import, Fetch, delete-entry -- and a fetched
|
|
110
|
+
disk-image row now links to its **Image** for footprint, live NBD /
|
|
111
|
+
overlay usage, and GC.
|
|
112
|
+
|
|
113
|
+
**Legacy `/ui/exports` lands on Images.** The kept-alive redirect for
|
|
114
|
+
the old exports URL (and the Stop-export action) now points at the
|
|
115
|
+
Images view, where NBD export usage is surfaced per content sha, rather
|
|
116
|
+
than at Catalog.
|
|
117
|
+
|
|
118
|
+
**Overlay picker shows aliases held elsewhere, disabled.** The
|
|
119
|
+
machine-detail overlay dropdown used to hide any alias held by another
|
|
120
|
+
machine, so an operator searching for it assumed it didn't exist and
|
|
121
|
+
tried to create a duplicate (which the single-writer bind then
|
|
122
|
+
rejected). Held-elsewhere aliases are now shown as a disabled option
|
|
123
|
+
labelled with the holder MAC ("held by `<mac>`") -- visible, but not
|
|
124
|
+
selectable.
|
|
125
|
+
|
|
126
|
+
**Overlays distinguish "pending" from "file missing".** A reserved
|
|
127
|
+
overlay alias whose qcow2 hasn't been lazy-created yet (never booted)
|
|
128
|
+
previously read as *file missing* -- the same alarming state as a
|
|
129
|
+
booted-then-lost overlay -- and Prune would reclaim it as junk. Such an
|
|
130
|
+
overlay is now classified **pending** (benign, awaiting its first
|
|
131
|
+
nbdboot) and is left alone by Prune; *missing* is reserved for an
|
|
132
|
+
overlay whose qcow2 vanished after a prior boot (real data loss). The
|
|
133
|
+
`last_boot_at` timestamp is the discriminator.
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
|
|
137
|
+
**First-contact machines emit a `machine.discovered` audit event.** The
|
|
138
|
+
first time an unknown MAC hits `GET /pxe/<mac>` and is auto-registered,
|
|
139
|
+
pixie now records one `machine.discovered` event (carrying the
|
|
140
|
+
auto-registered boot mode + the client IP); repeat contacts do not
|
|
141
|
+
re-emit. The kind was reserved but never fired before.
|
|
142
|
+
|
|
143
|
+
**Images: the materialised content behind Catalog sources.** A new
|
|
144
|
+
**Images** page (`/ui/images`) separates the *source* (a Catalog entry,
|
|
145
|
+
a URL you can fetch) from the *entity* it produces once fetched (an
|
|
146
|
+
image, identity = the disk content sha). Machines, NBD exports, and
|
|
147
|
+
overlays all key off that sha, so each image rolls up its on-disk
|
|
148
|
+
footprint (raw disk + rootfs + boot bundle + overlays) and every live
|
|
149
|
+
usage -- machines bound, the ephemeral nbdkit export, and per-machine
|
|
150
|
+
qemu-nbd overlays -- with counts that link into the per-usage admin
|
|
151
|
+
surfaces. An **image detail hub** (`/ui/images/<sha>`) lays out the
|
|
152
|
+
artifacts + every usage inline and offers a **guarded delete / blob GC**:
|
|
153
|
+
allowed only when the usage count (the refcount) is zero, it removes the
|
|
154
|
+
whole `blobs/<sha>/` dir (raw disk **and** the `rootfs.raw` the old
|
|
155
|
+
per-entry delete leaked) and clears the sha off every entry that
|
|
156
|
+
resolved to it. The list also surfaces **orphan blobs** -- sha dirs on
|
|
157
|
+
disk with no catalog entry -- which is where the un-GC'd disk pressure
|
|
158
|
+
actually hides; they delete straight through. Catalog is unchanged for
|
|
159
|
+
now.
|
|
160
|
+
|
|
161
|
+
### Fixed
|
|
162
|
+
|
|
163
|
+
**Live-env artifacts are served after a post-startup fetch, no restart
|
|
164
|
+
needed.** The `/boot/pixie-live-env/` mount was created at app startup
|
|
165
|
+
only if the directory already existed, so on a fresh deploy -- where the
|
|
166
|
+
operator stages the netboot-pc bake later via "Fetch live env" -- the
|
|
167
|
+
plan pointed targets at `/boot/pixie-live-env/vmlinuz` and friends that
|
|
168
|
+
then 404'd until pixie was restarted, silently breaking every
|
|
169
|
+
`pixie-inventory` / `-tui` / `-flash` boot. The mount is now created
|
|
170
|
+
unconditionally (dir ensured, `check_dir=False`), so a fetched live-env
|
|
171
|
+
is served immediately.
|
|
172
|
+
|
|
173
|
+
**`pixie-lab purge --all` no longer tracebacks on a root-owned parent.**
|
|
174
|
+
When the deploy dir lives under a directory the operator can't write
|
|
175
|
+
(the common `/opt/pixie` case), purge could empty the dir but not
|
|
176
|
+
remove the dir itself, and surfaced the failure as a raw Python
|
|
177
|
+
traceback. It now clears the state, prints a plain one-line caveat
|
|
178
|
+
("emptied `<dir>`, but could not remove the directory itself ..."), and
|
|
179
|
+
exits 0 -- the purge did its job; only the empty-dir removal was blocked
|
|
180
|
+
by the parent's permissions.
|
|
181
|
+
|
|
14
182
|
## [0.3.2] - 2026-07-24
|
|
15
183
|
|
|
16
184
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pixie-lab
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
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,173 @@
|
|
|
1
|
+
# Boot modes
|
|
2
|
+
|
|
3
|
+
Every machine pixie has seen is bound to exactly one of six boot
|
|
4
|
+
modes. On the target's next PXE request, pixie renders an iPXE plan
|
|
5
|
+
whose shape depends on the mode. The bind form on the machine detail
|
|
6
|
+
page picks the mode by clicking a card; the JSON API accepts the same
|
|
7
|
+
tokens.
|
|
8
|
+
|
|
9
|
+
## The six modes
|
|
10
|
+
|
|
11
|
+
### `ipxe-exit`
|
|
12
|
+
|
|
13
|
+
Pixie exits the iPXE chain. The target's BIOS boot order picks the
|
|
14
|
+
next bootable device. A pure no-op: pixie won't reflash a machine or
|
|
15
|
+
netboot it. This is where `pixie-inventory` self-terminates to (see
|
|
16
|
+
below), and where an operator parks a machine pixie should leave alone.
|
|
17
|
+
|
|
18
|
+
### `pixie-inventory` (default)
|
|
19
|
+
|
|
20
|
+
The target boots pixie's own live env. The `pixie` CLI collects
|
|
21
|
+
disk + NIC + lshw output and POSTs it to `/pxe/<mac>/inventory`,
|
|
22
|
+
then the target reboots to firmware. Prerequisite for
|
|
23
|
+
`pixie-flash-*`: without inventory, pixie doesn't know which disk
|
|
24
|
+
serial to hand the flash pipeline.
|
|
25
|
+
|
|
26
|
+
This is the **default a freshly-discovered MAC auto-registers with**:
|
|
27
|
+
it's non-destructive (touches no disk) and immediately useful (every
|
|
28
|
+
new machine's hardware shows up on `/ui/machines`, and the flash modes
|
|
29
|
+
become available without a manual pass). It is **one-shot** -- on the
|
|
30
|
+
first successful inventory POST pixie flips the binding to `ipxe-exit`,
|
|
31
|
+
so a PXE-first machine inventories itself exactly once and then stops
|
|
32
|
+
touching the boot (no re-inventory loop). Rebinding to
|
|
33
|
+
`pixie-inventory` buys one more pass. If no live env is staged the plan
|
|
34
|
+
degrades to `unavailable`/exit, so a bare deploy behaves like the old
|
|
35
|
+
exit-by-default until the operator fetches the live env. Set
|
|
36
|
+
`PIXIE_DEFAULT_BOOT_MODE=ipxe-exit` to restore the old exit-by-default.
|
|
37
|
+
|
|
38
|
+
### `pixie-tui`
|
|
39
|
+
|
|
40
|
+
The target boots pixie's live env into an interactive TUI. An
|
|
41
|
+
operator drives the wizard on the target's own console (or IP-KVM /
|
|
42
|
+
serial-over-LAN). Useful for one-off image picks that don't need
|
|
43
|
+
recording on pixie's side.
|
|
44
|
+
|
|
45
|
+
### `pixie-flash-once`
|
|
46
|
+
|
|
47
|
+
The target boots pixie's live env, which writes the bound image to
|
|
48
|
+
the picked disk serial, then reboots to firmware. Pixie flips the
|
|
49
|
+
binding to `ipxe-exit` after a successful flash so the next PXE
|
|
50
|
+
lands the target on its freshly-flashed local disk. Requires
|
|
51
|
+
inventory + a target disk serial.
|
|
52
|
+
|
|
53
|
+
### `pixie-flash-always`
|
|
54
|
+
|
|
55
|
+
Same as `pixie-flash-once` but pixie leaves the binding on
|
|
56
|
+
`pixie-flash-always` after the flash. Every PXE re-flashes the
|
|
57
|
+
image; any local changes between reboots are discarded. Useful
|
|
58
|
+
for CI reflash loops where the target is expected to boot from a
|
|
59
|
+
known-clean image each cycle.
|
|
60
|
+
|
|
61
|
+
### `nbdboot`
|
|
62
|
+
|
|
63
|
+
The target boots the image's OWN kernel (extracted from the sibling
|
|
64
|
+
netboot bundle) and mounts the image over NBD. By default, root is an
|
|
65
|
+
overlay-on-tmpfs: writes go to RAM, nothing propagates back to the
|
|
66
|
+
source blob. Multiple targets can nbdboot the same image
|
|
67
|
+
simultaneously because they each get their own overlay.
|
|
68
|
+
|
|
69
|
+
**Persistent overlays** flip a target from ephemeral to dev mode
|
|
70
|
+
without changing anything else about the bind. On the machine detail
|
|
71
|
+
page, the `Overlay alias` field is blank by default (ephemeral,
|
|
72
|
+
unchanged behaviour) or names a persistent overlay volume (e.g.
|
|
73
|
+
`simon`, `karl`, `ci-with-nvme-tools`). A non-blank alias attaches a
|
|
74
|
+
qcow2 volume with the image's base blob as `backing_file`, served by
|
|
75
|
+
`qemu-nbd` at a dedicated port. The target mounts the NBD device
|
|
76
|
+
read-write; system-level changes (apt-installed packages,
|
|
77
|
+
hardware-specific config, kernel modules) land on the qcow2 and
|
|
78
|
+
survive reboots.
|
|
79
|
+
|
|
80
|
+
An overlay is a **globally-unique named volume over one base image**,
|
|
81
|
+
not a per-machine file. See [](#overlays-are-volumes-not-per-machine-files)
|
|
82
|
+
below for how the alias, its base image, and single-writer access
|
|
83
|
+
work.
|
|
84
|
+
|
|
85
|
+
**Kexec into a locally-installed kernel.** The netboot bundle owns
|
|
86
|
+
the kernel and initrd pixie serves. Installing `linux-image-*` on the
|
|
87
|
+
target's persistent overlay writes files to `/boot` but the next
|
|
88
|
+
power-cycle refetches pixie's kernel and those files sit unused.
|
|
89
|
+
`kexec` bridges that gap: the netboot kernel comes up, then the
|
|
90
|
+
operator runs
|
|
91
|
+
`kexec -l /boot/vmlinuz-<v> --initrd=/boot/initrd.img-<v>
|
|
92
|
+
--reuse-cmdline && systemctl kexec` to switch to the local kernel
|
|
93
|
+
without going through firmware. Every netboot-shipping nosi variant
|
|
94
|
+
now bakes `kexec-tools` in; see nosi's [Custom kernel under netboot
|
|
95
|
+
(kexec)](https://safl.github.io/nosi/kexec.html) for the full
|
|
96
|
+
workflow. Recovery from a bad kernel is a power-cycle back to
|
|
97
|
+
pixie's kernel; nothing kexec's automatically, so a broken install
|
|
98
|
+
never becomes a boot loop.
|
|
99
|
+
|
|
100
|
+
## Overlays are volumes, not per-machine files
|
|
101
|
+
|
|
102
|
+
An overlay is a **globally-unique named writable volume** layered over
|
|
103
|
+
exactly one base image. The alias is the identity, not the machine:
|
|
104
|
+
`data/overlays/<alias>.qcow2`, a single qcow2 whose `backing_file` is
|
|
105
|
+
the image's base blob. There is no `(mac, image, profile)` key and no
|
|
106
|
+
per-machine directory; two machines cannot mint independent files
|
|
107
|
+
under the same name, because the name is the volume.
|
|
108
|
+
|
|
109
|
+
**The alias implies its image.** Attaching an *existing* alias binds
|
|
110
|
+
the machine to that overlay's base image; you don't re-pick the image
|
|
111
|
+
on the bind form, the volume already knows it. Attaching a *new* alias
|
|
112
|
+
takes the image you selected and lays a fresh qcow2 over it. Because
|
|
113
|
+
the alias carries the image, moving a volume between machines is just
|
|
114
|
+
re-binding the alias; the base image follows.
|
|
115
|
+
|
|
116
|
+
**Single-writer, enforced in the app.** At most one machine holds an
|
|
117
|
+
alias at a time. Binding an alias already attached to another machine
|
|
118
|
+
is refused ("overlay `<alias>` held by `<mac>`; detach first") on both
|
|
119
|
+
the operator form and the `PUT /machines/{mac}` API, before any qcow2
|
|
120
|
+
is touched. The qemu qcow2 lock is the backstop; the app-level check
|
|
121
|
+
is the operator-facing guard. Rebinding a machine to ephemeral, to a
|
|
122
|
+
different alias, or to a non-`nbdboot` mode releases the hold it had.
|
|
123
|
+
|
|
124
|
+
**Managing volumes.** The Overlays page (`/ui/overlays`) lists every
|
|
125
|
+
volume with its state: *serving* (a live machine is bound to it and
|
|
126
|
+
`qemu-nbd` is up), *held* (attached to a machine, nothing serving),
|
|
127
|
+
*free* (unattached, kept for a future bind), *orphaned* (attached to a
|
|
128
|
+
MAC with no machine row), or *missing* (the qcow2 is gone). **Reset**
|
|
129
|
+
tears down `qemu-nbd` and unlinks one volume's qcow2 so the next boot
|
|
130
|
+
lazy-creates it fresh from the base; **Prune** reclaims the junk
|
|
131
|
+
states (orphaned + missing) in bulk and deliberately leaves free
|
|
132
|
+
volumes alone.
|
|
133
|
+
|
|
134
|
+
## Bindings
|
|
135
|
+
|
|
136
|
+
A binding is what pixie serves a MAC next time it PXEs: a boot mode,
|
|
137
|
+
plus (for the modes that need one) an image, plus (for `nbdboot`) an
|
|
138
|
+
optional overlay alias. A fresh MAC auto-registers with
|
|
139
|
+
`PIXIE_DEFAULT_BOOT_MODE` (default `pixie-inventory`, which
|
|
140
|
+
self-terminates to `ipxe-exit` after one inventory pass) and no image
|
|
141
|
+
on first contact; the machine detail page is where an operator promotes
|
|
142
|
+
it. Saving the bind form persists all three fields
|
|
143
|
+
together, and the plan renderer reads them per PXE request: it resolves
|
|
144
|
+
the image's netboot bundle, resolves the alias to its overlay (and
|
|
145
|
+
base image), ensures the NBD export is up, and renders the plan. A
|
|
146
|
+
binding that can't be satisfied (no image bound, bundle not fetched,
|
|
147
|
+
alias held elsewhere) degrades to an `unavailable` plan whose comment
|
|
148
|
+
names the reason, rather than serving a broken boot.
|
|
149
|
+
|
|
150
|
+
## Prerequisites at a glance
|
|
151
|
+
|
|
152
|
+
| Mode | Needs image | Needs inventory | Needs target disk |
|
|
153
|
+
|------|-------------|-----------------|-------------------|
|
|
154
|
+
| `ipxe-exit` | no | no | no |
|
|
155
|
+
| `pixie-inventory` | no | no | no |
|
|
156
|
+
| `pixie-tui` | no | no | no |
|
|
157
|
+
| `pixie-flash-once` | yes | yes | yes |
|
|
158
|
+
| `pixie-flash-always` | yes | yes | yes |
|
|
159
|
+
| `nbdboot` | yes (with sibling netboot bundle) | no | no |
|
|
160
|
+
|
|
161
|
+
The bind form on the machine detail page enforces these prerequisites
|
|
162
|
+
client-side; the server enforces them again with a 422 on the
|
|
163
|
+
`PUT /machines/{mac}` endpoint.
|
|
164
|
+
|
|
165
|
+
## Extra kernel cmdline
|
|
166
|
+
|
|
167
|
+
Every mode that boots pixie's live env or the nbdboot chain accepts
|
|
168
|
+
extra kernel-cmdline tokens. Deploy-wide default:
|
|
169
|
+
`PIXIE_LIVE_ENV_EXTRA_CMDLINE` in the container env. Per-machine
|
|
170
|
+
override on the bind form: the `Extra kernel cmdline` text field.
|
|
171
|
+
A non-blank per-machine value fully overrides the deploy-wide default
|
|
172
|
+
for that ONE machine, so hardware quirks stay scoped to the target
|
|
173
|
+
that needs them. See [](hardware-quirks.md) for known-good tokens.
|
|
@@ -69,7 +69,7 @@ unattended). Flags choose how far the wipe goes:
|
|
|
69
69
|
|
|
70
70
|
- `--data` - also delete `data/`: `state.db` (catalog, machines,
|
|
71
71
|
events, exports, overlays, settings), every fetched blob and unpacked
|
|
72
|
-
artifact, all
|
|
72
|
+
artifact, all overlay volumes, and the staged `live-env/`.
|
|
73
73
|
`data/` is a bind mount (`./data:/var/lib/pixie`), not a named
|
|
74
74
|
volume, so purge unlinks it directly - `podman compose down -v`
|
|
75
75
|
alone would not touch it.
|
|
@@ -135,10 +135,18 @@ if HTTP is proxied but NBD is direct.
|
|
|
135
135
|
to every pixie-live-env chain. Common values are hardware-quirk
|
|
136
136
|
workarounds; see [](hardware-quirks.md).
|
|
137
137
|
|
|
138
|
+
**`PIXIE_DEFAULT_BOOT_MODE`** (default: `pixie-inventory`) - boot mode a
|
|
139
|
+
freshly-discovered MAC auto-registers with. The default is
|
|
140
|
+
non-destructive (collect + post inventory, then exit) and one-shot (the
|
|
141
|
+
first inventory POST flips it to `ipxe-exit`, so a PXE-first box does
|
|
142
|
+
not re-inventory). Set to `ipxe-exit` for the old exit-by-default
|
|
143
|
+
behaviour. See [](boot-modes.md).
|
|
144
|
+
|
|
138
145
|
**`PIXIE_DATA_DIR`** (default: `/var/lib/pixie`) - state root. Holds
|
|
139
146
|
`state.db`, `blobs/` (fetched image bytes), `artifacts/` (extracted
|
|
140
|
-
netboot bundles), `overlays/<
|
|
141
|
-
(
|
|
147
|
+
netboot bundles), `overlays/<alias>.qcow2`
|
|
148
|
+
(globally-named single-writer overlay volumes for nbdboot; see
|
|
149
|
+
[](boot-modes.md)),
|
|
142
150
|
`live-env/` (staged pixie live env).
|
|
143
151
|
|
|
144
152
|
**`PIXIE_LIVE_ENV_DIR`** (default: `$PIXIE_DATA_DIR/live-env`) - the
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
This walks through a first pixie deploy: install, bring the container
|
|
4
|
+
up, point DHCP at it, and boot a first target.
|
|
5
|
+
|
|
6
|
+
## Run the deploy generator (no install)
|
|
7
|
+
|
|
8
|
+
The `pixie-lab` commands (`init` / `deploy` / `purge`) are one-off
|
|
9
|
+
admin tasks, so run them ephemerally with `uv` instead of installing
|
|
10
|
+
anything:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
uv tool run pixie-lab init
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`uv tool run pixie-lab` fetches the distribution into a temporary
|
|
17
|
+
isolated environment, runs the command, and leaves nothing behind: no
|
|
18
|
+
system Python pollution, nothing to uninstall. Every command below is
|
|
19
|
+
invoked the same way. (If you would rather keep it around, `uv tool
|
|
20
|
+
install pixie-lab` installs the `pixie-lab` command persistently.)
|
|
21
|
+
|
|
22
|
+
The distribution ships two console-scripts: `pixie-lab` (the deploy
|
|
23
|
+
generator you run here) and `pixie` (the operator TUI baked into the
|
|
24
|
+
pixie live env; targets run it after booting the live env, operators
|
|
25
|
+
don't call it on their workstation).
|
|
26
|
+
|
|
27
|
+
## Generate the deploy bundle
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
mkdir /opt/pixie && cd /opt/pixie
|
|
31
|
+
uv tool run pixie-lab init
|
|
32
|
+
${EDITOR:-vi} envvars # set PIXIE_HOST_ADDR + PIXIE_ADMIN_PASSWORD
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`uv tool run pixie-lab init` writes `compose.yml`, `envvars` (with placeholder
|
|
36
|
+
values), and `envvars.example` into the current directory. Edit
|
|
37
|
+
`envvars` to point pixie at your LAN address and set a real admin
|
|
38
|
+
password.
|
|
39
|
+
|
|
40
|
+
## Bring pixie up
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
podman compose --env-file envvars up -d
|
|
44
|
+
curl http://<PIXIE_HOST_ADDR>:8080/healthz
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The compose file runs pixie under `network_mode: host` so udp/69
|
|
48
|
+
(TFTP) plus the NBD port range plus tcp/8080 (HTTP) all reach the
|
|
49
|
+
LAN without publish gymnastics.
|
|
50
|
+
|
|
51
|
+
## Point DHCP at pixie
|
|
52
|
+
|
|
53
|
+
Set your DHCP server to chain PXE targets through pixie's TFTP and
|
|
54
|
+
iPXE bootstrap. See [](deployment.md#dhcp-handoff) for BIOS + UEFI
|
|
55
|
+
dnsmasq recipes.
|
|
56
|
+
|
|
57
|
+
## Add a first catalog entry
|
|
58
|
+
|
|
59
|
+
Open `http://<PIXIE_HOST_ADDR>:8080/ui/catalog` in a browser, log in
|
|
60
|
+
with your admin password, and add a catalog entry with a source URL.
|
|
61
|
+
Hit Fetch. Pixie pulls the bytes to disk (and for `img.gz` / `img.zst`
|
|
62
|
+
inputs, decompresses on the way in). The row flips to `fetched` when
|
|
63
|
+
the pipeline lands.
|
|
64
|
+
|
|
65
|
+
## Bind a machine
|
|
66
|
+
|
|
67
|
+
Once a target has PXEd at least once, it appears on `/ui/machines`.
|
|
68
|
+
Click its MAC to open the machine detail page. Pick a boot mode from
|
|
69
|
+
the card grid, pick an image, and Save. On the target's next PXE,
|
|
70
|
+
pixie serves the plan you bound.
|
|
71
|
+
|
|
72
|
+
See [](boot-modes.md) for what each mode does and how bindings pin a
|
|
73
|
+
machine to an image and, for `nbdboot`, an overlay volume.
|
|
74
|
+
|
|
75
|
+
## Tear it down
|
|
76
|
+
|
|
77
|
+
`uv tool run pixie-lab purge` is the inverse of the deploy. Run it from
|
|
78
|
+
the deploy directory (or pass the path):
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
uv tool run pixie-lab purge # stop + remove the container only
|
|
82
|
+
uv tool run pixie-lab purge --data # also DELETE data/ (state.db, blobs, artifacts, overlays, live-env)
|
|
83
|
+
uv tool run pixie-lab purge --images # also remove the pixie container image
|
|
84
|
+
uv tool run pixie-lab purge --all # container + image + data/ + the deploy directory itself
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Purge prints its plan and gates every variant behind a `y/N`
|
|
88
|
+
confirmation; pass `--yes` to skip the prompt for scripted teardown.
|
|
89
|
+
Even the plain stop is impactful: it drops every nbdkit / qemu-nbd
|
|
90
|
+
export, so any target currently booted `nbdboot` off pixie loses its
|
|
91
|
+
NBD root at that moment. The `--data` and `--all` deletions are
|
|
92
|
+
irreversible, so the confirmation is deliberate.
|
|
93
|
+
|
|
94
|
+
The single-shot `uv tool run pixie-lab deploy` is the mirror image of purge: it
|
|
95
|
+
runs `init`, auto-fills `envvars`, brings the stack up, and waits on
|
|
96
|
+
`/healthz` in one command, for when you don't need to hand-edit the
|
|
97
|
+
generated files first.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# pixie netboot-pc live env: bake a BROAD driver set into the initramfs.
|
|
2
|
+
#
|
|
3
|
+
# The live env's very first action after the kernel hands off is to
|
|
4
|
+
# fetch its squashfs over HTTP from the kernel cmdline `fetch=` param
|
|
5
|
+
# (Debian live-boot). That means the target's NIC must be driven from
|
|
6
|
+
# INSIDE the initramfs, before pivot-root -- iPXE loaded vmlinuz+initrd
|
|
7
|
+
# over the firmware's network stack, but from Linux on it's the kernel
|
|
8
|
+
# module that matters.
|
|
9
|
+
#
|
|
10
|
+
# mkinitramfs' default is MODULES=dep: only the drivers the BUILD HOST
|
|
11
|
+
# needs. So the netboot-pc initrd shipped drivers for the builder's NIC
|
|
12
|
+
# (plus the r8125 DKMS hook) and nothing else -- a target with a
|
|
13
|
+
# different NIC (e.g. matx / ASRock Rack) came up to `initrd` and then
|
|
14
|
+
# stalled forever at the squashfs fetch, because its NIC had no driver.
|
|
15
|
+
#
|
|
16
|
+
# MODULES=most bakes the broad Debian-installer driver set, so an
|
|
17
|
+
# arbitrary lab box's NIC (and storage) is alive before the fetch.
|
|
18
|
+
# Costs initramfs size (~2x); acceptable for a netboot appliance whose
|
|
19
|
+
# whole job is booting unknown hardware. Narrow to an explicit NIC list
|
|
20
|
+
# in /etc/initramfs-tools/modules later if size becomes a problem and
|
|
21
|
+
# the target NICs are known.
|
|
22
|
+
MODULES=most
|
|
@@ -311,10 +311,32 @@ def _cmd_purge(args: argparse.Namespace) -> int:
|
|
|
311
311
|
shutil.rmtree(data_dir)
|
|
312
312
|
print(f"pixie-lab purge: removed {data_dir}", file=sys.stderr)
|
|
313
313
|
|
|
314
|
-
# 4. Delete the deploy directory itself.
|
|
314
|
+
# 4. Delete the deploy directory itself. ``dest`` often sits under a
|
|
315
|
+
# root-owned parent (e.g. /opt), where an unprivileged operator can
|
|
316
|
+
# empty the dir but can't rmdir it -- rmtree clears the contents,
|
|
317
|
+
# then raises on the final rmdir. Report that plainly instead of
|
|
318
|
+
# dumping a traceback; the state is gone either way, so it's a
|
|
319
|
+
# caveat, not a failure.
|
|
315
320
|
if remove_dir and dest.exists():
|
|
316
|
-
|
|
317
|
-
|
|
321
|
+
try:
|
|
322
|
+
shutil.rmtree(dest)
|
|
323
|
+
print(f"pixie-lab purge: removed {dest}", file=sys.stderr)
|
|
324
|
+
except OSError as exc:
|
|
325
|
+
leftover = sorted(p.name for p in dest.iterdir()) if dest.is_dir() else []
|
|
326
|
+
if not leftover:
|
|
327
|
+
print(
|
|
328
|
+
f"pixie-lab purge: emptied {dest}, but could not remove the "
|
|
329
|
+
f"directory itself ({exc.strerror or exc}) -- its parent is not "
|
|
330
|
+
f"writable (a root-owned /opt, say). The empty dir is harmless; "
|
|
331
|
+
f"you can redeploy into it or 'sudo rmdir' it.",
|
|
332
|
+
file=sys.stderr,
|
|
333
|
+
)
|
|
334
|
+
else:
|
|
335
|
+
print(
|
|
336
|
+
f"pixie-lab purge: could not fully remove {dest} "
|
|
337
|
+
f"({exc.strerror or exc}); leftover: {', '.join(leftover)}",
|
|
338
|
+
file=sys.stderr,
|
|
339
|
+
)
|
|
318
340
|
|
|
319
341
|
return 0
|
|
320
342
|
|
|
@@ -21,7 +21,9 @@ from __future__ import annotations
|
|
|
21
21
|
# ---------- catalog + fetch pipeline ---------------------------------
|
|
22
22
|
#
|
|
23
23
|
# Every catalog-store mutation emits one of these. ``subject_kind`` is
|
|
24
|
-
#
|
|
24
|
+
# ``"entry"`` (``subject_id`` = the catalog entry name) for the per-row
|
|
25
|
+
# kinds; the ``catalog.import.*`` pair is catalog-scoped instead
|
|
26
|
+
# (``subject_kind = "catalog"``) since one import touches many entries.
|
|
25
27
|
|
|
26
28
|
CATALOG_ENTRY_ADDED = "catalog.entry.added"
|
|
27
29
|
"""A new row landed via POST /catalog/entries, POST /ui/catalog/add,
|
|
@@ -95,36 +97,37 @@ EXPORT_NBDKIT_EXITED = "export.nbdkit.exited"
|
|
|
95
97
|
(``_refresh_row`` noticed no live proc for a ``running`` row).
|
|
96
98
|
``details.previous_port`` + ``details.error`` explain."""
|
|
97
99
|
|
|
98
|
-
# ---------- persistent overlays (
|
|
100
|
+
# ---------- persistent overlays (alias-keyed volumes) ---------------
|
|
99
101
|
#
|
|
100
|
-
# ``subject_kind`` is always ``"
|
|
101
|
-
#
|
|
102
|
+
# ``subject_kind`` is always ``"overlay"``; ``subject_id`` is the
|
|
103
|
+
# globally-unique ``alias`` (``""`` for a fleet-wide bulk action). An
|
|
104
|
+
# overlay is a single-writer qcow2 volume over one base image, not a
|
|
105
|
+
# per-machine file; ``details`` carries ``alias`` / ``image_sha`` /
|
|
106
|
+
# ``qcow2_path`` as relevant.
|
|
102
107
|
|
|
103
108
|
OVERLAY_CREATED = "overlay.created"
|
|
104
|
-
"""
|
|
105
|
-
|
|
106
|
-
``
|
|
109
|
+
"""An alias-keyed qcow2 overlay was materialised for the first time
|
|
110
|
+
(lazy-created on the first nbdboot render, or after a Reset).
|
|
111
|
+
``details`` carries ``alias``, ``image_sha``, and ``qcow2_path``."""
|
|
107
112
|
|
|
108
113
|
OVERLAY_RESET = "overlay.reset"
|
|
109
|
-
"""Operator hit Reset
|
|
110
|
-
terminated, the qcow2
|
|
114
|
+
"""Operator hit Reset (one alias) or Prune (bulk) on the Overlays
|
|
115
|
+
page: the qemu-nbd was terminated, the qcow2 unlinked, the overlays
|
|
116
|
+
row deleted. ``subject_id`` is the alias for a single Reset, ``""``
|
|
117
|
+
for a bulk Prune (``details.pruned`` counts the reclaimed volumes).
|
|
111
118
|
Next plan render lazily creates a fresh overlay from the base."""
|
|
112
119
|
|
|
113
|
-
OVERLAY_BOOTED = "overlay.booted"
|
|
114
|
-
"""Plan render for an already-existing overlay row (heartbeat).
|
|
115
|
-
Emitted on every persistent nbdboot render so an operator can grep
|
|
116
|
-
the events log for "which overlays am I actually using?"."""
|
|
117
|
-
|
|
118
120
|
# ---------- machines + PXE ------------------------------------------
|
|
119
121
|
#
|
|
120
122
|
# ``subject_kind`` is always ``"machine"``; ``subject_id`` is the
|
|
121
123
|
# canonical MAC address.
|
|
122
124
|
|
|
123
125
|
MACHINE_DISCOVERED = "machine.discovered"
|
|
124
|
-
"""First-ever GET /pxe/<mac> for a MAC pixie has not seen before.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
via the ``pxe.plan.rendered`` event
|
|
126
|
+
"""First-ever GET /pxe/<mac> for a MAC pixie has not seen before. The
|
|
127
|
+
``/pxe/<mac>`` route detects the absent row before ``touch_seen``
|
|
128
|
+
auto-registers it and emits this once; subsequent hits do NOT emit
|
|
129
|
+
(they update ``last_seen_at`` via the ``pxe.plan.rendered`` event
|
|
130
|
+
instead). ``details.boot_mode`` is the auto-registered default."""
|
|
128
131
|
|
|
129
132
|
MACHINE_BOUND = "machine.bound"
|
|
130
133
|
"""First bind for a MAC: PUT /machines/<mac> or POST
|
|
@@ -232,7 +235,6 @@ KNOWN_EVENT_KINDS: frozenset[str] = frozenset(
|
|
|
232
235
|
EXPORT_NBDKIT_EXITED,
|
|
233
236
|
OVERLAY_CREATED,
|
|
234
237
|
OVERLAY_RESET,
|
|
235
|
-
OVERLAY_BOOTED,
|
|
236
238
|
MACHINE_DISCOVERED,
|
|
237
239
|
MACHINE_BOUND,
|
|
238
240
|
MACHINE_BINDING_CHANGED,
|