Skip to content

ci: nbd provisioning groundwork for Blacksmith (KVM jobs blocked on kernel >= 6.7) - #3332

Closed
tomassrnka wants to merge 4 commits into
mainfrom
ci/blacksmith-kernel-modules
Closed

ci: nbd provisioning groundwork for Blacksmith (KVM jobs blocked on kernel >= 6.7)#3332
tomassrnka wants to merge 4 commits into
mainfrom
ci/blacksmith-kernel-modules

Conversation

@tomassrnka

@tomassrnka tomassrnka commented Jul 22, 2026

Copy link
Copy Markdown
Member

Goal

Run the remaining GitHub-larger-runner jobs — orchestrator unit shards (x64 + arm64) and the integration suite — on Blacksmith, without losing any test coverage. #3326 found the blocker: Blacksmith's custom kernel ships no nbd module.

What the kernel probes established (runs on this PR)

Blacksmith x64 (2404) Blacksmith arm64
nbd driver built in (CONFIG_BLK_DEV_NBD=y), 16 devices at boot absent — but a module built from kernel.org source for the running kernel (using /proc/config.gz) insmods cleanly: 36s cold, cacheable per kernel release
/dev/kvm present absent (same as GitHub arm runners — the KVM smoketest skips on both)
tun / uffd / hugetlbfs / swap / cgroup2 all present all present
module signing / modversions disabled disabled
netlink nbd device creation works (~60 devices/s) — escape hatch if 16 devices ever becomes tight n/a (module loads with nbds_max=256)

vsock is confirmed not needed: PutGuestVsock has zero callers; guest communication is tap networking + MMDS.

Changes

  • .github/actions/ensure-nbd: one action, four strategies in order — driver already present → plain modprobelinux-modules-extra via apt (GitHub arm) → build nbd.ko from source + insmod (Blacksmith arm, cached). Workflows stay fully functional on GitHub-hosted runners.
  • orchestrator unit shards → blacksmith-8vcpu-ubuntu-2404 / blacksmith-4vcpu-ubuntu-2404-arm
  • integration tests → blacksmith-32vcpu-ubuntu-2404
  • init-client.sh skips its modprobe nbd when the driver is built in

Merge checklist (coverage, not just green)

  • x64 orchestrator shard: TestSmokeAllFCVersions runs and passes (it skips silently without /dev/kvm — a green check alone is not proof)
  • No new environment-gated skips vs. the infra-tests baseline (requires root, /dev/kvm not available, cgroup v2, hugepage-mmap skips…)
  • Integration service logs free of no free slots (NBD pool clamps to the 16 built-in devices on x64; -parallel=4 should stay well under)
  • Timings comparable to infra-tests baseline (orchestrator ~112s, integration 10–18 min)
  • Remove blacksmith-kernel-probe.yml before merge

Known limits / fallbacks

  • x64 integration concurrency is capped at 16 simultaneous sandbox devices. If NoFreeSlotsError ever shows up, options: netlink pre-creation + a small pool change to size from the actual device inventory, or move integration back.
  • If Blacksmith bumps their kernel, the arm cache key (uname -r) rolls over automatically and one job pays the 36s rebuild.

🤖 Generated with Claude Code

Diagnostic-only workflow: dumps kernel config and device availability on
Blacksmith x64/arm64 runners and attempts to build the nbd module from
matching kernel.org source and insmod it. Establishes whether the
orchestrator unit shard and integration tests can be provisioned to run
there. Temporary; removed before any of this merges.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@cla-bot cla-bot Bot added the cla-signed label Jul 22, 2026
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
CI-only changes that compile and insmod kernel modules on some runners; mis-provisioning could flake orchestrator tests or mask runner/kernel gaps until Blacksmith upgrades.

Overview
This PR makes CI hosts reliably expose the NBD block driver the orchestrator expects, so more jobs can run on Blacksmith without losing coverage. Orchestrator PR test setup now calls a composite action that picks among built-in driver, modprobe, linux-modules-extra, or building and caching nbd.ko from kernel source (for arm64 images with no module). Integration host init skips creating swap when swap is already active and skips modprobe when NBD is already present. Most x64 and arm64 unit-test matrix shards move to Blacksmith runners; orchestrator shards and the integration suite stay on the existing infra runners because Blacksmith’s 6.6 kernel lacks UFFD_FEATURE_WP_ASYNC (required from 6.7). PR path filters treat changes to the new action as test-input changes.

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

