Skip to content

Fix: Support snapshots for non-default clusters#2947

Merged
sitole merged 1 commit into
mainfrom
fix/sandbox-snapshots-support-for-byoc
Jun 8, 2026
Merged

Fix: Support snapshots for non-default clusters#2947
sitole merged 1 commit into
mainfrom
fix/sandbox-snapshots-support-for-byoc

Conversation

@sitole

@sitole sitole commented Jun 8, 2026

Copy link
Copy Markdown
Member

Add cluster ID (if not default) to snaphost, allowing to resume template when using BYOC.

@cursor

cursor Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes snapshot pause and snapshot-template DB writes; scope is narrow and follows the existing LocalClusterID null pattern, but incorrect cluster handling could affect multi-cluster routing or template resolution.

Overview
Snapshot and snapshot-template creation now persist the sandbox’s cluster on new envs rows when the sandbox is not on the local/default cluster, so paused snapshots and snapshot templates stay tied to the right cluster instead of behaving like default-cluster resources.

Reviewed by Cursor Bugbot for commit d92ff3f. Bugbot is set up for automated code reviews on this repo. Configure here.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the orchestrator to propagate and store the ClusterID when pausing instances and creating snapshot templates. Specifically, it conditionally passes the cluster ID (if it is not the local cluster ID) to the database queries for upserting snapshots and creating snapshot template environments, and updates the corresponding SQL queries to insert the cluster_id into the envs table. There are no review comments, and we have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@codecov

codecov Bot commented Jun 8, 2026

Copy link
Copy Markdown

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
2746 4 2742 7
View the top 1 failed test(s) by shortest run time
github.com/e2b-dev/infra/tests/integration/internal/tests/api/templates::TestTemplateBuildCOPY
Stack Traces | 300s run time
=== RUN   TestTemplateBuildCOPY
=== PAUSE TestTemplateBuildCOPY
=== CONT  TestTemplateBuildCOPY
    build_template_test.go:133: test-ubuntu-copy: [info] Building template yfzti79n4gxgdupdxd7d/d501c58b-6102-4279-a4d8-6fc6d77760c9
    build_template_test.go:133: test-ubuntu-copy: [info] [base] FROM ubuntu:24.04 [b9371451a87d7d440003cda6ae89fcf7dc35fd82a96b9152fc15a4a8ca68de41]
    build_template_test.go:133: test-ubuntu-copy: [info] Base Docker image size: 30 MB
    build_template_test.go:133: test-ubuntu-copy: [info] Creating file system and pulling Docker image
    build_template_test.go:133: test-ubuntu-copy: [info] Uncompressing layer sha256:cb259a83ac3dd9fea0b394df41df2b298adf0df938fef5999475af18a751c257 30 MB
    build_template_test.go:133: test-ubuntu-copy: [info] Uncompressing layer sha256:a2e6082ce9c9e455e03295996cc73435581d095ba19d131d565d35618458ad9e 13 MB
    build_template_test.go:133: test-ubuntu-copy: [info] Uncompressing layer sha256:8c4b1b28875140ed3abacaf16ad0d696f6bef912f52d2148f261a23e3349465b 168 B
    build_template_test.go:133: test-ubuntu-copy: [info] Layers extracted
    build_template_test.go:133: test-ubuntu-copy: [info] Root filesystem structure: bin, boot, dev, etc, home, lib, lib64, media, mnt, opt, proc, root, run, sbin, srv, sys, tmp, usr, var
    build_template_test.go:133: test-ubuntu-copy: [info] Provisioning sandbox template
    build_template_test.go:1156: 
        	Error Trace:	.../api/templates/build_template_test.go:96
        	            				.../api/templates/build_template_test.go:1156
        	Error:      	Received unexpected error:
        	            	Get "http://localhost:.../builds/d501c58b-6102-4279-a4d8-6fc6d77760c9/status?logsOffset=10&level=info": context deadline exceeded
        	Test:       	TestTemplateBuildCOPY
