From a7ef94e1400230d67bb9586393b39f07068cc000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Van=C4=9Bk?= Date: Thu, 16 Jul 2026 16:55:43 +0200 Subject: [PATCH 1/2] fix(orchestrator): make copy-build handle filesystem-only snapshots copy-build unconditionally read memfile.header, so copying a filesystem-only snapshot (which uploads no memory snapshot: no memfile.header, no memfile data, no snapfile) died with: failed to create header from object: ... failed to create reader for "/memfile.header": object does not exist Read metadata.json first and branch on its filesystem_only flag - the resume path's source of truth - instead of probing for memfile.header. This keeps a missing memfile.header on a full snapshot a hard error (incomplete build) rather than silently degrading it to an fs-only copy, and skips memfile and snapfile only for genuine fs-only builds. Rootfs artifacts and metadata.json are copied as before. --- packages/orchestrator/cmd/copy-build/main.go | 67 ++++++++++++++------ 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/packages/orchestrator/cmd/copy-build/main.go b/packages/orchestrator/cmd/copy-build/main.go index 438c75cea6..11ceefdbc9 100644 --- a/packages/orchestrator/cmd/copy-build/main.go +++ b/packages/orchestrator/cmd/copy-build/main.go @@ -20,6 +20,7 @@ import ( "github.com/google/uuid" "golang.org/x/sync/errgroup" + "github.com/e2b-dev/infra/packages/orchestrator/pkg/template/metadata" "github.com/e2b-dev/infra/packages/shared/pkg/id" "github.com/e2b-dev/infra/packages/shared/pkg/storage" "github.com/e2b-dev/infra/packages/shared/pkg/storage/header" @@ -221,32 +222,66 @@ func main() { var filesToCopy []string - // Extract all files referenced by the build memfile header - buildMemfileHeaderPath := paths.MemfileHeader() - - var memfileHeader *header.Header + // Metadata is the source of truth for whether the build is a + // filesystem-only snapshot (no memfile, no snapfile). + var meta metadata.Template if strings.HasPrefix(*from, "gs://") { bucketName, _ := strings.CutPrefix(*from, "gs://") - h, err := NewHeaderFromObject(ctx, bucketName, buildMemfileHeaderPath) + provider, err := storage.NewGCP(ctx, bucketName, nil) if err != nil { - log.Fatalf("failed to create header from object: %s", err) + log.Fatalf("failed to create GCS bucket storage provider: %s", err) + } + + m, err := metadata.FromBuildID(ctx, provider, *buildId) + if err != nil { + log.Fatalf("failed to read build metadata: %s", err) } - memfileHeader = h + meta = m } else { - h, err := NewHeaderFromPath(ctx, *from, buildMemfileHeaderPath) + m, err := metadata.FromFile(path.Join(*from, "templates", paths.Metadata())) if err != nil { - log.Fatalf("failed to create header from path: %s", err) + log.Fatalf("failed to read build metadata: %s", err) } - memfileHeader = h + meta = m } - dataReferences := getReferencedData(memfileHeader, storage.MemfileName) + if meta.IsFilesystemOnly() { + fmt.Fprintf(os.Stderr, "Build is a filesystem-only snapshot; skipping memfile and snapfile\n") + } else { + // Extract all files referenced by the build memfile header + buildMemfileHeaderPath := paths.MemfileHeader() - filesToCopy = append(filesToCopy, buildMemfileHeaderPath) - filesToCopy = append(filesToCopy, dataReferences...) + var memfileHeader *header.Header + if strings.HasPrefix(*from, "gs://") { + bucketName, _ := strings.CutPrefix(*from, "gs://") + + h, err := NewHeaderFromObject(ctx, bucketName, buildMemfileHeaderPath) + if err != nil { + log.Fatalf("failed to create header from object: %s", err) + } + + memfileHeader = h + } else { + h, err := NewHeaderFromPath(ctx, *from, buildMemfileHeaderPath) + if err != nil { + log.Fatalf("failed to create header from path: %s", err) + } + + memfileHeader = h + } + + dataReferences := getReferencedData(memfileHeader, storage.MemfileName) + + filesToCopy = append(filesToCopy, buildMemfileHeaderPath) + filesToCopy = append(filesToCopy, dataReferences...) + + // Add the snapfile to the list of files to copy + snapfilePath := paths.Snapfile() + filesToCopy = append(filesToCopy, snapfilePath) + } // Extract all files referenced by the build rootfs header buildRootfsHeaderPath := paths.RootfsHeader() @@ -269,15 +304,11 @@ func main() { rootfsHeader = h } - dataReferences = getReferencedData(rootfsHeader, storage.RootfsName) + dataReferences := getReferencedData(rootfsHeader, storage.RootfsName) filesToCopy = append(filesToCopy, buildRootfsHeaderPath) filesToCopy = append(filesToCopy, dataReferences...) - // Add the snapfile to the list of files to copy - snapfilePath := paths.Snapfile() - filesToCopy = append(filesToCopy, snapfilePath) - metadataPath := paths.Metadata() filesToCopy = append(filesToCopy, metadataPath) From fdcfdff0e54a1f59015d0987f5bf4a7a39b76b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Van=C4=9Bk?= Date: Thu, 16 Jul 2026 18:43:28 +0200 Subject: [PATCH 2/2] build(orchestrator): make template metadata package cross-platform pkg/template/metadata was //go:build linux only transitively: it imports pkg/sandbox/block for two pure data types (AccessType, PrefetchBlockEntry), and every file in block carries the linux tag. That made anything importing metadata linux-only too - including cmd/copy-build since it started reading metadata.json, breaking its darwin build. Drop the linux tag from block/prefetch_tracker.go (pure Go, no platform-specific imports) and from the metadata package and its tests. The rest of the block package stays linux-only. --- packages/orchestrator/pkg/sandbox/block/prefetch_tracker.go | 2 -- packages/orchestrator/pkg/template/metadata/prefetch.go | 2 -- .../orchestrator/pkg/template/metadata/prefetch_carry_test.go | 2 -- .../orchestrator/pkg/template/metadata/template_metadata.go | 2 -- .../pkg/template/metadata/template_metadata_test.go | 2 -- 5 files changed, 10 deletions(-) diff --git a/packages/orchestrator/pkg/sandbox/block/prefetch_tracker.go b/packages/orchestrator/pkg/sandbox/block/prefetch_tracker.go index f32486e943..af586fc02b 100644 --- a/packages/orchestrator/pkg/sandbox/block/prefetch_tracker.go +++ b/packages/orchestrator/pkg/sandbox/block/prefetch_tracker.go @@ -1,5 +1,3 @@ -//go:build linux - package block import ( diff --git a/packages/orchestrator/pkg/template/metadata/prefetch.go b/packages/orchestrator/pkg/template/metadata/prefetch.go index d6796d9556..5d61e9bafe 100644 --- a/packages/orchestrator/pkg/template/metadata/prefetch.go +++ b/packages/orchestrator/pkg/template/metadata/prefetch.go @@ -1,5 +1,3 @@ -//go:build linux - package metadata import ( diff --git a/packages/orchestrator/pkg/template/metadata/prefetch_carry_test.go b/packages/orchestrator/pkg/template/metadata/prefetch_carry_test.go index b41e76f67c..0d7354530a 100644 --- a/packages/orchestrator/pkg/template/metadata/prefetch_carry_test.go +++ b/packages/orchestrator/pkg/template/metadata/prefetch_carry_test.go @@ -1,5 +1,3 @@ -//go:build linux - package metadata import ( diff --git a/packages/orchestrator/pkg/template/metadata/template_metadata.go b/packages/orchestrator/pkg/template/metadata/template_metadata.go index eb9fb70ccd..2a5f344d4e 100644 --- a/packages/orchestrator/pkg/template/metadata/template_metadata.go +++ b/packages/orchestrator/pkg/template/metadata/template_metadata.go @@ -1,5 +1,3 @@ -//go:build linux - package metadata import ( diff --git a/packages/orchestrator/pkg/template/metadata/template_metadata_test.go b/packages/orchestrator/pkg/template/metadata/template_metadata_test.go index 11dbc26206..b01e851890 100644 --- a/packages/orchestrator/pkg/template/metadata/template_metadata_test.go +++ b/packages/orchestrator/pkg/template/metadata/template_metadata_test.go @@ -1,5 +1,3 @@ -//go:build linux - package metadata import (