pixie-lab 0.1.0__tar.gz → 0.2.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.1.0 → pixie_lab-0.2.0}/CHANGELOG.md +73 -4
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/Containerfile +4 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/PKG-INFO +8 -6
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/README.md +7 -5
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/test-pxe-nbdboot.toml +59 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/pxe_run_chain_test.py +41 -5
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/src/boot-modes.md +40 -1
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/src/deployment.md +77 -3
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/src/hardware-quirks.md +32 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/src/quickstart.md +3 -3
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pyproject.toml +1 -1
- pixie_lab-0.2.0/src/pixie/_partition.py +152 -0
- pixie_lab-0.2.0/src/pixie/_util.py +17 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/catalog/_fetcher.py +231 -68
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/catalog/_routes.py +5 -6
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/catalog/_store.py +10 -9
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/deploy/_main.py +122 -26
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/events/_kinds.py +44 -1
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/events/_log.py +53 -1
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/exports/__init__.py +0 -5
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/exports/_routes.py +3 -2
- pixie_lab-0.2.0/src/pixie/exports/_store.py +347 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/exports/_supervisor.py +143 -7
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/flash.py +4 -6
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/images.py +8 -9
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/machines/_routes.py +10 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/machines/_store.py +52 -9
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/pivot/nbdboot +116 -55
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/pxe/_renderer.py +127 -4
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/pxe/_routes.py +2 -2
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/tui/__init__.py +7 -9
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/tui/_app.py +5 -4
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/tui_catalog.py +16 -22
- pixie_lab-0.2.0/src/pixie/web/__init__.py +9 -0
- pixie_lab-0.2.0/src/pixie/web/_bind_preview.py +84 -0
- pixie_lab-0.2.0/src/pixie/web/_inventory.py +275 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/dashboard.html +74 -3
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/events.html +17 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/ipxe/nbdboot.j2 +10 -1
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/machine_detail.html +227 -43
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/main.py +250 -2
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/conftest.py +11 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_deploy_unit.py +71 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_events_unit.py +33 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_exports_unit.py +57 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_fetch_progress.py +69 -2
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_machines_unit.py +73 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_ui_pages.py +108 -9
- pixie_lab-0.2.0/tests/test_web_bind_preview.py +89 -0
- pixie_lab-0.2.0/tests/test_web_inventory.py +232 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/uv.lock +1 -1
- pixie_lab-0.1.0/src/pixie/_util.py +0 -38
- pixie_lab-0.1.0/src/pixie/exports/_store.py +0 -156
- pixie_lab-0.1.0/src/pixie/web/__init__.py +0 -6
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/.dockerignore +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/.github/workflows/cicd.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/.github/workflows/docs.yml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/.gitignore +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/LICENSE +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/Makefile +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/PLAN.md +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/netboot-pc.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/test-pxe-flash-always.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/test-pxe-flash.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/test-pxe-inventory.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/test-pxe-tui.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/test-pxe.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/configs/usbboot-pc.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/live_build.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/pixie_ipxe_build.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/pixie_wheel_stage.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/pxe_flash_stage.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/pxe_inventory_stage.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/pxe_prepare.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/scripts/usb_iso_build.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/netboot-pc.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/test-pxe-flash-always.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/test-pxe-flash.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/test-pxe-inventory.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/test-pxe-nbdboot.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/test-pxe-tui.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/test-pxe.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/cijoe/tasks/usbboot-pc.yaml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/audit.md +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/src/conf.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/src/index.md +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/tooling/README.md +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/tooling/pyproject.toml +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/tooling/src/pixie_docs/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/docs/tooling/src/pixie_docs/cli.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/README.md +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/auxiliary/cloudinit-metadata.meta +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/auxiliary/ipxe-embed.ipxe +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/auxiliary/ipxe-local-general.h +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/auto/config +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/archives/backports.list.binary +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/archives/backports.list.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/bootloaders/grub-efi/splash.png +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/bootloaders/syslinux/splash.png +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0500-pixie-install.hook.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0500-pixie-skip-bootloader-menu.hook.binary +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0600-pixie-r8125-dkms.hook.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0700-pixie-clock-from-http.hook.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0800-pixie-ssh-live.hook.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0900-pixie-enable-services.hook.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/hooks/normal/0980-pixie-apt-validate.hook.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/issue +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/modprobe.d/zz-pixie-blacklist-nouveau.conf +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/motd +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/profile.d/pixie-version.sh +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/getty@.service.d/zzz-pixie-autologin-root.conf +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-early.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-late.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-mid.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-clock-from-http.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-images-discover.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-on-tty1.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-usb-grow.service +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/var-lib-pixie-images.mount +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/etc/udev/rules.d/70-pixie-realtek-2g5-offloads.rules +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.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.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-boot-banner +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-clock-from-http +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-images-discover +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-on-tty1 +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-trace +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-usb-grow +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/package-lists/pixie-base.list.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/package-lists/pixie-flash.list.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/preferences/backports.pref.binary +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/pixie-media/live-build/config/preferences/backports.pref.chroot +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/catalog/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/catalog/_schema.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/deploy/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/deploy/_templates.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/disks.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/events/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/events/_routes.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/machines/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/oras.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/pivot/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/pxe/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/tftp/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/tftp/_supervisor.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_auth.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_settings_store.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/.gitkeep +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/bootstrap-icons.min.css +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/bootstrap.min.css +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/fonts/bootstrap-icons.woff +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/fonts/bootstrap-icons.woff2 +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/htmx.min.js +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/pixie-favicon.png +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_static/sse.js +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_table_state.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/_partials/page_description.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/_partials/recent_events.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/_partials/table_helpers.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/catalog.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/catalog_detail.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/ipxe/bootstrap.j2 +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/ipxe/exit.j2 +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/ipxe/pixie-live-env.j2 +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/ipxe/unavailable.j2 +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/layout.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/login.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/machines.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/src/pixie/web/_templates/settings.html +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/__init__.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/conftest.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/test_catalog_fetch.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/test_deploy.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/test_exports.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/test_inventory.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/test_pxe.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/integration/test_tftp.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_auth.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_catalog_api.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_event_kinds.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_healthz.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_pivot.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_pxe_plan_json.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_schema.py +0 -0
- {pixie_lab-0.1.0 → pixie_lab-0.2.0}/tests/test_settings.py +0 -0
|
@@ -7,15 +7,84 @@ perceives, defaults that survived a `pip install -U`, and gates that
|
|
|
7
7
|
landed in CI.
|
|
8
8
|
|
|
9
9
|
Per-release commit history lives in `git log`; this file is the
|
|
10
|
-
operator-facing summary.
|
|
11
|
-
next real release has been tagged: the intermediate work all lands
|
|
12
|
-
under `[Unreleased]` until an operator can drive the full flow end-
|
|
13
|
-
to-end on real hardware.
|
|
10
|
+
operator-facing summary.
|
|
14
11
|
|
|
15
12
|
## [Unreleased]
|
|
16
13
|
|
|
14
|
+
## [0.2.0] - 2026-07-22
|
|
15
|
+
|
|
16
|
+
First real release after the 0.1.0 skeleton: nbdboot (ephemeral +
|
|
17
|
+
persistent per-machine overlays) validated end-to-end on real
|
|
18
|
+
hardware, plus a bty-lab-shaped deploy CLI and an operator-managed
|
|
19
|
+
event log.
|
|
20
|
+
|
|
17
21
|
### Added
|
|
18
22
|
|
|
23
|
+
**Event-log Acknowledge + Clear actions.** The `/ui/events` page grows
|
|
24
|
+
two bulk actions: **Acknowledge** advances the ack cursor so the
|
|
25
|
+
dashboard's unacknowledged-error count zeros without touching the log,
|
|
26
|
+
and **Clear** wipes the whole log (behind a confirm) and drops one
|
|
27
|
+
`events.cleared` marker so the reset itself stays on the record.
|
|
28
|
+
Mirrors the ack/clear affordances bty's event log carried.
|
|
29
|
+
|
|
30
|
+
**`pixie-lab purge` reworked to match `bty-lab`.** `purge` now prints
|
|
31
|
+
a plan and gates the destructive parts behind a `y/N` confirmation
|
|
32
|
+
(`-y`/`--yes` to skip; a non-TTY refuses without `--yes`). Flags:
|
|
33
|
+
`--data` deletes the on-disk state (previously `--wipe-data`, which
|
|
34
|
+
never actually removed the bind-mounted `data/`), `--images` removes
|
|
35
|
+
the container image, and `--all` also removes the deploy directory
|
|
36
|
+
(implies `--data`).
|
|
37
|
+
|
|
38
|
+
**Per-machine persistent qcow2 overlays under `nbdboot`.** A new
|
|
39
|
+
`overlay_profile` field on the machine binding flips one target from
|
|
40
|
+
the default ephemeral-tmpfs behaviour to a per-machine writable
|
|
41
|
+
overlay without changing anything else about the bind. A non-blank
|
|
42
|
+
profile maps to a `data/overlays/<mac>/<image_sha>/<profile>.qcow2`
|
|
43
|
+
file with the image's base blob as `backing_file`, served over NBD by
|
|
44
|
+
`qemu-nbd`; the target mounts it read-write and system changes (apt
|
|
45
|
+
installs, kernel modules, hardware-specific config) survive reboots.
|
|
46
|
+
Overlays are keyed by `(mac, image_sha, profile)`, so different
|
|
47
|
+
machines have fully independent files under the same profile name and
|
|
48
|
+
rebinding to a different image leaves the old image's overlays on
|
|
49
|
+
disk for a later resume. A Reset button on the machine detail page
|
|
50
|
+
tears down `qemu-nbd`, unlinks the qcow2, and lets the next boot
|
|
51
|
+
lazy-create a fresh overlay from the base. New `overlays` table on
|
|
52
|
+
state.db (idempotent additive migration), new `overlay.created`,
|
|
53
|
+
`overlay.reset`, `overlay.booted` events. Concurrency is by
|
|
54
|
+
construction (a MAC boots one target at a time), so there is no
|
|
55
|
+
holder tracking or force-reclaim.
|
|
56
|
+
|
|
57
|
+
**Slick Inventory card viz.** The machine detail Inventory card was
|
|
58
|
+
rewritten to consume a normalised view of the stored `lshw -json`
|
|
59
|
+
blob. CPU renders one stat-block per socket with the model as
|
|
60
|
+
headline, an architecture badge, and Bootstrap `display-6` big-type
|
|
61
|
+
numbers for cores over threads plus max clock. Memory shows a total
|
|
62
|
+
headline plus a per-DIMM slot-fill row (filled blocks for populated
|
|
63
|
+
SMBIOS type-17 bank records, outlined blocks for empty slots,
|
|
64
|
+
hover-title tooltip per slot showing size / speed / type), with a
|
|
65
|
+
total-only fallback for firmwares that skimp on bank records. The
|
|
66
|
+
extractor lives in `pixie.web._inventory.normalise_inventory` and
|
|
67
|
+
runs at render time, so a wire-format change or a new lshw quirk
|
|
68
|
+
touches one function. Two new Jinja filters: `humanize_bytes` and
|
|
69
|
+
`humanize_hz`.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
**Truncated `.img.gz` fetches now fail at the download stage.**
|
|
74
|
+
Operators saw "decompress img.gz failed: Compressed file ended before
|
|
75
|
+
the end-of-stream marker was reached" on the catalog page when a
|
|
76
|
+
ghcr download was interrupted mid-transfer. Root cause: the fetch
|
|
77
|
+
pipeline's byte-copy loop treated `resp.read()` returning an empty
|
|
78
|
+
chunk as "done" but urllib does not raise when a peer closes the
|
|
79
|
+
connection early, so a short body was accepted and the gzip trailer
|
|
80
|
+
check surfaced the truncation several minutes downstream of the
|
|
81
|
+
actual failure. `_stream_to_tmpfile` now cross-checks bytes-written
|
|
82
|
+
against `Content-Length` and raises a clear `download truncated for
|
|
83
|
+
<url>: got X of Y bytes` `FetchError` at the point of cause. A
|
|
84
|
+
related cleanup leak (the `finally` block only unlinked `.inflight`
|
|
85
|
+
files for `tar.gz`, so failing `img.gz` fetches left multi-GB
|
|
86
|
+
orphans in `data/tmp/` forever) is fixed as part of the same change.
|
|
87
|
+
|
|
19
88
|
**Settings pane with per-operator display picks.** New top-nav
|
|
20
89
|
pill `/ui/settings` with two knobs: display timezone (IANA zone
|
|
21
90
|
name) and datetime format (strftime pattern). Both resolve override
|
|
@@ -44,6 +44,9 @@ LABEL org.opencontainers.image.title="pixie" \
|
|
|
44
44
|
# /usr/lib/ipxe/, which we copy into pixie's
|
|
45
45
|
# TFTP root so the daemon can serve them.
|
|
46
46
|
# qemu-utils: qemu-img info + qemu-nbd for qcow2 handling.
|
|
47
|
+
# fdisk: sfdisk for pixie._partition partition-offset lookup
|
|
48
|
+
# on persistent-overlay renders. On Ubuntu 26.04
|
|
49
|
+
# sfdisk moved out of util-linux into this package.
|
|
47
50
|
# ca-certificates: HTTPS fetch of ORAS + release assets.
|
|
48
51
|
#
|
|
49
52
|
# Verified against ubuntu:26.04's package list in CI on every build;
|
|
@@ -64,6 +67,7 @@ RUN apt-get update \
|
|
|
64
67
|
tftpd-hpa \
|
|
65
68
|
ipxe \
|
|
66
69
|
qemu-utils \
|
|
70
|
+
fdisk \
|
|
67
71
|
&& rm -rf /var/lib/apt/lists/*
|
|
68
72
|
|
|
69
73
|
# App under /app with editable-style install from the source we copy in.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pixie-lab
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.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
|
|
@@ -81,11 +81,13 @@ top nav has Machines, Catalog, Events, and Settings.
|
|
|
81
81
|
|
|
82
82
|
Everything writable lives under `PIXIE_DATA_DIR` (default
|
|
83
83
|
`/var/lib/pixie`). `state.db` holds catalog rows, machine rows,
|
|
84
|
-
event log, settings,
|
|
85
|
-
holds fetched disk images.
|
|
86
|
-
manifest.json}` holds unpacked
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
event log, settings, NBD-export records, and persistent-overlay
|
|
85
|
+
records. `blobs/<sha>/blob` holds fetched disk images.
|
|
86
|
+
`artifacts/<sha>/{vmlinuz,initrd,manifest.json}` holds unpacked
|
|
87
|
+
netboot bundles. `overlays/<mac>/<image_sha>/<profile>.qcow2` holds
|
|
88
|
+
per-machine writable overlays for the `nbdboot` boot mode.
|
|
89
|
+
`live-env/` holds the pixie live env kernel + initrd + squashfs the
|
|
90
|
+
netboot-pc bake produced.
|
|
89
91
|
|
|
90
92
|
Both admin password and display timezone / strftime pattern have
|
|
91
93
|
env-var overrides plus DB overrides via `/ui/settings`; env wins
|
|
@@ -53,11 +53,13 @@ top nav has Machines, Catalog, Events, and Settings.
|
|
|
53
53
|
|
|
54
54
|
Everything writable lives under `PIXIE_DATA_DIR` (default
|
|
55
55
|
`/var/lib/pixie`). `state.db` holds catalog rows, machine rows,
|
|
56
|
-
event log, settings,
|
|
57
|
-
holds fetched disk images.
|
|
58
|
-
manifest.json}` holds unpacked
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
event log, settings, NBD-export records, and persistent-overlay
|
|
57
|
+
records. `blobs/<sha>/blob` holds fetched disk images.
|
|
58
|
+
`artifacts/<sha>/{vmlinuz,initrd,manifest.json}` holds unpacked
|
|
59
|
+
netboot bundles. `overlays/<mac>/<image_sha>/<profile>.qcow2` holds
|
|
60
|
+
per-machine writable overlays for the `nbdboot` boot mode.
|
|
61
|
+
`live-env/` holds the pixie live env kernel + initrd + squashfs the
|
|
62
|
+
netboot-pc bake produced.
|
|
61
63
|
|
|
62
64
|
Both admin password and display timezone / strftime pattern have
|
|
63
65
|
env-var overrides plus DB overrides via `/ui/settings`; env wins
|
|
@@ -88,3 +88,62 @@ needle = "systemd["
|
|
|
88
88
|
[[test.pxe.chain_markers]]
|
|
89
89
|
key = "debian-userspace"
|
|
90
90
|
needle = "Debian"
|
|
91
|
+
|
|
92
|
+
# ---- Positive userland proof ---------------------------------------
|
|
93
|
+
#
|
|
94
|
+
# Getty printed the login prompt on the serial console: this is what
|
|
95
|
+
# "operator-usable userland" actually looks like from outside the VM.
|
|
96
|
+
# Getty runs as part of getty.target, which is pulled in by
|
|
97
|
+
# multi-user.target, so a login prompt on serial is unambiguous
|
|
98
|
+
# proof that multi-user.target was reached. Chosen over the
|
|
99
|
+
# "Reached target multi-user.target" systemd banner because Debian
|
|
100
|
+
# 13 boots in ``quiet`` mode by default and does not print that
|
|
101
|
+
# banner on the console -- getty's login prompt is always printed.
|
|
102
|
+
# Catches the "boots to systemd but a hanging unit blocks userspace"
|
|
103
|
+
# shape where the earlier markers (systemd-started, debian-userspace)
|
|
104
|
+
# fire but the target never reaches operator-usable userland.
|
|
105
|
+
[[test.pxe.chain_markers]]
|
|
106
|
+
key = "login-prompt"
|
|
107
|
+
needle = "login:"
|
|
108
|
+
|
|
109
|
+
# ---- Forbidden markers ---------------------------------------------
|
|
110
|
+
#
|
|
111
|
+
# Anything below here MUST NOT appear on the client serial log or
|
|
112
|
+
# in pixie's container logs. The check runs alongside the positive-
|
|
113
|
+
# marker poll and fails the whole test the moment any needle hits.
|
|
114
|
+
# Kept scoped to failure signals that would leave a booted-looking
|
|
115
|
+
# target with a broken userland (booted markers OK, but the console
|
|
116
|
+
# spells out the bad news).
|
|
117
|
+
|
|
118
|
+
# systemd-resolved / networkd starvation with no fallback resolv.conf.
|
|
119
|
+
# The mount hook's mask of systemd-networkd + NetworkManager killed
|
|
120
|
+
# both DHCP daemons on the pivoted rootfs; if the initrd's
|
|
121
|
+
# /etc/resolv.conf write did not stick, apt / curl on the target log
|
|
122
|
+
# this literal string on serial. Nosi 2026.W30's mount hook unlinks
|
|
123
|
+
# the /etc/resolv.conf symlink before writing so glibc's resolver
|
|
124
|
+
# reads the file directly -- if a regression puts the symlink back,
|
|
125
|
+
# this marker fires.
|
|
126
|
+
[[test.pxe.forbidden_markers]]
|
|
127
|
+
key = "dns-broken"
|
|
128
|
+
needle = "Temporary failure resolving"
|
|
129
|
+
|
|
130
|
+
# sshd itself failed to start (its unit went into failed state during
|
|
131
|
+
# multi-user.target activation). Distinct from "sshd-started not
|
|
132
|
+
# seen" so the operator gets a clear "start failure" vs "start never
|
|
133
|
+
# attempted" diagnosis in the CI log.
|
|
134
|
+
[[test.pxe.forbidden_markers]]
|
|
135
|
+
key = "sshd-failed"
|
|
136
|
+
needle = "Failed to start ssh.service"
|
|
137
|
+
|
|
138
|
+
# Dracut emergency shell: the mount hook died with _pixie_die and
|
|
139
|
+
# systemd-emergency published the emergency-shell prompt. Every
|
|
140
|
+
# persist-branch regression this session ended here.
|
|
141
|
+
[[test.pxe.forbidden_markers]]
|
|
142
|
+
key = "dracut-emergency"
|
|
143
|
+
needle = "dracut-emergency"
|
|
144
|
+
|
|
145
|
+
# Post-pivot emergency mode (something failed in userspace's own
|
|
146
|
+
# init and systemd fell back to emergency.target).
|
|
147
|
+
[[test.pxe.forbidden_markers]]
|
|
148
|
+
key = "emergency-mode"
|
|
149
|
+
needle = "Emergency mode"
|
|
@@ -243,6 +243,7 @@ def main(args, cijoe) -> int:
|
|
|
243
243
|
client = _start_client_vm(workspace, cfg, client_log, firmware)
|
|
244
244
|
|
|
245
245
|
markers = _build_markers(cfg)
|
|
246
|
+
forbidden = [(e["key"], e["needle"]) for e in cfg.get("forbidden_markers", [])]
|
|
246
247
|
# ``mode=flash`` runs the full real-image pipeline (oras
|
|
247
248
|
# pull + img.gz decompress + dd of ~10 GiB) inside the live
|
|
248
249
|
# env; ``mode=nbdboot`` also pulls the real nosi image but
|
|
@@ -252,7 +253,20 @@ def main(args, cijoe) -> int:
|
|
|
252
253
|
# blob store, similar order of magnitude. Everything else
|
|
253
254
|
# finishes well within the 5 min short-mode budget.
|
|
254
255
|
chain_deadline = CHAIN_TIMEOUT_FLASH if mode in ("flash", "nbdboot") else CHAIN_TIMEOUT
|
|
255
|
-
|
|
256
|
+
try:
|
|
257
|
+
seen = _wait_for_chain_markers(client_log, markers, chain_deadline, forbidden)
|
|
258
|
+
except ForbiddenMarkerSeen as exc:
|
|
259
|
+
log.error(
|
|
260
|
+
f"PXE chain hit forbidden marker {exc.key!r} ({exc.needle!r}); "
|
|
261
|
+
"a known-bad userland signal appeared on the client serial log "
|
|
262
|
+
"or in pixie's container logs. Dumping context."
|
|
263
|
+
)
|
|
264
|
+
qemu_log = client_log.with_suffix(".qemu.log")
|
|
265
|
+
_dump_tail(qemu_log, 60)
|
|
266
|
+
_dump_tail(workspace / "dnsmasq.log", 60)
|
|
267
|
+
_dump_tail(client_log, 200)
|
|
268
|
+
_dump_container_logs()
|
|
269
|
+
return errno.EPROTO
|
|
256
270
|
missing = [k for k, ok in seen.items() if not ok]
|
|
257
271
|
if missing:
|
|
258
272
|
log.error(f"PXE chain incomplete; missing markers: {', '.join(missing)}")
|
|
@@ -620,30 +634,52 @@ def _build_markers(cfg):
|
|
|
620
634
|
return out
|
|
621
635
|
|
|
622
636
|
|
|
623
|
-
def _wait_for_chain_markers(log_path: Path, markers, timeout: int):
|
|
637
|
+
def _wait_for_chain_markers(log_path: Path, markers, timeout: int, forbidden=None):
|
|
638
|
+
"""Poll the client serial log + pixie's container logs for the
|
|
639
|
+
positive markers, checking the same buffers for any ``forbidden``
|
|
640
|
+
substrings each round. A forbidden hit shortcuts the wait with
|
|
641
|
+
``ForbiddenMarkerSeen`` so the caller fails the test loud instead
|
|
642
|
+
of timing out looking for a positive marker that would never
|
|
643
|
+
arrive (the DNS / sshd / emergency-shell regressions come with
|
|
644
|
+
highly recognisable serial output and belong in this list rather
|
|
645
|
+
than in the reactive "check what's missing" branch)."""
|
|
624
646
|
seen = {key: False for key, _ in markers}
|
|
647
|
+
forbidden = forbidden or []
|
|
625
648
|
deadline = time.monotonic() + timeout
|
|
626
649
|
while time.monotonic() < deadline and not all(seen.values()):
|
|
627
|
-
|
|
650
|
+
body = ""
|
|
628
651
|
if log_path.exists():
|
|
629
652
|
body = log_path.read_text(encoding="utf-8", errors="replace")
|
|
630
653
|
for key, needle in markers:
|
|
631
654
|
if not seen[key] and needle in body:
|
|
632
655
|
log.info(f" + {key}: matched {needle!r}")
|
|
633
656
|
seen[key] = True
|
|
634
|
-
# Also mirror-check container logs so a server-side hit counts
|
|
635
|
-
# even when the client's console doesn't spell the fetch out.
|
|
636
657
|
cont = _container_log_snapshot()
|
|
637
658
|
for key, needle in markers:
|
|
638
659
|
if not seen[key] and needle in cont:
|
|
639
660
|
log.info(f" + {key}: matched {needle!r} in container logs")
|
|
640
661
|
seen[key] = True
|
|
662
|
+
for key, needle in forbidden:
|
|
663
|
+
if needle in body or needle in cont:
|
|
664
|
+
raise ForbiddenMarkerSeen(key, needle)
|
|
641
665
|
if all(seen.values()):
|
|
642
666
|
break
|
|
643
667
|
time.sleep(2)
|
|
644
668
|
return seen
|
|
645
669
|
|
|
646
670
|
|
|
671
|
+
class ForbiddenMarkerSeen(RuntimeError):
|
|
672
|
+
"""A ``[[test.pxe.forbidden_markers]]`` entry was observed on the
|
|
673
|
+
client serial log or in pixie's container logs. Raised by the
|
|
674
|
+
marker-polling loop so the caller can log the exact key + needle
|
|
675
|
+
that fired and fail with a distinct error code."""
|
|
676
|
+
|
|
677
|
+
def __init__(self, key: str, needle: str) -> None:
|
|
678
|
+
super().__init__(f"forbidden marker {key!r} matched {needle!r}")
|
|
679
|
+
self.key = key
|
|
680
|
+
self.needle = needle
|
|
681
|
+
|
|
682
|
+
|
|
647
683
|
def _container_log_snapshot() -> str:
|
|
648
684
|
res = subprocess.run(
|
|
649
685
|
["podman", "logs", "--tail", "500", CONTAINER_NAME],
|
|
@@ -49,11 +49,50 @@ known-clean image each cycle.
|
|
|
49
49
|
### `nbdboot`
|
|
50
50
|
|
|
51
51
|
The target boots the image's OWN kernel (extracted from the sibling
|
|
52
|
-
netboot bundle) and mounts the image over NBD.
|
|
52
|
+
netboot bundle) and mounts the image over NBD. By default, root is an
|
|
53
53
|
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 single target from ephemeral to dev
|
|
58
|
+
mode without changing anything else about the bind. On the machine
|
|
59
|
+
detail page, the `Overlay profile` field is blank by default
|
|
60
|
+
(ephemeral, unchanged behaviour) or names a per-machine profile
|
|
61
|
+
(e.g. `simon`, `karl`, `ci-with-nvme-tools`). A non-blank profile
|
|
62
|
+
maps to a per-machine qcow2 file with the image's base blob as
|
|
63
|
+
`backing_file`, served by `qemu-nbd` at a dedicated port. The target
|
|
64
|
+
mounts the NBD device read-write; system-level changes (apt-installed
|
|
65
|
+
packages, hardware-specific config, kernel modules) land on the qcow2
|
|
66
|
+
and survive reboots.
|
|
67
|
+
|
|
68
|
+
Overlays are keyed by `(mac, image_content_sha256, profile)`:
|
|
69
|
+
different machines have fully independent files even under the same
|
|
70
|
+
profile name, and rebinding a machine to a different image leaves the
|
|
71
|
+
old image's overlays on disk (a rebind back resumes them). Storage is
|
|
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.
|
|
80
|
+
|
|
81
|
+
**Kexec into a locally-installed kernel.** The netboot bundle owns
|
|
82
|
+
the kernel and initrd pixie serves. Installing `linux-image-*` on the
|
|
83
|
+
target's persistent overlay writes files to `/boot` but the next
|
|
84
|
+
power-cycle refetches pixie's kernel and those files sit unused.
|
|
85
|
+
`kexec` bridges that gap: the netboot kernel comes up, then the
|
|
86
|
+
operator runs
|
|
87
|
+
`kexec -l /boot/vmlinuz-<v> --initrd=/boot/initrd.img-<v>
|
|
88
|
+
--reuse-cmdline && systemctl kexec` to switch to the local kernel
|
|
89
|
+
without going through firmware. Every netboot-shipping nosi variant
|
|
90
|
+
now bakes `kexec-tools` in; see nosi's [Custom kernel under netboot
|
|
91
|
+
(kexec)](https://safl.github.io/nosi/kexec.html) for the full
|
|
92
|
+
workflow. Recovery from a bad kernel is a power-cycle back to
|
|
93
|
+
pixie's kernel; nothing kexec's automatically, so a broken install
|
|
94
|
+
never becomes a boot loop.
|
|
95
|
+
|
|
57
96
|
## Prerequisites at a glance
|
|
58
97
|
|
|
59
98
|
| Mode | Needs image | Needs inventory | Needs target disk |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Deployment
|
|
2
2
|
|
|
3
|
-
Pixie ships as a single podman-compose service. The `pixie-
|
|
3
|
+
Pixie ships as a single podman-compose service. The `pixie-lab`
|
|
4
4
|
CLI writes the compose file + envvars into a directory of the
|
|
5
5
|
operator's choosing.
|
|
6
6
|
|
|
@@ -17,10 +17,82 @@ The recommended layout on the deploy host:
|
|
|
17
17
|
live-env/ <- staged pixie live env (vmlinuz + initrd + squashfs)
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
`compose.yml` is generated by `pixie-
|
|
20
|
+
`compose.yml` is generated by `pixie-lab init` and shouldn't need
|
|
21
21
|
hand-edits for a standard deploy. `envvars` carries the site-specific
|
|
22
22
|
values.
|
|
23
23
|
|
|
24
|
+
## Lifecycle
|
|
25
|
+
|
|
26
|
+
The `pixie-lab` CLI drives a deploy directory. Install it with
|
|
27
|
+
`uv tool install pixie-lab` (or `pipx install pixie-lab`); each
|
|
28
|
+
subcommand takes an optional path, defaulting to the current
|
|
29
|
+
directory.
|
|
30
|
+
|
|
31
|
+
### First deploy
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
pixie-lab deploy /opt/pixie
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`deploy` writes `compose.yml` + `envvars` (auto-filling a random admin
|
|
38
|
+
password and the detected host address), brings the stack up with
|
|
39
|
+
`podman compose`, and waits for `/healthz`. It refuses to overwrite an
|
|
40
|
+
existing `compose.yml` / `envvars`, so it is a fresh-directory command;
|
|
41
|
+
pass `--admin-password` / `--host-addr` to pin those values, or edit
|
|
42
|
+
`envvars` and re-run `podman compose --env-file envvars up -d`.
|
|
43
|
+
|
|
44
|
+
### Restart vs. teardown
|
|
45
|
+
|
|
46
|
+
A restart is safe for running targets: pixie respawns every nbdkit +
|
|
47
|
+
qemu-nbd export from `state.db` on startup, and the nbdboot initrd
|
|
48
|
+
connects with `nbd-client -persist`, so a target whose root is on
|
|
49
|
+
pixie's NBD reconnects across a quick bounce.
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
podman restart pixie
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Taking the container fully down drops those exports. Any target
|
|
56
|
+
currently booted `nbdboot` off pixie loses its backing device and
|
|
57
|
+
hangs - power such targets off before a teardown, or reboot them after.
|
|
58
|
+
|
|
59
|
+
### Purge and start from scratch
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
pixie-lab purge /opt/pixie --data
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`purge` stops and removes the container. It prints what it will do and
|
|
66
|
+
asks for a `y/N` confirmation first; pass `-y` / `--yes` for scripted
|
|
67
|
+
runs (on a non-TTY it refuses without `--yes` rather than fire
|
|
68
|
+
unattended). Flags choose how far the wipe goes:
|
|
69
|
+
|
|
70
|
+
- `--data` - also delete `data/`: `state.db` (catalog, machines,
|
|
71
|
+
events, exports, overlays, settings), every fetched blob and unpacked
|
|
72
|
+
artifact, all per-machine overlays, and the staged `live-env/`.
|
|
73
|
+
`data/` is a bind mount (`./data:/var/lib/pixie`), not a named
|
|
74
|
+
volume, so purge unlinks it directly - `podman compose down -v`
|
|
75
|
+
alone would not touch it.
|
|
76
|
+
- `--images` - also remove the pixie container image.
|
|
77
|
+
- `--all` - also delete the deploy directory (`compose.yml`,
|
|
78
|
+
`envvars`); implies `--data`.
|
|
79
|
+
|
|
80
|
+
With no flag, purge only stops the container and leaves state in place.
|
|
81
|
+
Bring a config-preserved deploy back up with `podman compose --env-file
|
|
82
|
+
envvars up -d`. For a from-nothing redeploy - regenerated compose +
|
|
83
|
+
envvars + a fresh admin password - purge with `--all`, then
|
|
84
|
+
`pixie-lab deploy /opt/pixie` on the now-empty directory.
|
|
85
|
+
|
|
86
|
+
### Upgrade the image
|
|
87
|
+
|
|
88
|
+
The service runs the `pixie:local` image. Rebuild and recreate; state
|
|
89
|
+
in `data/` survives untouched:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
podman build -t pixie:local -f Containerfile .
|
|
93
|
+
cd /opt/pixie && podman compose --env-file envvars up -d
|
|
94
|
+
```
|
|
95
|
+
|
|
24
96
|
## Environment variables
|
|
25
97
|
|
|
26
98
|
Pixie reads these at container startup. The compose file passes the
|
|
@@ -51,7 +123,9 @@ workarounds; see [](hardware-quirks.md).
|
|
|
51
123
|
|
|
52
124
|
**`PIXIE_DATA_DIR`** (default: `/var/lib/pixie`) - state root. Holds
|
|
53
125
|
`state.db`, `blobs/` (fetched image bytes), `artifacts/` (extracted
|
|
54
|
-
netboot bundles), `
|
|
126
|
+
netboot bundles), `overlays/<mac>/<image_sha>/<profile>.qcow2`
|
|
127
|
+
(per-machine writable overlays for nbdboot; see [](boot-modes.md)),
|
|
128
|
+
`live-env/` (staged pixie live env).
|
|
55
129
|
|
|
56
130
|
**`PIXIE_LIVE_ENV_DIR`** (default: `$PIXIE_DATA_DIR/live-env`) - the
|
|
57
131
|
`pixie-*` boot modes degrade to an unavailable plan when this dir is
|
|
@@ -69,6 +69,38 @@ workaround kicks in the kernel logs:
|
|
|
69
69
|
|
|
70
70
|
...and the live-boot initrd fetches the squashfs normally.
|
|
71
71
|
|
|
72
|
+
## Target firmware prerequisites (not cmdline)
|
|
73
|
+
|
|
74
|
+
Two quirks are about the target's firmware / BMC rather than a kernel
|
|
75
|
+
token, but they produce the same "nbdboot doesn't work" report.
|
|
76
|
+
|
|
77
|
+
### UEFI network boot must be enabled in BIOS
|
|
78
|
+
|
|
79
|
+
nbdboot only happens if the target's UEFI actually PXE-boots. If the
|
|
80
|
+
board's network stack / PXE option-ROM is disabled in BIOS setup, or
|
|
81
|
+
the network device isn't in the boot order, the machine silently boots
|
|
82
|
+
its local disk instead - and, because that local install answers SSH,
|
|
83
|
+
it's easy to mistake for a working nbdboot. Some BMCs make this worse:
|
|
84
|
+
a one-shot **or** persistent "boot from PXE" override set over IPMI /
|
|
85
|
+
Redfish is accepted by the BMC (`bootparam get 5` shows `Force PXE`)
|
|
86
|
+
yet **ignored by the BIOS**, and the target never even appears in
|
|
87
|
+
pixie's access log. Seen on a Supermicro board whose BIOS network boot
|
|
88
|
+
had been turned off. Fix in BIOS setup directly: enable the UEFI
|
|
89
|
+
network stack + PXE, and put the NIC ahead of the local disk in the
|
|
90
|
+
boot order. Confirm success from pixie's side (a `GET /pxe/<mac>` in
|
|
91
|
+
the log, then `online.started … ramboot.up` status events), not from
|
|
92
|
+
SSH being open.
|
|
93
|
+
|
|
94
|
+
### Don't trust IPMI SOL to prove a boot
|
|
95
|
+
|
|
96
|
+
Some BMCs (e.g. the GIGABYTE MC12-LE0's Aspeed) do **not** mirror the
|
|
97
|
+
host serial console to IPMI SOL, so SOL stays blank even though the
|
|
98
|
+
target booted fine and `serial-getty@ttyS1` is running. Absence of a
|
|
99
|
+
login prompt on SOL is not proof of a failed boot on those boards.
|
|
100
|
+
Judge nbdboot by ground truth instead: root is `/dev/nbd0` (not the
|
|
101
|
+
SATA/NVMe disk), a live NBD socket to pixie's export port, and the
|
|
102
|
+
image's hostname rather than the local install's.
|
|
103
|
+
|
|
72
104
|
## Adding a row
|
|
73
105
|
|
|
74
106
|
If you hit new hardware, keep the row short. Reader wants:
|
|
@@ -12,7 +12,7 @@ pipx install pixie-lab
|
|
|
12
12
|
`pipx` is preferred so pixie's runtime deps stay isolated from the
|
|
13
13
|
system Python. `uv tool install pixie-lab` works too.
|
|
14
14
|
|
|
15
|
-
The `pixie-lab` distribution ships two console-scripts: `pixie-
|
|
15
|
+
The `pixie-lab` distribution ships two console-scripts: `pixie-lab`
|
|
16
16
|
generates the container deployment bundle, and `pixie` is the
|
|
17
17
|
operator TUI baked into the pixie live env (targets run it after
|
|
18
18
|
booting the live env; operators don't call it directly on their
|
|
@@ -22,11 +22,11 @@ workstation).
|
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
mkdir /opt/pixie && cd /opt/pixie
|
|
25
|
-
pixie-
|
|
25
|
+
pixie-lab init
|
|
26
26
|
${EDITOR:-vi} envvars # set PIXIE_HOST_ADDR + PIXIE_ADMIN_PASSWORD
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`pixie-
|
|
29
|
+
`pixie-lab init` writes `compose.yml`, `envvars` (with placeholder
|
|
30
30
|
values), and `envvars.example` into the current directory. Edit
|
|
31
31
|
`envvars` to point pixie at your LAN address and set a real admin
|
|
32
32
|
password.
|