pixie-lab 0.4.1__tar.gz → 0.4.2__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.
Files changed (210) hide show
  1. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/.github/workflows/cicd.yaml +78 -2
  2. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/CHANGELOG.md +27 -0
  3. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/Makefile +12 -1
  4. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/PKG-INFO +1 -1
  5. pixie_lab-0.4.2/cijoe/configs/live-env-image.toml +34 -0
  6. pixie_lab-0.4.2/cijoe/scripts/live_env_image.py +307 -0
  7. pixie_lab-0.4.2/cijoe/scripts/live_env_transform.sh +293 -0
  8. pixie_lab-0.4.2/cijoe/tasks/live-env-image.yaml +35 -0
  9. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pyproject.toml +1 -1
  10. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/_partition.py +93 -9
  11. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/_fetcher.py +15 -4
  12. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/catalog.toml +24 -0
  13. pixie_lab-0.4.2/src/pixie/oras_pull.py +85 -0
  14. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/pxe/_renderer.py +127 -59
  15. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/pxe/_routes.py +14 -1
  16. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_settings_store.py +40 -0
  17. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/live_env.html +36 -0
  18. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/main.py +59 -0
  19. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_catalog_seed.py +5 -3
  20. pixie_lab-0.4.2/tests/test_oras_pull.py +89 -0
  21. pixie_lab-0.4.2/tests/test_partition_select.py +107 -0
  22. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_pxe_plan_json.py +126 -0
  23. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_settings.py +55 -0
  24. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/uv.lock +1 -1
  25. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/.dockerignore +0 -0
  26. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/.github/workflows/docs.yml +0 -0
  27. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/.gitignore +0 -0
  28. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/Containerfile +0 -0
  29. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/LICENSE +0 -0
  30. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/PLAN.md +0 -0
  31. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/README.md +0 -0
  32. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/netboot-pc.toml +0 -0
  33. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-pxe-flash-always.toml +0 -0
  34. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-pxe-flash.toml +0 -0
  35. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-pxe-inventory.toml +0 -0
  36. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-pxe-nbdboot.toml +0 -0
  37. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-pxe-tui.toml +0 -0
  38. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-pxe.toml +0 -0
  39. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/test-usb-ventoy.toml +0 -0
  40. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/configs/usbboot-pc.toml +0 -0
  41. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/live_build.py +0 -0
  42. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/pixie_ipxe_build.py +0 -0
  43. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/pixie_wheel_stage.py +0 -0
  44. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/pxe_flash_stage.py +0 -0
  45. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/pxe_inventory_stage.py +0 -0
  46. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/pxe_prepare.py +0 -0
  47. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/pxe_run_chain_test.py +0 -0
  48. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/usb_iso_build.py +0 -0
  49. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/usb_iso_verify.py +0 -0
  50. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/usb_ventoy_guest_start.py +0 -0
  51. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/scripts/usb_ventoy_stage.py +0 -0
  52. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/netboot-pc.yaml +0 -0
  53. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-pxe-flash-always.yaml +0 -0
  54. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-pxe-flash.yaml +0 -0
  55. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-pxe-inventory.yaml +0 -0
  56. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-pxe-nbdboot.yaml +0 -0
  57. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-pxe-tui.yaml +0 -0
  58. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-pxe.yaml +0 -0
  59. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/test-usb-ventoy.yaml +0 -0
  60. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/cijoe/tasks/usbboot-pc.yaml +0 -0
  61. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/audit.md +0 -0
  62. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/src/boot-modes.md +0 -0
  63. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/src/conf.py +0 -0
  64. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/src/deployment.md +0 -0
  65. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/src/hardware-quirks.md +0 -0
  66. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/src/index.md +0 -0
  67. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/src/quickstart.md +0 -0
  68. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/tooling/README.md +0 -0
  69. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/tooling/pyproject.toml +0 -0
  70. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/tooling/src/pixie_docs/__init__.py +0 -0
  71. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/docs/tooling/src/pixie_docs/cli.py +0 -0
  72. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/README.md +0 -0
  73. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/auxiliary/cloudinit-metadata.meta +0 -0
  74. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/auxiliary/ipxe-embed.ipxe +0 -0
  75. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/auxiliary/ipxe-local-general.h +0 -0
  76. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/auto/config +0 -0
  77. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/archives/backports.list.binary +0 -0
  78. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/archives/backports.list.chroot +0 -0
  79. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/bootloaders/grub-efi/splash.png +0 -0
  80. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/bootloaders/syslinux/splash.png +0 -0
  81. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0500-pixie-install.hook.chroot +0 -0
  82. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0500-pixie-skip-bootloader-menu.hook.binary +0 -0
  83. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0600-pixie-r8125-dkms.hook.chroot +0 -0
  84. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0700-pixie-clock-from-http.hook.chroot +0 -0
  85. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0800-pixie-ssh-live.hook.chroot +0 -0
  86. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0900-pixie-enable-services.hook.chroot +0 -0
  87. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/hooks/normal/0980-pixie-apt-validate.hook.chroot +0 -0
  88. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/initramfs-tools/conf.d/pixie-modules-most +0 -0
  89. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/issue +0 -0
  90. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/modprobe.d/zz-pixie-blacklist-nouveau.conf +0 -0
  91. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/motd +0 -0
  92. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/profile.d/pixie-version.sh +0 -0
  93. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/getty@.service.d/zzz-pixie-autologin-root.conf +0 -0
  94. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-early.service +0 -0
  95. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-late.service +0 -0
  96. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-banner-mid.service +0 -0
  97. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-clock-from-http.service +0 -0
  98. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-images-discover.service +0 -0
  99. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-on-tty1.service +0 -0
  100. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/pixie-usb-grow.service +0 -0
  101. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/systemd/system/var-lib-pixie-images.mount +0 -0
  102. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/etc/udev/rules.d/70-pixie-realtek-2g5-offloads.rules +0 -0
  103. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/lib/systemd/system-generators/pixie-skip-usb-only-units-on-netboot +0 -0
  104. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-boot-banner +0 -0
  105. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-clock-from-http +0 -0
  106. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-images-discover +0 -0
  107. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-on-tty1 +0 -0
  108. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-trace +0 -0
  109. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/includes.chroot/usr/local/sbin/pixie-usb-grow +0 -0
  110. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/package-lists/pixie-base.list.chroot +0 -0
  111. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/package-lists/pixie-flash.list.chroot +0 -0
  112. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/preferences/backports.pref.binary +0 -0
  113. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/pixie-media/live-build/config/preferences/backports.pref.chroot +0 -0
  114. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/__init__.py +0 -0
  115. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/_util.py +0 -0
  116. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/__init__.py +0 -0
  117. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/_live_env.py +0 -0
  118. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/_routes.py +0 -0
  119. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/_schema.py +0 -0
  120. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/catalog/_store.py +0 -0
  121. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/deploy/__init__.py +0 -0
  122. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/deploy/_main.py +0 -0
  123. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/deploy/_templates.py +0 -0
  124. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/disks.py +0 -0
  125. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/events/__init__.py +0 -0
  126. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/events/_kinds.py +0 -0
  127. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/events/_log.py +0 -0
  128. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/events/_routes.py +0 -0
  129. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/exports/__init__.py +0 -0
  130. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/exports/_routes.py +0 -0
  131. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/exports/_store.py +0 -0
  132. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/exports/_supervisor.py +0 -0
  133. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/flash.py +0 -0
  134. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/images.py +0 -0
  135. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/machines/__init__.py +0 -0
  136. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/machines/_routes.py +0 -0
  137. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/machines/_store.py +0 -0
  138. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/oras.py +0 -0
  139. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/pivot/__init__.py +0 -0
  140. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/pivot/nbdboot +0 -0
  141. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/pxe/__init__.py +0 -0
  142. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/tftp/__init__.py +0 -0
  143. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/tftp/_supervisor.py +0 -0
  144. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/tui/__init__.py +0 -0
  145. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/tui/_app.py +0 -0
  146. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/tui_catalog.py +0 -0
  147. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/__init__.py +0 -0
  148. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_auth.py +0 -0
  149. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_bind_preview.py +0 -0
  150. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_fsutil.py +0 -0
  151. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_images.py +0 -0
  152. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_inventory.py +0 -0
  153. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_overlay_bind.py +0 -0
  154. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_overlays.py +0 -0
  155. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/.gitkeep +0 -0
  156. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/bootstrap-icons.min.css +0 -0
  157. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/bootstrap.min.css +0 -0
  158. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/fonts/bootstrap-icons.woff +0 -0
  159. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/fonts/bootstrap-icons.woff2 +0 -0
  160. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/htmx.min.js +0 -0
  161. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/pixie-favicon.png +0 -0
  162. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_static/sse.js +0 -0
  163. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_table_state.py +0 -0
  164. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/_partials/page_description.html +0 -0
  165. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/_partials/recent_events.html +0 -0
  166. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/_partials/table_helpers.html +0 -0
  167. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/catalog.html +0 -0
  168. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/catalog_detail.html +0 -0
  169. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/dashboard.html +0 -0
  170. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/events.html +0 -0
  171. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/image_detail.html +0 -0
  172. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/images.html +0 -0
  173. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/ipxe/bootstrap.j2 +0 -0
  174. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/ipxe/exit.j2 +0 -0
  175. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/ipxe/nbdboot.j2 +0 -0
  176. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/ipxe/pixie-live-env.j2 +0 -0
  177. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/ipxe/unavailable.j2 +0 -0
  178. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/layout.html +0 -0
  179. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/login.html +0 -0
  180. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/machine_detail.html +0 -0
  181. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/machines.html +0 -0
  182. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/overlays.html +0 -0
  183. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/src/pixie/web/_templates/settings.html +0 -0
  184. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/__init__.py +0 -0
  185. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/conftest.py +0 -0
  186. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/__init__.py +0 -0
  187. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/conftest.py +0 -0
  188. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/test_catalog_fetch.py +0 -0
  189. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/test_deploy.py +0 -0
  190. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/test_exports.py +0 -0
  191. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/test_inventory.py +0 -0
  192. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/test_pxe.py +0 -0
  193. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/integration/test_tftp.py +0 -0
  194. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_auth.py +0 -0
  195. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_catalog_api.py +0 -0
  196. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_deploy_unit.py +0 -0
  197. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_event_kinds.py +0 -0
  198. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_events_unit.py +0 -0
  199. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_exports_unit.py +0 -0
  200. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_fetch_progress.py +0 -0
  201. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_healthz.py +0 -0
  202. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_images_ui.py +0 -0
  203. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_live_env_fetch.py +0 -0
  204. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_machines_unit.py +0 -0
  205. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_overlays_ui.py +0 -0
  206. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_pivot.py +0 -0
  207. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_schema.py +0 -0
  208. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_ui_pages.py +0 -0
  209. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_web_bind_preview.py +0 -0
  210. {pixie_lab-0.4.1 → pixie_lab-0.4.2}/tests/test_web_inventory.py +0 -0
