@@ -414,71 +414,141 @@ func printLocalFileSizes(basePath, buildID string) {
414414}
415415
416416func setupKernel (ctx context.Context , dir , version string ) error {
417- dstPath := filepath .Join (dir , version , "vmlinux.bin" )
417+ arch := utils .TargetArch ()
418+ dstPath := filepath .Join (dir , version , arch , "vmlinux.bin" )
419+
418420 if err := os .MkdirAll (filepath .Dir (dstPath ), 0o755 ); err != nil {
419421 return fmt .Errorf ("mkdir kernel dir: %w" , err )
420422 }
421423
422424 if _ , err := os .Stat (dstPath ); err == nil {
423- fmt .Printf ("✓ Kernel %s exists\n " , version )
425+ fmt .Printf ("✓ Kernel %s (%s) exists\n " , version , arch )
424426
425427 return nil
426428 }
427429
428- kernelURL , _ := url .JoinPath ("https://storage.googleapis.com/e2b-prod-public-builds/kernels/" , version , "vmlinux.bin" )
429- fmt .Printf ("⬇ Downloading kernel %s...\n " , version )
430+ // Try arch-specific URL first: {version}/{arch}/vmlinux.bin
431+ archURL , err := url .JoinPath ("https://storage.googleapis.com/e2b-prod-public-builds/kernels/" , version , arch , "vmlinux.bin" )
432+ if err != nil {
433+ return fmt .Errorf ("invalid kernel URL: %w" , err )
434+ }
435+
436+ fmt .Printf ("⬇ Downloading kernel %s (%s)...\n " , version , arch )
437+
438+ if err := download (ctx , archURL , dstPath , 0o644 ); err == nil {
439+ return nil
440+ } else if ! errors .Is (err , errNotFound ) {
441+ return fmt .Errorf ("failed to download kernel: %w" , err )
442+ }
443+
444+ // Legacy URLs are x86_64-only; only fall back for amd64.
445+ if arch != "amd64" {
446+ return fmt .Errorf ("kernel %s not found for %s (no legacy fallback for non-amd64)" , version , arch )
447+ }
448+
449+ legacyURL , err := url .JoinPath ("https://storage.googleapis.com/e2b-prod-public-builds/kernels/" , version , "vmlinux.bin" )
450+ if err != nil {
451+ return fmt .Errorf ("invalid kernel legacy URL: %w" , err )
452+ }
453+
454+ fmt .Printf (" %s path not found, trying legacy URL...\n " , arch )
430455
431- return download (ctx , kernelURL , dstPath , 0o644 )
456+ return download (ctx , legacyURL , dstPath , 0o644 )
432457}
433458
434459func setupFC (ctx context.Context , dir , version string ) error {
435- dstPath := filepath .Join (dir , version , "firecracker" )
460+ arch := utils .TargetArch ()
461+ dstPath := filepath .Join (dir , version , arch , "firecracker" )
462+
436463 if err := os .MkdirAll (filepath .Dir (dstPath ), 0o755 ); err != nil {
437464 return fmt .Errorf ("mkdir firecracker dir: %w" , err )
438465 }
439466
440467 if _ , err := os .Stat (dstPath ); err == nil {
441- fmt .Printf ("✓ Firecracker %s exists\n " , version )
468+ fmt .Printf ("✓ Firecracker %s (%s) exists\n " , version , arch )
442469
443470 return nil
444471 }
445472
446- // Old releases in https://github.com/e2b-dev/fc-versions/releases don't build
447- // x86_64 and aarch64 binaries. They just build the former and the asset's name
448- // is just 'firecracker'
449- // TODO: Drop this work-around once we remove support for Firecracker v1.10
450- assetName := "firecracker-amd64"
451- if strings .HasPrefix (version , "v1.10" ) {
452- assetName = "firecracker"
473+ // Download from GCS bucket with {version}/{arch}/firecracker path
474+ fcURL , err := url .JoinPath ("https://storage.googleapis.com/e2b-prod-public-builds/fc-versions/" , version , arch , "firecracker" )
475+ if err != nil {
476+ return fmt .Errorf ("invalid Firecracker URL: %w" , err )
453477 }
454- fcURL := fmt .Sprintf ("https://github.com/e2b-dev/fc-versions/releases/download/%s/%s" , version , assetName )
455- fmt .Printf ("⬇ Downloading Firecracker %s...\n " , version )
456478
457- return download (ctx , fcURL , dstPath , 0o755 )
479+ fmt .Printf ("⬇ Downloading Firecracker %s (%s)...\n " , version , arch )
480+
481+ if err := download (ctx , fcURL , dstPath , 0o755 ); err == nil {
482+ return nil
483+ } else if ! errors .Is (err , errNotFound ) {
484+ return fmt .Errorf ("failed to download Firecracker: %w" , err )
485+ }
486+
487+ // Legacy URLs are x86_64-only; only fall back for amd64.
488+ if arch != "amd64" {
489+ return fmt .Errorf ("firecracker %s not found for %s (no legacy fallback for non-amd64)" , version , arch )
490+ }
491+
492+ legacyURL , err := url .JoinPath ("https://storage.googleapis.com/e2b-prod-public-builds/fc-versions/" , version , "firecracker" )
493+ if err != nil {
494+ return fmt .Errorf ("invalid Firecracker legacy URL: %w" , err )
495+ }
496+
497+ fmt .Printf (" %s path not found, trying legacy URL...\n " , arch )
498+
499+ return download (ctx , legacyURL , dstPath , 0o755 )
458500}
459501
460- func download (ctx context.Context , url , path string , perm os.FileMode ) error {
461- req , _ := http .NewRequestWithContext (ctx , http .MethodGet , url , nil )
502+ var errNotFound = errors .New ("not found" )
503+
504+ func download (ctx context.Context , rawURL , path string , perm os.FileMode ) error {
505+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , rawURL , nil )
506+ if err != nil {
507+ return fmt .Errorf ("invalid download URL %s: %w" , rawURL , err )
508+ }
509+
462510 resp , err := (& http.Client {Timeout : 5 * time .Minute }).Do (req )
463511 if err != nil {
464512 return err
465513 }
466514 defer resp .Body .Close ()
467515
516+ if resp .StatusCode == http .StatusNotFound {
517+ return fmt .Errorf ("%w: %s" , errNotFound , rawURL )
518+ }
468519 if resp .StatusCode != http .StatusOK {
469- return fmt .Errorf ("HTTP %d: %s" , resp .StatusCode , url )
520+ return fmt .Errorf ("HTTP %d: %s" , resp .StatusCode , rawURL )
470521 }
471522
472- f , err := os .OpenFile (path , os .O_CREATE | os .O_WRONLY | os .O_TRUNC , perm )
523+ // Write to a temporary file and rename atomically to avoid partial files
524+ // on network errors or disk-full conditions.
525+ tmpPath := path + ".tmp"
526+
527+ f , err := os .OpenFile (tmpPath , os .O_CREATE | os .O_WRONLY | os .O_TRUNC , perm )
473528 if err != nil {
474529 return err
475530 }
476- defer f .Close ()
477531
478- _ , err = io .Copy (f , resp .Body )
479- if err == nil {
480- fmt .Printf ("✓ Downloaded %s\n " , filepath .Base (path ))
532+ if _ , err := io .Copy (f , resp .Body ); err != nil {
533+ f .Close ()
534+ os .Remove (tmpPath )
535+
536+ return err
481537 }
482538
483- return err
539+ if err := f .Close (); err != nil {
540+ os .Remove (tmpPath )
541+
542+ return err
543+ }
544+
545+ if err := os .Rename (tmpPath , path ); err != nil {
546+ os .Remove (tmpPath )
547+
548+ return err
549+ }
550+
551+ fmt .Printf ("✓ Downloaded %s\n " , filepath .Base (path ))
552+
553+ return nil
484554}
0 commit comments