Comment thread .github/workflows/blacksmith-kernel-probe.yml Outdated
… on arm64

v1 verdicts: x64 kernel has nbd BUILTIN (CONFIG_BLK_DEV_NBD=y, /dev/nbd0
exists, /dev/kvm + tun + uffd all present) so no module is needed - only
more device nodes, which nbd's netlink interface creates on demand. arm64
has no nbd at all, so it needs the source-built module; v1's modpost
failed on undefined core symbols (no Module.symvers), fixed with
KBUILD_MODPOST_WARN=1. Also add swapfile smoke test (init-client.sh
swapon) and /proc/cmdline + device-count inventory.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/workflows/blacksmith-kernel-probe.yml Outdated
Probe results (see blacksmith-kernel-probe.yml runs): Blacksmith x64
kernels ship nbd BUILT IN (16 devices) plus /dev/kvm, tun, uffd,
hugepages, swap and cgroup2 - everything the orchestrator needs; the
device pool clamps to nbds_max so 16 devices just caps concurrency
(unit tests use ~8, integration parallelism is -parallel=4). arm64
kernels ship no nbd at all, but a module built from matching kernel.org
source with the running kernel's /proc/config.gz insmods cleanly (36s
cold, cached per kernel release thereafter).

- new ensure-nbd composite action: driver-present / modprobe /
  linux-modules-extra / build-from-source, in that order, so the same
  workflows keep working on GitHub-hosted runners
- orchestrator unit shards: infra-tests -> blacksmith-8vcpu,
  infra-runner-arm -> blacksmith-4vcpu-arm
- integration tests: infra-tests -> blacksmith-32vcpu
- init-client.sh: skip modprobe when the driver is built in

Verification criteria: TestSmokeAllFCVersions must RUN (not skip) on
x64, no new environment-gated skips, no NoFreeSlotsError in integration
service logs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
echo "strategy=none" >> "$GITHUB_OUTPUT"
elif sudo modprobe nbd nbds_max='${{ inputs.nbds-max }}' 2>/dev/null; then
echo "strategy=modprobe" >> "$GITHUB_OUTPUT"
elif apt-get -s install "linux-modules-extra-$(uname -r)" >/dev/null 2>&1; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Apt strategy probe needs sudo

Medium Severity

The apt provisioning branch is chosen with apt-get -s install, which typically cannot read the dpkg lock without sudo, so the check fails even when linux-modules-extra-$(uname -r) is available and the action falls through to the kernel build path instead of installing the package.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c6e2820. Configure here.

@blacksmith-sh

This comment has been minimized.

Full-suite run on Blacksmith found the real blocker: their 6.6.141
kernel predates UFFD_FEATURE_WP_ASYNC (Linux >= 6.7), which the uffd
memory backend and FC dirty-page tracking hard-require. 208 uffd test
failures (UFFDIO_API EINVAL) and FC snapshot loads failing with 'Failed
to UFFD object' on both arches. Not provisionable from CI - needs a
Blacksmith kernel upgrade.

Keep the groundwork (no behavior change on GitHub runners):
- ensure-nbd action replaces inline modprobe/modules-extra setup in the
  unit-test workflows; it also handles builtin-nbd and no-module kernels
- init-client.sh tolerates built-in nbd and pre-existing active swap
- runner labels reverted to infra-tests / infra-runner-arm; comments
  document the exact kernel blocker and the revisit condition

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@tomassrnka

Copy link
Copy Markdown
Member Author

Final verdict: hard blocker is the kernel VERSION, not nbd/KVM

The full suite ran on Blacksmith (run 29915860237). Everything we set out to fix was fixed — nbd provisioned on both arches, /dev/kvm present and the FC smoketest actually ran and booted VMs, 901 orchestrator unit tests passed on x64. What failed is unfixable from CI:

UFFDIO_API ioctl failed: invalid argument            (208 occurrences, both arches)
Load snapshot error: ... Error creating guest memory from uffd: Failed to UFFD object: System error