--- FAIL: TestTemplateBuildCOPY (300.46s)
View the full list of 3 ❄️ flaky test(s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/sandboxes::TestSandboxListPaginationRunningLargerLimit

Flake rate in main: 39.28% (Passed 926 times, Failed 599 times)

Stack Traces | 91s run time
=== RUN   TestSandboxListPaginationRunningLargerLimit
    sandbox_list_test.go:327: Created sandbox 1/12: iwm2bj8xytifk0cns55y6
    sandbox_list_test.go:327: Created sandbox 2/12: ibf9e24jf8rahey0njcv1
    sandbox_list_test.go:327: Created sandbox 3/12: izr0cowhm41qsxhy6zrnv
    sandbox_list_test.go:327: Created sandbox 4/12: is3fyl5vhseetzkmiurrz
    sandbox_list_test.go:327: Created sandbox 5/12: imksox7wk9pq199mjhi6k
    sandbox_list_test.go:327: Created sandbox 6/12: iatu5v6j0qyjnd1bmkruc
    sandbox_list_test.go:327: Created sandbox 7/12: iu2yr61iczrz0r8q9y3jv
    sandbox_list_test.go:327: Created sandbox 8/12: ikrza40xnfp2jbvr6853l
    sandbox_list_test.go:327: Created sandbox 9/12: iqlo651icjnwyn3874e28
    sandbox_list_test.go:327: Created sandbox 10/12: ibrxgjnozn90s78bwjocv
    sandbox_list_test.go:327: Created sandbox 11/12: i3y3q8oi1hzxfvtuqb6l2
    sandbox_list_test.go:327: Created sandbox 12/12: ihdvr5pf2d5r6twwd3qlq
    sandbox_list_test.go:330: 
        	Error Trace:	.../api/sandboxes/sandbox_list_test.go:340
        	            				.../hostedtoolcache/go/1.26.3.../src/runtime/asm_amd64.s:1771
        	Error:      	"[]" should have 12 item(s), but has 0
    sandbox_list_test.go:330: 
        	Error Trace:	.../api/sandboxes/sandbox_list_test.go:330
        	Error:      	Condition never satisfied
        	Test:       	TestSandboxListPaginationRunningLargerLimit
--- FAIL: TestSandboxListPaginationRunningLargerLimit (90.97s)
github.com/e2b-dev/infra/tests/integration/internal/tests/orchestrator::TestSandboxMemoryIntegrity

Flake rate in main: 54.07% (Passed 919 times, Failed 1082 times)

Stack Traces | 60.6s run time
=== RUN   TestSandboxMemoryIntegrity
=== PAUSE TestSandboxMemoryIntegrity
=== CONT  TestSandboxMemoryIntegrity
    sandbox_memory_integrity_test.go:27: Build completed successfully
--- FAIL: TestSandboxMemoryIntegrity (60.62s)
github.com/e2b-dev/infra/tests/integration/internal/tests/orchestrator::TestSandboxMemoryIntegrity/tmpfs_hash

Flake rate in main: 54.14% (Passed 909 times, Failed 1073 times)

Stack Traces | 187s run time
=== RUN   TestSandboxMemoryIntegrity/tmpfs_hash
=== PAUSE TestSandboxMemoryIntegrity/tmpfs_hash
=== CONT  TestSandboxMemoryIntegrity/tmpfs_hash
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{start:{pid:1279}}
Executing command bash in sandbox iohy8rjwxdzzqum2ebh3z (user: root)
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Total memory: 985 MB\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Used memory before tmpfs mount: 185 MB\nFree memory before tmpfs mount: 799 MB\nMemory to use in integrity test (60% of free, min 64MB): 479 MB\n"}}
Executing command bash in sandbox iohy8rjwxdzzqum2ebh3z (user: root)
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"479+0 records in\n479+0 records out\n502267904 bytes (502 MB, 479 MiB) copied, 2.08136 s, 241 MB/s\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\tCommand being timed: \"dd if=/dev/urandom of=/mnt/testfile bs=1M count=479\"\n\tUser time (seconds): 0.00\n\tSystem time (seconds): 2.07\n\tPercent of CPU this job got: 99%\n\tElapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08\n\tAverage shared text size (kbytes): 0\n\tAverage unshared d"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"ata size (kbytes"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"): 0\n\t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"Avera"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"ge s"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"tack"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" siz"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e ("}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"kbyt"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"es): 0\n\tAverage total size (kbytes): 0\n\tMaximum resident set size (kbytes): 2604\n\tAverage resident set size (kbytes): 0\n\tMajor (requiring I/O) page faults: 3\n\tMinor (reclaiming a frame) page faults: 342\n\tVoluntary context switches: 4\n\tInvoluntary context switches: 10\n\tSwaps: 0\n\tFile system inputs: 176\n\tFile system outputs: 0\n\tSocket messages sent: 0\n\tSocket messages received: 0\n\tSignals delivered: 0\n\tPage size (bytes): 4096\n\tExit status: 0\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Used memory after tmpfs mount and file fill: 670 MB\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{end:{exited:true  status:"exit status 0"}}
    sandbox_memory_integrity_test.go:70: Command [bash] completed successfully in sandbox ikyv65eq0ruywoz7e8sn6
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{start:{pid:1295}}
Executing command bash in sandbox i8oh7et9tcbjhu3nqgeua (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{data:{stdout:"80ed92bf2b514260f7e2cd7df4dd2a3a7f2455d8a05cf822b49f0b2d1ae6a7a4\n"}}
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{end:{exited:true  status:"exit status 0"}}
    sandbox_memory_integrity_test.go:80: Command [bash] completed successfully in sandbox ikyv65eq0ruywoz7e8sn6
Executing command bash in sandbox i8oh7et9tcbjhu3nqgeua (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{start:{pid:1298}}
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
Executing command bash in sandbox ikyv65eq0ruywoz7e8sn6 (user: root)
    sandbox_memory_integrity_test.go:110: 
        	Error Trace:	.../tests/orchestrator/sandbox_memory_integrity_test.go:81
        	            				.../hostedtoolcache/go/1.26.3.../src/runtime/asm_amd64.s:1771
        	Error:      	Received unexpected error:
        	            	failed to execute command bash in sandbox ikyv65eq0ruywoz7e8sn6: unavailable: HTTP status 502 Bad Gateway
    sandbox_memory_integrity_test.go:110: 
        	Error Trace:	.../tests/orchestrator/sandbox_memory_integrity_test.go:78
        	            				.../tests/orchestrator/sandbox_memory_integrity_test.go:110
        	Error:      	Condition never satisfied
        	Test:       	TestSandboxMemoryIntegrity/tmpfs_hash
--- FAIL: TestSandboxMemoryIntegrity/tmpfs_hash (186.71s)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — clean fix that propagates ClusterID into the snapshot envs row, following the same nil-as-LocalClusterID idiom already used in register_build.go.

Extended reasoning...

Overview

This PR fixes snapshot creation for sandboxes running on non-default (non-local) clusters by populating the envs.cluster_id column on the new envs rows inserted by UpsertSnapshot and CreateSnapshotTemplateEnv. The change touches two Go callsites in packages/api/internal/orchestrator and the two corresponding sqlc-generated query files plus their source .sql files.

Security risks

None. The change only routes an additional cluster identifier (already trusted, derived from the sandbox record) into a new column on the envs table. The column is a nullable FK to clusters(id), and the Go code maps LocalClusterID (uuid.Nil) to a Go nil pointer / SQL NULL, which is the same convention used elsewhere in the codebase (register_build.go:163-166).

Level of scrutiny

Low. This is a small, mechanical data-propagation fix following an established pattern. The SQL parameter renumbering in both generated files was tedious but correct: every $N after position 2 shifts by +1 in both queries, and the Go struct/QueryRow argument order matches the new placeholder order. The migration 20250624001048_cluster_for_templates.sql confirms envs.cluster_id is nullable, so existing local-cluster behavior (NULL cluster_id) is preserved.

Other factors

The bug hunting system reported no findings. The new code mirrors an existing pattern that's covered by other tests (create_instance_test.go, routing_test.go). No callers/contracts changed — only an additional optional field is set on insert.

@sitole sitole merged commit 28eeb72 into main Jun 8, 2026
55 checks passed
@sitole sitole deleted the fix/sandbox-snapshots-support-for-byoc branch June 8, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants