From 994152bedfb6d6b132f5758a5b290ab6fa0f9a5c Mon Sep 17 00:00:00 2001 From: josh Date: Thu, 14 May 2026 14:09:12 -0400 Subject: [PATCH] Use sanhook to expose ISO as block device during kernel/initrd boot The CPIO-embedded initrd approach failed (too large for iPXE memory). Instead, use iPXE's sanhook to connect the ISO as a SAN block device before booting with kernel/initrd. The installer finds the ISO on the SAN device while we retain control over kernel parameters. Co-Authored-By: Claude Opus 4.6 --- internal/image/service.go | 18 +----------------- internal/pxe/ipxe.go | 9 ++++++--- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/internal/image/service.go b/internal/image/service.go index b01868e..7e86000 100644 --- a/internal/image/service.go +++ b/internal/image/service.go @@ -53,24 +53,8 @@ func (s *Service) Upload(ctx context.Context, p UploadParams) (*model.Image, err return nil, fmt.Errorf("extract ISO: %w", err) } - report := func(stage, detail string) { - if p.OnProgress != nil { - p.OnProgress(stage, detail) - } - } - report("packaging", "Creating PXE boot image (embedding ISO in initrd)...") - - origInitrdPath := filepath.Join(destDir, result.InitrdFilename) - origISOPath := filepath.Join(destDir, result.ISOFilename) - pxeInitrdFile := "initrd-pxe.img" - pxeInitrdPath := filepath.Join(destDir, pxeInitrdFile) - if err := CreatePXEInitrd(origInitrdPath, origISOPath, pxeInitrdPath); err != nil { - os.RemoveAll(destDir) - return nil, fmt.Errorf("create PXE initrd: %w", err) - } - kernelPath := filepath.Join(p.Name, result.KernelFilename) - initrdPath := filepath.Join(p.Name, pxeInitrdFile) + initrdPath := filepath.Join(p.Name, result.InitrdFilename) isoPath := filepath.Join(p.Name, result.ISOFilename) id, err := s.Store.Create(ctx, model.Image{ diff --git a/internal/pxe/ipxe.go b/internal/pxe/ipxe.go index b0ad6a4..f476833 100644 --- a/internal/pxe/ipxe.go +++ b/internal/pxe/ipxe.go @@ -9,14 +9,17 @@ import ( func BuildIPXEScript(publicURL string, img *model.Image, mac string) string { kernelURL := fmt.Sprintf("%s/images/boot/%s", publicURL, img.KernelPath) initrdURL := fmt.Sprintf("%s/images/boot/%s", publicURL, img.InitrdPath) + isoURL := fmt.Sprintf("%s/images/boot/%s", publicURL, img.ISOPath) return fmt.Sprintf(`#!ipxe echo Provisioning: booting %s on ${mac} +echo Connecting ISO via SAN... +sanhook %s echo Loading kernel... -kernel %s ramdisk_size=16777216 vga=791 video=vesafb:lfb:on rw quiet splash=verbose rdinit=/pxe-init initrd=initrd -echo Loading initrd (this may take a few minutes)... +kernel %s ramdisk_size=16777216 vga=791 video=vesafb:lfb:on rw quiet splash=verbose initrd=initrd +echo Loading initrd... initrd --name initrd %s echo Booting... boot -`, img.Name, kernelURL, initrdURL) +`, img.Name, isoURL, kernelURL, initrdURL) }