The uffd memory backend and our Firecracker dirty-page tracking hard-require UFFD_FEATURE_WP_ASYNC, which was added in Linux 6.7 (fd.go defines bit 15 explicitly). Blacksmith VMs run 6.6.141 — the feature does not exist there, at any config setting. Integration also tripped over the image's pre-existing active /swapfile (fixed here) before it would have hit the same uffd wall.

What this PR now is (mergeable, no behavior change on GitHub runners)

  • ensure-nbd action: driver-present → modprobe → linux-modules-extra → build-from-source; replaces the inline nbd setup in both unit workflows and keeps them portable across runner kernels
  • init-client.sh tolerates built-in nbd and pre-existing active swap
  • Runner labels stay on infra-tests / infra-runner-arm, with comments documenting the exact blocker and revisit condition

The ask for Blacksmith

Upgrade guest kernels to ≥ 6.7 (6.12 LTS ideal). Everything else is already proven working on their runners: KVM boots Firecracker, built-in nbd + netlink device creation, tun/hugepages/cgroup2/swap. With a 6.7+ kernel, flipping the three runner labels back is the entire remaining migration — worth ~80% of our paid larger-runner minutes.

🤖 Generated with Claude Code

@tomassrnka tomassrnka changed the title ci: provision Blacksmith runners for KVM/nbd test jobs ci: nbd provisioning groundwork for Blacksmith (KVM jobs blocked on kernel >= 6.7) Jul 22, 2026

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3b2bb7f. Configure here.