@@ -191,6 +191,67 @@ jobs:
191
191
  ~/system_imaging/disk/pixie-usbboot-pc-x86_64-v*.iso
192
192
  ~/system_imaging/disk/pixie-usbboot-pc-x86_64-v*.sha256
193
193
 
194
+ build-live-env-image:
195
+ name: Build pixie-live-env image
196
+ # The image the live-env boot modes nbdboot: the nosi arch-headless
197
+ # base disk image with the pixie CLI + pixie-on-tty1 service injected
198
+ # (cijoe/tasks/live-env-image.yaml). Unlike the live-build bakes this
199
+ # does NOT run debootstrap/mksquashfs; it qemu-nbd-mounts a copy of a
200
+ # pulled base image, injects userspace, slims, and gzips. Wired to
201
+ # ``test`` so we don't pay for the ORAS pull + qemu transform on a
202
+ # broken lint/typecheck.
203
+ needs: test
204
+ runs-on: ubuntu-latest
205
+ # 60 min cap for the same reason as build-media: the real ORAS pull
206
+ # of the arch-headless base (~1.6 GiB) + decompress + qemu transform
207
+ # + gzip dominate wall clock.
208
+ timeout-minutes: 60
209
+ steps:
210
+ - uses: actions/checkout@v6
211
+
212
+ - name: Install build dependencies (qemu-nbd, rsync, nbd module)
213
+ run: |
214
+ set -eu
215
+ sudo apt-get update
216
+ sudo apt-get install -y --no-install-recommends \
217
+ qemu-utils rsync gzip
218
+ # The transform attaches a copy of the base image to /dev/nbdX
219
+ # via qemu-nbd; load the module with partition scanning so the
220
+ # root partition shows up as nbdXp1.
221
+ sudo modprobe nbd max_part=16
222
+ ls -la /dev/nbd0
223
+
224
+ - name: Install cijoe
225
+ run: pipx install --force cijoe
226
+
227
+ - name: Install uv
228
+ uses: astral-sh/setup-uv@v8.1.0
229
+
230
+ - name: Build pixie-live-env image
231
+ run: make live-env-image
232
+
233
+ # cijoe captures the full run (per-command output + report.html)
234
+ # under cijoe/cijoe-output/. Upload it ALWAYS so a transform
235
+ # failure leaves a diagnosable artifact.
236
+ - name: Upload cijoe output
237
+ if: always()
238
+ uses: actions/upload-artifact@v7
239
+ with:
240
+ name: cijoe-output-live-env-image
241
+ path: cijoe/cijoe-output
242
+ if-no-files-found: warn
243
+
244
+ - name: Upload artifact (pixie-live-env-image)
245
+ uses: actions/upload-artifact@v7
246
+ with:
247
+ name: pixie-live-env-image-x86_64
248
+ path: |
249
+ ~/system_imaging/disk/pixie-live-env-x86_64.img.gz
250
+ ~/system_imaging/disk/pixie-live-env-x86_64.img.gz.sha256
251
+ ~/system_imaging/disk/pixie-live-env-x86_64.content-sha256
252
+ ~/system_imaging/disk/pixie-live-env-catalog.toml
253
+ if-no-files-found: error
254
+
194
255
  test-pxe:
