pixie-lab 0.3.2__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.2 → pixie_lab-0.4.0}/CHANGELOG.md +126 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/PKG-INFO +1 -1
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/src/boot-modes.md +63 -23
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/pyproject.toml +1 -1
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/deploy/_main.py +25 -3
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/events/_kinds.py +21 -19
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/exports/_store.py +118 -80
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/machines/_routes.py +23 -7
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/machines/_store.py +56 -30
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/pxe/_renderer.py +62 -82
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/pxe/_routes.py +13 -0
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/src/pixie/web/_overlays.py +68 -50
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_settings_store.py +7 -5
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/catalog.html +21 -57
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/catalog_detail.html +1 -1
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/layout.html +3 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/machine_detail.html +88 -69
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/machines.html +16 -5
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/overlays.html +36 -29
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/main.py +303 -114
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_deploy_unit.py +36 -0
- {pixie_lab-0.3.2 → 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.2 → 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.2 → pixie_lab-0.4.0}/tests/test_pxe_plan_json.py +44 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_settings.py +4 -1
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_ui_pages.py +44 -6
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_web_bind_preview.py +11 -7
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/uv.lock +1 -1
- 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.0}/.dockerignore +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/.github/workflows/cicd.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/.github/workflows/docs.yml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/.gitignore +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/Containerfile +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/LICENSE +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/Makefile +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/PLAN.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/README.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/netboot-pc.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-flash-always.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-flash.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-inventory.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-nbdboot.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-pxe-tui.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-pxe.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/test-usb-ventoy.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/configs/usbboot-pc.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/live_build.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/pixie_ipxe_build.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/pixie_wheel_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/pxe_flash_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/pxe_inventory_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/pxe_prepare.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/pxe_run_chain_test.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/usb_iso_build.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/usb_iso_verify.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/usb_ventoy_guest_start.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/scripts/usb_ventoy_stage.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/netboot-pc.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-flash-always.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-flash.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-inventory.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-nbdboot.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe-tui.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-pxe.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/test-usb-ventoy.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/cijoe/tasks/usbboot-pc.yaml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/audit.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/src/conf.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/src/hardware-quirks.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/src/index.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/tooling/README.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/tooling/pyproject.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/tooling/src/pixie_docs/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/docs/tooling/src/pixie_docs/cli.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/README.md +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/auxiliary/cloudinit-metadata.meta +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/auxiliary/ipxe-embed.ipxe +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/auxiliary/ipxe-local-general.h +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/auto/config +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/archives/backports.list.binary +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/archives/backports.list.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/bootloaders/grub-efi/splash.png +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/bootloaders/syslinux/splash.png +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0500-pixie-install.hook.chroot +0 -0
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0600-pixie-r8125-dkms.hook.chroot +0 -0
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0800-pixie-ssh-live.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0900-pixie-enable-services.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/hooks/normal/0980-pixie-apt-validate.hook.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/issue +0 -0
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/motd +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/etc/profile.d/pixie-version.sh +0 -0
- {pixie_lab-0.3.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → 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.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-boot-banner +0 -0
- {pixie_lab-0.3.2 → 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.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-images-discover +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-on-tty1 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-trace +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-usb-grow +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/package-lists/pixie-base.list.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/package-lists/pixie-flash.list.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/preferences/backports.pref.binary +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/pixie-media/live-build/config/preferences/backports.pref.chroot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/_partition.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/_util.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/_fetcher.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/_live_env.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/_routes.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/_schema.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/_store.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/catalog/catalog.toml +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/deploy/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/deploy/_templates.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/disks.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/events/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/events/_log.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/events/_routes.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/exports/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/exports/_routes.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/exports/_supervisor.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/flash.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/images.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/machines/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/oras.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/pivot/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/pivot/nbdboot +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/pxe/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/tftp/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/tftp/_supervisor.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/tui/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/tui/_app.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/tui_catalog.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_auth.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_inventory.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/.gitkeep +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/bootstrap-icons.min.css +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/bootstrap.min.css +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/fonts/bootstrap-icons.woff +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/fonts/bootstrap-icons.woff2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/htmx.min.js +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/pixie-favicon.png +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_static/sse.js +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_table_state.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/_partials/page_description.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/_partials/recent_events.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/_partials/table_helpers.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/events.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/bootstrap.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/exit.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/nbdboot.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/pixie-live-env.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/ipxe/unavailable.j2 +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/live_env.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/login.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/src/pixie/web/_templates/settings.html +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/conftest.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/__init__.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/conftest.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/test_catalog_fetch.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/test_deploy.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/test_exports.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/test_inventory.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/test_pxe.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/integration/test_tftp.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_auth.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_catalog_api.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_catalog_seed.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_event_kinds.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_events_unit.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_fetch_progress.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_healthz.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_live_env_fetch.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_pivot.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_schema.py +0 -0
- {pixie_lab-0.3.2 → pixie_lab-0.4.0}/tests/test_web_inventory.py +0 -0
|
@@ -11,6 +11,132 @@ 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
|
+
|
|
14
140
|
## [0.3.2] - 2026-07-24
|
|
15
141
|
|
|
16
142
|
### Added
|
|
@@ -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
|
|
@@ -54,29 +54,21 @@ overlay-on-tmpfs: writes go to RAM, nothing propagates back to the
|
|
|
54
54
|
source blob. Multiple targets can nbdboot the same image
|
|
55
55
|
simultaneously because they each get their own overlay.
|
|
56
56
|
|
|
57
|
-
**Persistent overlays** flip a
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`data/overlays/<mac>/<image_sha>/<profile>.qcow2`. The **Reset**
|
|
73
|
-
button on the machine detail page tears down `qemu-nbd`, unlinks the
|
|
74
|
-
qcow2, and lets the next boot lazy-create a fresh overlay from the
|
|
75
|
-
base.
|
|
76
|
-
|
|
77
|
-
Concurrency is by construction: a MAC boots one target at a time, so
|
|
78
|
-
two machines can never contend for the same qcow2. There is no
|
|
79
|
-
holder-tracking or force-reclaim.
|
|
57
|
+
**Persistent overlays** flip a target from ephemeral to dev mode
|
|
58
|
+
without changing anything else about the bind. On the machine detail
|
|
59
|
+
page, the `Overlay alias` field is blank by default (ephemeral,
|
|
60
|
+
unchanged behaviour) or names a persistent overlay volume (e.g.
|
|
61
|
+
`simon`, `karl`, `ci-with-nvme-tools`). A non-blank alias attaches a
|
|
62
|
+
qcow2 volume with the image's base blob as `backing_file`, served by
|
|
63
|
+
`qemu-nbd` at a dedicated port. The target mounts the NBD device
|
|
64
|
+
read-write; system-level changes (apt-installed packages,
|
|
65
|
+
hardware-specific config, kernel modules) land on the qcow2 and
|
|
66
|
+
survive reboots.
|
|
67
|
+
|
|
68
|
+
An overlay is a **globally-unique named volume over one base image**,
|
|
69
|
+
not a per-machine file. See [](#overlays-are-volumes-not-per-machine-files)
|
|
70
|
+
below for how the alias, its base image, and single-writer access
|
|
71
|
+
work.
|
|
80
72
|
|
|
81
73
|
**Kexec into a locally-installed kernel.** The netboot bundle owns
|
|
82
74
|
the kernel and initrd pixie serves. Installing `linux-image-*` on the
|
|
@@ -93,6 +85,54 @@ workflow. Recovery from a bad kernel is a power-cycle back to
|
|
|
93
85
|
pixie's kernel; nothing kexec's automatically, so a broken install
|
|
94
86
|
never becomes a boot loop.
|
|
95
87
|
|
|
88
|
+
## Overlays are volumes, not per-machine files
|
|
89
|
+
|
|
90
|
+
An overlay is a **globally-unique named writable volume** layered over
|
|
91
|
+
exactly one base image. The alias is the identity, not the machine:
|
|
92
|
+
`data/overlays/<alias>.qcow2`, a single qcow2 whose `backing_file` is
|
|
93
|
+
the image's base blob. There is no `(mac, image, profile)` key and no
|
|
94
|
+
per-machine directory; two machines cannot mint independent files
|
|
95
|
+
under the same name, because the name is the volume.
|
|
96
|
+
|
|
97
|
+
**The alias implies its image.** Attaching an *existing* alias binds
|
|
98
|
+
the machine to that overlay's base image; you don't re-pick the image
|
|
99
|
+
on the bind form, the volume already knows it. Attaching a *new* alias
|
|
100
|
+
takes the image you selected and lays a fresh qcow2 over it. Because
|
|
101
|
+
the alias carries the image, moving a volume between machines is just
|
|
102
|
+
re-binding the alias; the base image follows.
|
|
103
|
+
|
|
104
|
+
**Single-writer, enforced in the app.** At most one machine holds an
|
|
105
|
+
alias at a time. Binding an alias already attached to another machine
|
|
106
|
+
is refused ("overlay `<alias>` held by `<mac>`; detach first") on both
|
|
107
|
+
the operator form and the `PUT /machines/{mac}` API, before any qcow2
|
|
108
|
+
is touched. The qemu qcow2 lock is the backstop; the app-level check
|
|
109
|
+
is the operator-facing guard. Rebinding a machine to ephemeral, to a
|
|
110
|
+
different alias, or to a non-`nbdboot` mode releases the hold it had.
|
|
111
|
+
|
|
112
|
+
**Managing volumes.** The Overlays page (`/ui/overlays`) lists every
|
|
113
|
+
volume with its state: *serving* (a live machine is bound to it and
|
|
114
|
+
`qemu-nbd` is up), *held* (attached to a machine, nothing serving),
|
|
115
|
+
*free* (unattached, kept for a future bind), *orphaned* (attached to a
|
|
116
|
+
MAC with no machine row), or *missing* (the qcow2 is gone). **Reset**
|
|
117
|
+
tears down `qemu-nbd` and unlinks one volume's qcow2 so the next boot
|
|
118
|
+
lazy-creates it fresh from the base; **Prune** reclaims the junk
|
|
119
|
+
states (orphaned + missing) in bulk and deliberately leaves free
|
|
120
|
+
volumes alone.
|
|
121
|
+
|
|
122
|
+
## Bindings
|
|
123
|
+
|
|
124
|
+
A binding is what pixie serves a MAC next time it PXEs: a boot mode,
|
|
125
|
+
plus (for the modes that need one) an image, plus (for `nbdboot`) an
|
|
126
|
+
optional overlay alias. A fresh MAC auto-registers as `ipxe-exit` with
|
|
127
|
+
no image on first contact; the machine detail page is where an
|
|
128
|
+
operator promotes it. Saving the bind form persists all three fields
|
|
129
|
+
together, and the plan renderer reads them per PXE request: it resolves
|
|
130
|
+
the image's netboot bundle, resolves the alias to its overlay (and
|
|
131
|
+
base image), ensures the NBD export is up, and renders the plan. A
|
|
132
|
+
binding that can't be satisfied (no image bound, bundle not fetched,
|
|
133
|
+
alias held elsewhere) degrades to an `unavailable` plan whose comment
|
|
134
|
+
names the reason, rather than serving a broken boot.
|
|
135
|
+
|
|
96
136
|
## Prerequisites at a glance
|
|
97
137
|
|
|
98
138
|
| Mode | Needs image | Needs inventory | Needs target disk |
|
|
@@ -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.
|
|
@@ -137,8 +137,9 @@ workarounds; see [](hardware-quirks.md).
|
|
|
137
137
|
|
|
138
138
|
**`PIXIE_DATA_DIR`** (default: `/var/lib/pixie`) - state root. Holds
|
|
139
139
|
`state.db`, `blobs/` (fetched image bytes), `artifacts/` (extracted
|
|
140
|
-
netboot bundles), `overlays/<
|
|
141
|
-
(
|
|
140
|
+
netboot bundles), `overlays/<alias>.qcow2`
|
|
141
|
+
(globally-named single-writer overlay volumes for nbdboot; see
|
|
142
|
+
[](boot-modes.md)),
|
|
142
143
|
`live-env/` (staged pixie live env).
|
|
143
144
|
|
|
144
145
|
**`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.
|
|
@@ -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,
|