mkdir -p /tmp/nbd-ko
cp drivers/block/nbd.ko /tmp/nbd-ko/
fi
sudo insmod /tmp/nbd-ko/nbd.ko nbds_max='${{ inputs.nbds-max }}' || {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale nbd.ko skips rebuild

Medium Severity

On the build strategy, a cache miss only rebuilds when /tmp/nbd-ko/nbd.ko is missing. After the runner kernel changes, an older .ko left on persistent /tmp skips the build and insmod uses the wrong module, causing failures or repeated failed jobs until the file is removed manually.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3b2bb7f. Configure here.

@tomassrnka

Copy link
Copy Markdown
Member Author

Closing: blocked on Blacksmith shipping a kernel >= 6.7 (UFFD_FEATURE_WP_ASYNC). Everything needed to retry lives in this PR's history: the kernel probe workflow, the ensure-nbd action, and the init-client.sh tolerance fixes.

@tomassrnka tomassrnka closed this Jul 22, 2026
@tomassrnka
tomassrnka deleted the ci/blacksmith-kernel-modules branch July 22, 2026 12:30
@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
3470 1 3469 7
View the top 3 failed test(s) by shortest run time
github.com/e2b-dev/infra/tests/integration/internal/tests/envd::TestListDir/depth_2_lists_first_level_of_subdirectories_(in_this_case_the_root_directory)
Stack Traces | 0.01s run time
=== RUN   TestListDir/depth_2_lists_first_level_of_subdirectories_(in_this_case_the_root_directory)
=== PAUSE TestListDir/depth_2_lists_first_level_of_subdirectories_(in_this_case_the_root_directory)
=== CONT  TestListDir/depth_2_lists_first_level_of_subdirectories_(in_this_case_the_root_directory)
    filesystem_test.go:96: 
        	Error Trace:	.../tests/envd/filesystem_test.go:96
        	Error:      	Received unexpected error:
        	            	unavailable: 502 Bad Gateway
        	Test:       	TestListDir/depth_2_lists_first_level_of_subdirectories_(in_this_case_the_root_directory)
--- FAIL: TestListDir/depth_2_lists_first_level_of_subdirectories_(in_this_case_the_root_directory) (0.01s)
github.com/e2b-dev/infra/tests/integration/internal/tests/envd::TestListDir/depth_0_lists_only_root_directory
Stack Traces | 0.02s run time
=== RUN   TestListDir/depth_0_lists_only_root_directory
=== PAUSE TestListDir/depth_0_lists_only_root_directory
=== CONT  TestListDir/depth_0_lists_only_root_directory
    filesystem_test.go:96: 
        	Error Trace:	.../tests/envd/filesystem_test.go:96
        	Error:      	Received unexpected error:
        	            	unavailable: 502 Bad Gateway
        	Test:       	TestListDir/depth_0_lists_only_root_directory
--- FAIL: TestListDir/depth_0_lists_only_root_directory (0.02s)
github.com/e2b-dev/infra/tests/integration/internal/tests/envd::TestListDir/depth_1_lists_root_directory
Stack Traces | 0.02s run time
=== RUN   TestListDir/depth_1_lists_root_directory
=== PAUSE TestListDir/depth_1_lists_root_directory
=== CONT  TestListDir/depth_1_lists_root_directory
    filesystem_test.go:96: 
        	Error Trace:	.../tests/envd/filesystem_test.go:96
        	Error:      	Received unexpected error:
        	            	unavailable: 502 Bad Gateway
        	Test:       	TestListDir/depth_1_lists_root_directory
--- FAIL: TestListDir/depth_1_lists_root_directory (0.02s)
github.com/e2b-dev/infra/tests/integration/internal/tests/envd::TestListDir
Stack Traces | 0.76s run time
=== RUN   TestListDir
=== PAUSE TestListDir
=== CONT  TestListDir
--- FAIL: TestListDir (0.76s)
Executing command python in sandbox igsuyguikqxbe3iklivht
github.com/e2b-dev/infra/packages/orchestrator/pkg/sandbox/block::TestDedupedMemfdCache_MemfdHeldUntilSwap
Stack Traces | 6.73s run time
=== RUN   TestDedupedMemfdCache_MemfdHeldUntilSwap
=== PAUSE TestDedupedMemfdCache_MemfdHeldUntilSwap
=== CONT  TestDedupedMemfdCache_MemfdHeldUntilSwap
    memfd_test.go:373: 
        	Error Trace:	.../sandbox/block/memfd_test.go:373
        	Error:      	Condition never satisfied
        	Test:       	TestDedupedMemfdCache_MemfdHeldUntilSwap
--- FAIL: TestDedupedMemfdCache_MemfdHeldUntilSwap (6.73s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/sandboxes::TestSandboxRapidSnapshotForkChain
Stack Traces | 15.9s run time
=== RUN   TestSandboxRapidSnapshotForkChain
=== PAUSE TestSandboxRapidSnapshotForkChain
=== CONT  TestSandboxRapidSnapshotForkChain
    sandbox_rapid_pause_resume_test.go:43: Sandbox creation failed status=500 body={"code":500,"message":"Failed to place sandbox"}
    sandbox_rapid_pause_resume_test.go:43: Sandbox creation={Body:[123 34 99 111 100 101 34 58 53 48 48 44 34 109 101 115 115 97 103 101 34 58 34 70 97 105 108 101 100 32 116 111 32 112 108 97 99 101 32 115 97 110 100 98 111 120 34 125] HTTPResponse:0x258566c9e240 JSON201:<nil> JSON400:<nil> JSON401:<nil> JSON500:0x258566f05758}
    sandbox_rapid_pause_resume_test.go:43: 
        	Error Trace:	.../internal/utils/sandbox.go:173
        	            				.../api/sandboxes/sandbox_rapid_pause_resume_test.go:43
        	Error:      	Not equal: 
        	            	expected: 201
        	            	actual  : 500
        	Test:       	TestSandboxRapidSnapshotForkChain
--- FAIL: TestSandboxRapidSnapshotForkChain (15.86s)
View the full list of 1 ❄️ flaky test(s)
github.com/e2b-dev/infra/tests/integration/internal/tests/envd::TestListDir/depth_3_lists_all_directories_and_files

Flake rate in main: 30.77% (Passed 9 times, Failed 4 times)

Stack Traces | 0.01s run time
=== RUN   TestListDir/depth_3_lists_all_directories_and_files
=== PAUSE TestListDir/depth_3_lists_all_directories_and_files
=== CONT  TestListDir/depth_3_lists_all_directories_and_files
    filesystem_test.go:96: 
        	Error Trace:	.../tests/envd/filesystem_test.go:96
        	Error:      	Received unexpected error:
        	            	unavailable: 502 Bad Gateway
        	Test:       	TestListDir/depth_3_lists_all_directories_and_files
--- FAIL: TestListDir/depth_3_lists_all_directories_and_files (0.01s)

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

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.

1 participant