195
256
  name: PXE bootstrap chain test (containerized pixie + client QEMU VM)
196
257
  # Independent of the media bake: the chain test only needs the
@@ -650,6 +711,7 @@ jobs:
650
711
  - build-container
651
712
  - build-wheel
652
713
  - build-media
714
+ - build-live-env-image
653
715
  - test-pxe
654
716
  - test-pxe-nbdboot
655
717
  - test-pxe-inventory
@@ -692,6 +754,7 @@ jobs:
692
754
  - build-container
693
755
  - build-wheel
694
756
  - build-media
757
+ - build-live-env-image
695
758
  - test-pxe
696
759
  - test-pxe-nbdboot
697
760
  - test-pxe-inventory
@@ -737,6 +800,7 @@ jobs:
737
800
  - build-container
738
801
  - build-wheel
739
802
  - build-media
803
+ - build-live-env-image
740
804
  - test-pxe
741
805
  - test-pxe-nbdboot
742
806
  - test-pxe-inventory
@@ -759,6 +823,15 @@ jobs:
759
823
  pattern: pixie-*-pc-x86_64
760
824
  merge-multiple: true
761
825
  path: release-assets
826
+ - name: Download pixie-live-env image
827
+ # The nbdboot live-env image (arch-headless + injected pixie CLI
828
+ # / service): the gzipped disk image + its .sha256, the
829
+ # .content-sha256 sidecar (the value an operator sets
830
+ # PIXIE_LIVE_ENV_IMAGE_SHA to), and the catalog fragment.
831
+ uses: actions/download-artifact@v8
832
+ with:
833
+ name: pixie-live-env-image-x86_64
834
+ path: release-assets
762
835
  - name: List release assets
763
836
  run: ls -la release-assets
764
837
  - name: Assemble live-env fetch tarball
@@ -798,7 +871,10 @@ jobs:
798
871
 
799
872
  ## Media assets attached here
800
873
 
801
- - `pixie-live-env-x86_64.tar.gz` — the live-env trio packaged for pixie's in-app **Fetch live-env** action (the default `PIXIE_LIVE_ENV_SRC`). Click Fetch live-env on the dashboard and pixie pulls + stages this itself; no manual bake or copy.
802
- - `pixie-netboot-pc-x86_64-*.{vmlinuz,initrd,squashfs}` — the same live-env (netboot-pc bake) as loose files, if you prefer to stage `PIXIE_LIVE_ENV_DIR` (`data/live-env/`) by hand. Used by the `pixie-flash-once` / `pixie-flash-always` / `pixie-inventory` / `pixie-tui` boot modes.
874
+ - `pixie-live-env-x86_64.img.gz` — the **nbdboot** live-env image: the nosi `arch-headless` base disk image with the pixie CLI + `pixie-on-tty1` service injected. Fetch it from the **Catalog** tab (it seeds into a fresh catalog), then set `PIXIE_LIVE_ENV_IMAGE_SHA` to select it for the `pixie-flash-once` / `pixie-flash-always` / `pixie-inventory` / `pixie-tui` boot modes so they nbdboot this image ephemerally.
875
+ - `pixie-live-env-x86_64.content-sha256` — the raw-image sha256 to set `PIXIE_LIVE_ENV_IMAGE_SHA` to (identical to the `content_sha256` pixie assigns after fetching the `pixie-live-env` catalog entry).
876
+ - `pixie-live-env-catalog.toml` — the catalog fragment (the `pixie-live-env` disk image + its arch-headless netboot bundle) with `content_sha256` filled in; the shipped `catalog.toml` also lists these entries.
877
+ - `pixie-live-env-x86_64.tar.gz` — the older squashfs live-env trio for pixie's in-app **Fetch live-env** action (the default `PIXIE_LIVE_ENV_SRC`) and the `PIXIE_LIVE_ENV_DIR` staging path.
878
+ - `pixie-netboot-pc-x86_64-*.{vmlinuz,initrd,squashfs}` — the squashfs live-env (netboot-pc bake) as loose files, if you prefer to stage `PIXIE_LIVE_ENV_DIR` (`data/live-env/`) by hand.
803
879
  - `pixie-usbboot-pc-x86_64-*.iso` — bootable USB / ISO media for the pixie live env (uncompressed; `dd` / Etcher / Ventoy ready).
804
880
  - `*.sha256` — checksums for the above.
@@ -11,6 +11,33 @@ operator-facing summary.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [0.4.2] - 2026-07-26
15
+
16
+ ### Added
17
+
18
+ **The live-env boots as an ephemeral-nbdboot disk image, not a
19
+ live-boot squashfs.** The inventory / tui / flash boot modes now
20
+ nbdboot a normal disk image (nosi `arch-headless` with the pixie CLI +
21
+ `pixie-on-tty1` service injected) with a tmpfs overlay, instead of
22
+ fetching a live-boot squashfs. This fixes boxes whose NIC never came up
23
+ under the old Debian live-boot initramfs (dual-NIC Intel `igb` among
24
+ them): the image rides the same dracut ramboot path that nbdboot
25
+ already uses, which brings those NICs up. Point pixie at it by fetching
26
+ the `pixie-live-env` catalog entry and setting `PIXIE_LIVE_ENV_IMAGE_SHA`
27
+ (or the `live_env.image_sha` setting) to its content sha; the image ships
28
+ as a release asset (`pixie-live-env-x86_64.img.gz`, under 2 GB) built and
29
+ published by CI.
30
+
31
+ ### Fixed
32
+
33
+ **Rootfs extraction picks the Linux root partition by GPT type.** The
34
+ fetcher extracted partition 1 as `rootfs.raw`, correct for the
35
+ ubuntu/debian cloud images (root at p1) but not for arch/fedora, whose
36
+ images place BIOS-boot + ESP first and root at p3 -- there it produced a
37
+ 1 MiB stub that could not mount. It now selects by type (Linux-root GUID,
38
+ then the largest Linux filesystem, then the largest non-firmware/boot/swap
39
+ partition), so every nosi image extracts its real root.
40
+
14
41
  ## [0.4.1] - 2026-07-25
