pixie-lab 0.3.1__tar.gz → 0.4.0__tar.gz

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