15
42
 
16
43
  ### Changed
@@ -23,7 +23,7 @@ endif
23
23
 
24
24
  .PHONY: help \
25
25
  deps test lint format format-check typecheck ci wheel \
26
- media-deps build ipxe test-pxe test-usb-ventoy \
26
+ media-deps build live-env-image ipxe test-pxe test-usb-ventoy \
27
27
  clean
28
28
 
29
29
  help:
@@ -43,6 +43,8 @@ help:
43
43
  @echo " media-deps pipx install cijoe"
44
44
  @echo " build build a media image (override VARIANT below)"
45
45
  @echo " -> ~/system_imaging/disk/pixie-<variant>.*"
46
+ @echo " live-env-image build the pixie-live-env disk image (arch-headless"
47
+ @echo " base + pixie CLI/service) nbdbooted by the live-env modes"
46
48
  @echo " ipxe build pixie's custom iPXE -> IPXE_OUT/ipxe.efi (default dist/ipxe/)"
47
49
  @echo " test-pxe end-to-end PXE bootstrap chain test"
48
50
  @echo " (needs podman + QEMU + KVM + dnsmasq; a few min wall clock)"
@@ -107,6 +109,15 @@ media-deps:
107
109
  build:
108
110
  cd cijoe && cijoe $(MEDIA_TASK) --monitor -c configs/$(VARIANT).toml
109
111
 
112
+ # Build the pixie-live-env disk image: pull the nosi arch-headless base
113
+ # via ORAS, inject the pixie CLI + pixie-on-tty1 service, slim + gzip,
114
+ # and publish the asset (< 2 GiB) plus its sha256 / content-sha256
115
+ # sidecars and a catalog fragment. The live-env boot modes nbdboot this
116
+ # image; PIXIE_LIVE_ENV_IMAGE_SHA selects it (= the content-sha256).
117
+ # Needs qemu-nbd + passwordless sudo + uv + the nbd kernel module.
118
+ live-env-image:
119
+ cd cijoe && cijoe tasks/live-env-image.yaml --monitor -c configs/live-env-image.toml
120
+
110
121
  # Build pixie's slim iPXE binary (bin-x86_64-efi/ipxe.efi) with the
111
122
  # embedded chain-loader baked in. Landed in the container image so a
112
123
  # fresh deploy gets the one-bootfile chain guarantee without needing
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixie-lab
3
- Version: 0.4.1
3
+ Version: 0.4.2
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,34 @@
1
+ # pixie live-env image - build configuration
2
+ #
3
+ # Drives the transform that turns the nosi ``arch-headless`` base disk
4
+ # image into the ``pixie-live-env`` image pixie nbdboots ephemerally for
5
+ # the live-env boot modes. See cijoe/tasks/live-env-image.yaml.
6
+ #
7
+ # Usage:
8
+ # cijoe tasks/live-env-image.yaml --config configs/live-env-image.toml --monitor
9
+ # (or via the Makefile dispatcher: ``make live-env-image``)
10
+
11
+ [pixie]
12
+ variant = "live-env-image"
13
+
14
+ [cijoe.workflow]
15
+ fail_fast = true
16
+
17
+ [live-env-image]
18
+ # The nosi base disk image + its netboot bundle (kernel + initrd). The
19
+ # transform only mutates userspace, so the pixie-live-env image reuses
20
+ # arch-headless's own kernel/initrd unchanged -- ``netboot_src`` points
21
+ # straight at the arch-headless netboot bundle.
22
+ base_src = "oras://ghcr.io/safl/nosi/arch-headless:latest"
23
+ netboot_src = "oras://ghcr.io/safl/nosi/arch-headless-netboot:latest"
24
+
25
+ # The stable release-asset URL the shipped catalog entry references
26
+ # (``.../releases/latest/download/pixie-live-env-x86_64.img.gz``), so a
27
+ # fresh pixie can Fetch it from the Catalog tab like any nosi image.
28
+ catalog_src = "https://github.com/safl/pixie/releases/latest/download/pixie-live-env-x86_64.img.gz"
29
+
30
+ image_name = "pixie-live-env"
31
+
32
+ # Where the published asset + sidecars + catalog fragment land. Mirrors
33
+ # the netboot-pc / usbboot-pc variants so all media live under one tree.
34
+ publish.dir = "{{ local.env.HOME }}/system_imaging/disk"
@@ -0,0 +1,307 @@
1
+ """
2
+ Build + publish the pixie-live-env disk image
3
+ =============================================
4
+
5
+ Produces the ``pixie-live-env`` image that pixie nbdboots ephemerally
6
+ for the live-env boot modes (``pixie-flash-once`` / ``-always`` /
7
+ ``pixie-inventory`` / ``pixie-tui``). The renderer selects this image
8
+ via the ``PIXIE_LIVE_ENV_IMAGE_SHA`` setting; the value an operator
9
+ sets there is the ``content_sha256`` this build computes and publishes
10
+ (see step 5 below and the ``.content-sha256`` sidecar).
11
+
12
+ Pipeline:
13
+
14
+ 1. ``uv build --wheel`` the current pixie-lab, then assemble a vendored
15
+ CLI tree: ``pip install --target`` the pixie package (``--no-deps``)
16
+ plus only the pure-Python CLI runtime deps (``rich`` + ``tomlkit``).
17
+ The CLI reaches the server over stdlib ``urllib`` -- NOT httpx -- so
18
+ the heavy fastapi / uvicorn / pydantic base deps are deliberately
19
+ left out. The image's stock ``python3`` runs this tree.
20
+
21
+ 2. Pull the nosi ``arch-headless`` base disk image via ORAS, reusing
22
+ pixie's own resolver (``python -m pixie.oras_pull``) so the bytes +
23
+ digest match a live catalog Fetch. Decompress the ``img.gz`` to a
24
+ raw disk image.
25
+
26
+ 3. Run ``live_env_transform.sh`` (privileged: qemu-nbd + mount) to
27
+ inject the vendored CLI + the ``pixie-on-tty1`` service trio and
28
+ slim conservatively, emitting a raw disk image.
29
+
30
+ 4. sha256 the RAW image -> ``content_sha256`` (== PIXIE_LIVE_ENV_IMAGE_SHA);
31
+ gzip it to ``pixie-live-env-x86_64.img.gz`` (the release asset);
32
+ assert the gzipped asset is < 2 GiB (GitHub's per-file release
33
+ limit) and fail otherwise.
34
+
35
+ 5. Emit alongside the asset: its ``.sha256`` checksum, a
36
+ ``.content-sha256`` sidecar carrying the raw-image sha (the value
37
+ for ``PIXIE_LIVE_ENV_IMAGE_SHA``), and ``pixie-live-env-catalog.toml``
38
+ -- a catalog fragment (the bindable disk image with its
39
+ ``netboot_src`` + the arch-headless netboot bundle it points at) the
40
+ release job merges into the shipped ``catalog.toml`` so the image is
41
+ fetchable via the Catalog tab like any other.
42
+
43
+ The cwd at run time is ``cijoe/`` (the Makefile cd's there), so the
44
+ repo root is ``Path.cwd().parent``. Requires: passwordless sudo,
45
+ qemu-utils (qemu-nbd + qemu-img), the ``nbd`` module, rsync, gzip, and
46
+ ``uv`` on PATH. Skipped for any variant other than ``live-env-image``.
47
+
48
+ Retargetable: False
49
+ """
50
+
51
+ from __future__ import annotations
52
+
53
+ import errno
54
+ import logging as log
55
+ import shutil
56
+ from argparse import ArgumentParser
57
+ from pathlib import Path
58
+
59
+ # Reuse the pyproject version reader so the published asset + catalog
60
+ # fragment carry the same stamped version as the other bakes.
61
+ from usb_iso_build import _read_pixie_version
62
+
63
+ # GitHub's per-file release-asset hard limit. The gzipped image must
64
+ # land under this or the release upload is rejected downstream, so we
65
+ # gate here (loud, early) instead.
66
+ RELEASE_ASSET_LIMIT = 2 * 1024 * 1024 * 1024
67
+
68
+ # Stable, unversioned asset basename so the catalog + settings default
69
+ # can reference ``.../releases/latest/download/<name>`` at a fixed URL
70
+ # (mirrors how the live-env tarball + catalog.toml are published).
71
+ ASSET_BASENAME = "pixie-live-env-x86_64.img.gz"
72
+ CATALOG_FRAGMENT_BASENAME = "pixie-live-env-catalog.toml"
73
+ CONTENT_SHA_BASENAME = "pixie-live-env-x86_64.content-sha256"
74
+
75
+ # Defaults; overridable via the ``[live-env-image]`` config table.
76
+ DEFAULT_BASE_SRC = "oras://ghcr.io/safl/nosi/arch-headless:latest"
77
+ DEFAULT_NETBOOT_SRC = "oras://ghcr.io/safl/nosi/arch-headless-netboot:latest"
78
+ DEFAULT_CATALOG_SRC = (
79
+ "https://github.com/safl/pixie/releases/latest/download/pixie-live-env-x86_64.img.gz"
80
+ )
81
+ DEFAULT_IMAGE_NAME = "pixie-live-env"
82
+
83
+
84
+ def add_args(parser: ArgumentParser):
85
+ del parser # no flags; signature kept for cijoe consistency
86
+
87
+
88
+ def _sha256_of(cijoe, path: Path) -> str | None:
89
+ err, state = cijoe.run_local(f"sha256sum {path}")
90
+ if err:
91
+ return None
92
+ out = state.output() if hasattr(state, "output") else str(state)
93
+ fields = out.strip().split()
94
+ return fields[0] if fields else None
95
+
96
+
97
+ def _build_vendored_cli(cijoe, repo_root: Path, build_dir: Path) -> Path | None:
98
+ """Build the wheel and assemble the vendored CLI tree. Returns the
99
+ vendor dir on success, ``None`` on failure."""
100
+ wheel_out = build_dir / "wheel"
101
+ if wheel_out.exists():
102
+ shutil.rmtree(wheel_out)
103
+ wheel_out.mkdir(parents=True)
104
+
105
+ err, _ = cijoe.run_local(f"sh -c 'cd {repo_root} && uv build --wheel --out-dir {wheel_out}'")
106
+ if err:
107
+ log.error("uv build --wheel failed")
108
+ return None
109
+ wheels = sorted(wheel_out.glob("pixie_lab-*-py3-none-any.whl"))
110
+ if not wheels:
111
+ log.error(f"no pixie_lab wheel produced in {wheel_out}")
112
+ return None
113
+ wheel = wheels[-1]
114
+
115
+ vendor = build_dir / "vendor"
116
+ if vendor.exists():
117
+ shutil.rmtree(vendor)
118
+ vendor.mkdir(parents=True)
119
+
120
+ # The pixie package only (no deps -- installing the full wheel would
121
+ # drag fastapi / uvicorn / httpx / pydantic, which are compiled,
122
+ # version-specific, and unused by the CLI).
123
+ err, _ = cijoe.run_local(f"uv pip install --target {vendor} --no-compile --no-deps {wheel}")
124
+ if err:
125
+ log.error("uv pip install (pixie package, --no-deps) failed")
126
+ return None
127
+ # The pure-Python CLI runtime deps. rich powers the wizard; tomlkit
128
+ # backs the catalog round-trip the CLI can reach. Both ship as
129
+ # ``py3-none-any`` wheels, so they import under the image's own
130
+ # python3 regardless of its minor version.
131
+ err, _ = cijoe.run_local(f"uv pip install --target {vendor} --no-compile rich tomlkit")
132
+ if err:
133
+ log.error("uv pip install (rich + tomlkit) failed")
134
+ return None
135
+ return vendor
136
+
137
+
138
+ def main(args, cijoe):
139
+ del args
140
+ cijoe_dir = Path.cwd()
141
+ repo_root = cijoe_dir.parent
142
+ pixie_media = repo_root / "pixie-media"
143
+
144
+ variant = cijoe.getconf("pixie", {}).get("variant", "")
145
+ if variant != "live-env-image":
146
+ log.info(f"Skipping live_env_image (variant={variant!r}; only 'live-env-image' runs)")
147
+ return 0
148
+
149
+ conf = cijoe.getconf("live-env-image", {})
150
+ base_src = conf.get("base_src", DEFAULT_BASE_SRC)
151
+ netboot_src = conf.get("netboot_src", DEFAULT_NETBOOT_SRC)
152
+ catalog_src = conf.get("catalog_src", DEFAULT_CATALOG_SRC)
153
+ image_name = conf.get("image_name", DEFAULT_IMAGE_NAME)
154
+ publish_dir_str = conf.get("publish", {}).get("dir")
155
+ if not publish_dir_str:
156
+ log.error("live-env-image.publish.dir is unset in the config")
157
+ return errno.EINVAL
158
+ publish_dir = Path(publish_dir_str)
159
+ publish_dir.mkdir(parents=True, exist_ok=True)
160
+
161
+ if not pixie_media.exists():
162
+ log.error(f"pixie-media tree missing: {pixie_media}")
163
+ return errno.ENOENT
164
+
165
+ build_dir = cijoe_dir / "_build" / "live-env-image"
166
+ if build_dir.exists():
167
+ # The transform's scratch is torn down internally, but the raw
168
+ # base image is owned by the invoking user; a plain rm is fine.
169
+ err, _ = cijoe.run_local(f"sudo rm -rf {build_dir}")
170
+ if err:
171
+ log.error(f"failed to remove stale build dir {build_dir}")
172
+ return err
173
+ build_dir.mkdir(parents=True)
174
+
175
+ pixie_version = _read_pixie_version(cijoe_dir)
176
+ log.info(f"Building {image_name} v{pixie_version} from base {base_src}")
177
+
178
+ # 1. Vendored CLI tree.
179
+ vendor = _build_vendored_cli(cijoe, repo_root, build_dir)
180
+ if vendor is None:
181
+ return errno.EIO
182
+
183
+ # 2. Pull + decompress the base image, reusing pixie's ORAS resolver.
184
+ base_gz = build_dir / "base.img.gz"
185
+ err, _ = cijoe.run_local(
186
+ f"sh -c 'cd {repo_root} && uv run python -m pixie.oras_pull {base_src} {base_gz}'"
187
+ )
188
+ if err:
189
+ log.error(f"failed to pull base image {base_src}")
190
+ return err
191
+ base_raw = build_dir / "base.img"
192
+ err, _ = cijoe.run_local(f"sh -c 'gzip -dc {base_gz} > {base_raw}'")
193
+ if err:
194
+ log.error("failed to decompress the base image")
195
+ return err
196
+
197
+ # 3. Transform: inject CLI + service trio, slim, fstrim.
198
+ out_raw = build_dir / "pixie-live-env.img"
199
+ transform = cijoe_dir / "scripts" / "live_env_transform.sh"
200
+ err, _ = cijoe.run_local(
201
+ f"sudo bash {transform} "
202
+ f"--base {base_raw} --out {out_raw} --vendor {vendor} "
203
+ f"--media {pixie_media} --force"
204
+ )
205
+ if err:
206
+ log.error("live_env_transform.sh failed")
207
+ return err
208
+ # The transform chown's the output back to us, but be defensive.
209
+ cijoe.run_local(f"sudo chown $(id -u):$(id -g) {out_raw}")
210
+
211
+ # 4. Content-address on the RAW image (matches pixie's img.gz fetch:
212
+ # decompress -> sha of the raw disk image), then gzip the asset.
213
+ content_sha = _sha256_of(cijoe, out_raw)
214
+ if not content_sha:
215
+ log.error(f"failed computing content sha256 of {out_raw}")
216
+ return errno.EIO
217
+ log.info(f"content_sha256 (PIXIE_LIVE_ENV_IMAGE_SHA) = {content_sha}")
218
+
219
+ asset_path = publish_dir / ASSET_BASENAME
220
+ err, _ = cijoe.run_local(f"sh -c 'gzip -c {out_raw} > {asset_path}'")
221
+ if err:
222
+ log.error("failed gzipping the live-env image asset")
223
+ return err
224
+
225
+ asset_bytes = asset_path.stat().st_size
226
+ log.info(f"asset {asset_path.name}: {asset_bytes} bytes ({asset_bytes / 2**30:.2f} GiB)")
227
+ if asset_bytes >= RELEASE_ASSET_LIMIT:
228
+ log.error(
229
+ f"{asset_path.name} is {asset_bytes / 2**30:.2f} GiB, "
230
+ f">= the 2 GiB GitHub release-asset limit; tighten the transform slim"
231
+ )
232
+ return errno.EFBIG
233
+
234
+ # 5. Sidecars + catalog fragment.
235
+ asset_sha = _sha256_of(cijoe, asset_path)
236
+ if not asset_sha:
237
+ log.error("failed computing sha256 of the gzipped asset")
238
+ return errno.EIO
239
+ (publish_dir / f"{ASSET_BASENAME}.sha256").write_text(
240
+ f"{asset_sha} {ASSET_BASENAME}\n", encoding="utf-8"
241
+ )
242
+ (publish_dir / CONTENT_SHA_BASENAME).write_text(f"{content_sha}\n", encoding="utf-8")
243
+
244
+ fragment = _catalog_fragment(
245
+ image_name=image_name,
246
+ catalog_src=catalog_src,
247
+ netboot_src=netboot_src,
248
+ content_sha=content_sha,
249
+ version=pixie_version,
250
+ )
251
+ (publish_dir / CATALOG_FRAGMENT_BASENAME).write_text(fragment, encoding="utf-8")
252
+
253
+ cijoe.run_local(f"ls -la {publish_dir}")
254
+ log.info(
255
+ f"published {ASSET_BASENAME} (+ .sha256, {CONTENT_SHA_BASENAME}, "
256
+ f"{CATALOG_FRAGMENT_BASENAME}) to {publish_dir}"
257
+ )
258
+ return 0
259
+
260
+
261
+ def _catalog_fragment(
262
+ *,
263
+ image_name: str,
264
+ catalog_src: str,
265
+ netboot_src: str,
266
+ content_sha: str,
267
+ version: str,
268
+ ) -> str:
269
+ """Render the catalog fragment (no ``version =`` header; the release
270
+ job appends these ``[[images]]`` blocks to the shipped catalog).
271
+
272
+ Two peer entries: the bindable disk image (with a filled-in
273
+ ``content_sha256`` == PIXIE_LIVE_ENV_IMAGE_SHA, and a
274
+ ``netboot_src`` URL cross-reference) and the arch-headless netboot
275
+ bundle it points at, so the nbdboot renderer resolves the pair.
276
+ """
277
+ disk_desc = (
278
+ "pixie live-env (nosi arch-headless + the pixie CLI + pixie-on-tty1 service). "
279
+ "nbdbooted ephemerally for the live-env boot modes."
280
+ )
281
+ bundle_desc = (
282
+ "Netboot bundle for arch-headless: vmlinuz + initrd so pixie can nbdboot the "
283
+ "pixie-live-env image over NBD."
284
+ )
285
+ return f"""\
286
+ # pixie-live-env {version} -- the image the live-env boot modes
287
+ # (pixie-flash-once / -always / pixie-inventory / pixie-tui) nbdboot
288
+ # ephemerally. Set PIXIE_LIVE_ENV_IMAGE_SHA to the content_sha256 below
289
+ # to select it (that sha is the sha256 of the raw disk image, which is
290
+ # exactly what pixie content-addresses this img.gz to after fetching).
291
+
292
+ [[images]]
293
+ name = "{image_name}"
294
+ src = "{catalog_src}"
295
+ format = "img.gz"
296
+ arch = "x86_64"
297
+ description = "{disk_desc}"
298
+ netboot_src = "{netboot_src}"
299
+ content_sha256 = "{content_sha}"
300
+
301
+ [[images]]
302
+ name = "nosi arch-headless netboot bundle"
303
+ src = "{netboot_src}"
304
+ format = "tar.gz"
305
+ arch = "x86_64"
306
+ description = "{bundle_desc}"
307
+ """