Skip to content

feat: add Firecracker hypervisor support#112

Merged
rgarcia merged 3 commits intomainfrom
feat/firecracker-hypervisor
Mar 2, 2026
Merged

feat: add Firecracker hypervisor support#112
rgarcia merged 3 commits intomainfrom
feat/firecracker-hypervisor

Conversation

@rgarcia
Copy link
Contributor

@rgarcia rgarcia commented Feb 27, 2026

Summary

  • Add Firecracker as a first-class Linux hypervisor with starter/client/vsock implementations, VM config mapping, and snapshot/restore support.
  • Embed Firecracker binaries in build/test workflows while supporting a runtime hypervisor.firecracker_binary_path override.
  • Wire Firecracker through hypervisor registration, instance creation config, OpenAPI surface, docs, and standby/restore shutdown hardening.
  • Fix Firecracker process startup to avoid request-context cancellation terminating newly created VMs.

Test plan

  • go test ./lib/hypervisor/firecracker
  • RUN_FIRECRACKER_INTEGRATION=1 go test ./lib/instances -run TestFirecrackerStandbyAndRestore -count=1
  • Local API e2e with workspace-local config (tmp/firecracker-e2e-config.yaml): image pull, create (hypervisor=firecracker), standby, restore, stop, delete
  • 10-run latency sample on local host: create->running p50/p95 = 257/391 ms; restore->running p50/p95 = 119/139 ms

Made with Cursor


Note

High Risk
Adds a new Linux hypervisor implementation and changes core instance lifecycle (start/standby/restore/stop), socket cleanup, and embedded-binary handling, which can impact VM stability and process management across platforms. Also updates API surface/config, so regressions could affect existing clients and deployments if enums/config defaults are mishandled.

Overview
Adds Firecracker as a first-class Linux hypervisor, including a new lib/hypervisor/firecracker implementation (process starter, HTTP-over-UDS client, vsock dialer) with snapshot/restore support and translation from hypervisor.VMConfig into Firecracker API models.

Introduces embedded Firecracker binaries (with make download-firecracker-binaries/ensure-firecracker-binaries) and a runtime override via new config hypervisor.firecracker_binary_path; wiring is added in providers and paths to extract/locate binaries under data_dir.

Updates instance orchestration to support Firecracker: registers the new hypervisor.TypeFirecracker, exposes it through openapi.yaml/generated lib/oapi, and threads per-instance network bandwidth limits into hypervisor.NetworkConfig so Firecracker can apply per-device rate limiters.

Hardens lifecycle cleanup around standby/stop by removing stale VMM/vsock sockets, force-killing unresponsive hypervisor processes during shutdown, and ensuring stopped instances don’t retain snapshot directories; adds Firecracker-focused integration tests and makes the OOM test more resilient with retry/skip behavior.

Written by Cursor Bugbot for commit edc7295. This will update automatically on new commits. Configure here.

@github-actions
Copy link

github-actions bot commented Feb 27, 2026

✱ Stainless preview builds

This PR will update the hypeman SDKs with the following commit message.

feat: add Firecracker hypervisor support
hypeman-openapi studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅

hypeman-typescript studio · code

generate ✅build ✅lint ⏳test ✅

npm install https://pkg.stainless.com/s/hypeman-typescript/cb6868a04419ca033fe96515928147ef88dde0dd/dist.tar.gz
hypeman-go studio · code

generate ✅build ⏳lint ❗test ❗

go get github.com/stainless-sdks/hypeman-go@251f4b953c665f32305f393196974c8cb4fe7ec3

⏳ These are partial results; builds are still running.


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-03-02 16:51:32 UTC

Copy link

@cursor cursor bot left a comment

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 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Process leak when socket wait times out
    • When socket startup times out, startProcess now kills and waits on the started Firecracker process before returning the error so no orphaned PID is left behind.
  • ✅ Fixed: Guaranteed 2-second delay for Firecracker shutdown
    • shutdownHypervisor now skips the initial graceful-exit wait when Shutdown returns ErrNotSupported and immediately force-kills the Firecracker PID.

Create PR

Or push these changes by commenting:

@cursor push b348216fba
Preview (b348216fba)
diff --git a/lib/hypervisor/firecracker/process.go b/lib/hypervisor/firecracker/process.go
--- a/lib/hypervisor/firecracker/process.go
+++ b/lib/hypervisor/firecracker/process.go
@@ -148,6 +148,10 @@
 	}
 
 	if err := waitForSocket(socketPath, socketWaitTimeout); err != nil {
+		if cmd.Process != nil {
+			_ = cmd.Process.Kill()
+			_ = cmd.Wait()
+		}
 		if data, readErr := os.ReadFile(vmmLogPath); readErr == nil && len(data) > 0 {
 			return 0, fmt.Errorf("%w; vmm.log: %s", err, string(data))
 		}

diff --git a/lib/instances/standby.go b/lib/instances/standby.go
--- a/lib/instances/standby.go
+++ b/lib/instances/standby.go
@@ -190,8 +190,7 @@
 
 	// Wait for process to exit
 	if inst.HypervisorPID != nil {
-		if !WaitForProcessExit(*inst.HypervisorPID, 2*time.Second) {
-			log.WarnContext(ctx, "hypervisor did not exit gracefully in time, force killing process", "instance_id", inst.Id, "pid", *inst.HypervisorPID)
+		forceKill := func() error {
 			if err := syscall.Kill(*inst.HypervisorPID, syscall.SIGKILL); err != nil && err != syscall.ESRCH {
 				return fmt.Errorf("force kill hypervisor pid %d: %w", *inst.HypervisorPID, err)
 			}
@@ -202,6 +201,19 @@
 					return fmt.Errorf("hypervisor pid %d did not exit after SIGKILL", *inst.HypervisorPID)
 				}
 			}
+			return nil
+		}
+
+		if shutdownErr == hypervisor.ErrNotSupported {
+			log.DebugContext(ctx, "hypervisor does not support graceful shutdown, force killing process", "instance_id", inst.Id, "pid", *inst.HypervisorPID)
+			if err := forceKill(); err != nil {
+				return err
+			}
+		} else if !WaitForProcessExit(*inst.HypervisorPID, 2*time.Second) {
+			log.WarnContext(ctx, "hypervisor did not exit gracefully in time, force killing process", "instance_id", inst.Id, "pid", *inst.HypervisorPID)
+			if err := forceKill(); err != nil {
+				return err
+			}
 		} else {
 			log.DebugContext(ctx, "hypervisor shutdown gracefully", "instance_id", inst.Id, "pid", *inst.HypervisorPID)
 		}

Copy link

@cursor cursor bot left a comment

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.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: DetachVolume returns HTTP 500 for client errors
    • Added a 409 response for detachVolume in openapi.yaml, regenerated lib/oapi/oapi.go, and updated DetachVolume to return DetachVolume409JSONResponse for invalid state/in-use/ambiguous client errors.

Create PR

Or push these changes by commenting:

@cursor push fc873343ba
Preview (fc873343ba)
diff --git a/cmd/api/api/instances.go b/cmd/api/api/instances.go
--- a/cmd/api/api/instances.go
+++ b/cmd/api/api/instances.go
@@ -757,7 +757,7 @@
 				Message: err.Error(),
 			}, nil
 		case errors.Is(err, instances.ErrInvalidState), errors.Is(err, volumes.ErrInUse), errors.Is(err, volumes.ErrAmbiguousName):
-			return oapi.DetachVolume500JSONResponse{
+			return oapi.DetachVolume409JSONResponse{
 				Code:    "invalid_state",
 				Message: err.Error(),
 			}, nil

diff --git a/lib/oapi/oapi.go b/lib/oapi/oapi.go
--- a/lib/oapi/oapi.go
+++ b/lib/oapi/oapi.go
@@ -4102,6 +4102,7 @@
 	HTTPResponse *http.Response
 	JSON200      *Instance
 	JSON404      *Error
+	JSON409      *Error
 	JSON500      *Error
 }
 
@@ -5989,6 +5990,13 @@
 		}
 		response.JSON404 = &dest
 
+	case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 409:
+		var dest Error
+		if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+			return nil, err
+		}
+		response.JSON409 = &dest
+
 	case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
 		var dest Error
 		if err := json.Unmarshal(bodyBytes, &dest); err != nil {
@@ -9284,6 +9292,15 @@
 	return json.NewEncoder(w).Encode(response)
 }
 
+type DetachVolume409JSONResponse Error
+
+func (response DetachVolume409JSONResponse) VisitDetachVolumeResponse(w http.ResponseWriter) error {
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(409)
+
+	return json.NewEncoder(w).Encode(response)
+}
+
 type DetachVolume500JSONResponse Error
 
 func (response DetachVolume500JSONResponse) VisitDetachVolumeResponse(w http.ResponseWriter) error {
@@ -10756,178 +10773,178 @@
 // Base64 encoded, gzipped, json marshaled Swagger object
 var swaggerSpec = []string{
 
-	"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",
+	"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",
-	"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",
-	"xqU6OhwcDoKPrz/+bwAAAP//OrJd9TvrAAA=",
+	"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",
+	"7WZcqqPDweEg+Pjm4/8GAAD///hcyO7d6wAA",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file

diff --git a/openapi.yaml b/openapi.yaml
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -1853,6 +1853,12 @@
             application/json:
               schema:
                 $ref: "#/components/schemas/Error"
+        409:
+          description: Conflict - instance not in correct state or volume in use
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
         500:
           description: Internal server error
           content:

Copy link

@cursor cursor bot left a comment

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.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Snapshot load sends unsupported network_overrides to Firecracker API
    • Removed network_overrides from the snapshot load request schema so restore payloads no longer include the unsupported field, and added a regression test asserting it is omitted.

Create PR

Or push these changes by commenting:

@cursor push abd0e6d07c
Preview (abd0e6d07c)
diff --git a/lib/hypervisor/firecracker/config.go b/lib/hypervisor/firecracker/config.go
--- a/lib/hypervisor/firecracker/config.go
+++ b/lib/hypervisor/firecracker/config.go
@@ -67,11 +67,10 @@
 }
 
 type snapshotLoadParams struct {
-	MemFilePath         string            `json:"mem_file_path,omitempty"`
-	SnapshotPath        string            `json:"snapshot_path"`
-	EnableDiffSnapshots bool              `json:"enable_diff_snapshots,omitempty"`
-	ResumeVM            bool              `json:"resume_vm,omitempty"`
-	NetworkOverrides    []networkOverride `json:"network_overrides,omitempty"`
+	MemFilePath         string `json:"mem_file_path,omitempty"`
+	SnapshotPath        string `json:"snapshot_path"`
+	EnableDiffSnapshots bool   `json:"enable_diff_snapshots,omitempty"`
+	ResumeVM            bool   `json:"resume_vm,omitempty"`
 }
 
 type networkOverride struct {
@@ -187,13 +186,12 @@
 	}
 }
 
-func toSnapshotLoadParams(snapshotDir string, networkOverrides []networkOverride) snapshotLoadParams {
+func toSnapshotLoadParams(snapshotDir string, _ []networkOverride) snapshotLoadParams {
 	return snapshotLoadParams{
 		MemFilePath:         snapshotMemoryPath(snapshotDir),
 		SnapshotPath:        snapshotStatePath(snapshotDir),
 		EnableDiffSnapshots: true,
 		ResumeVM:            false,
-		NetworkOverrides:    networkOverrides,
 	}
 }
 

diff --git a/lib/hypervisor/firecracker/config_test.go b/lib/hypervisor/firecracker/config_test.go
--- a/lib/hypervisor/firecracker/config_test.go
+++ b/lib/hypervisor/firecracker/config_test.go
@@ -1,6 +1,7 @@
 package firecracker
 
 import (
+	"encoding/json"
 	"testing"
 
 	"github.com/kernel/hypeman/lib/hypervisor"
@@ -71,5 +72,7 @@
 	assert.Equal(t, "/tmp/snapshot-latest/memory", load.MemFilePath)
 	assert.True(t, load.EnableDiffSnapshots)
 	assert.False(t, load.ResumeVM)
-	require.Len(t, load.NetworkOverrides, 1)
+	loadJSON, err := json.Marshal(load)
+	require.NoError(t, err)
+	assert.NotContains(t, string(loadJSON), "network_overrides")
 }

Introduce Firecracker as a first-class hypervisor with lifecycle hardening, snapshot and network integration coverage, and CI/test updates needed to keep end-to-end VM suites reliable.

Made-with: Cursor
@rgarcia rgarcia force-pushed the feat/firecracker-hypervisor branch from 62a391d to 6790336 Compare March 2, 2026 10:21
Document that network bandwidth limits are enforced host-side for all hypervisors and that Firecracker additionally applies interface rate limiters, and annotate the /serial fallback with its v1.14.0 introduction context.

Made-with: Cursor
@rgarcia rgarcia requested a review from sjmiller609 March 2, 2026 15:04
Copy link
Collaborator

@sjmiller609 sjmiller609 left a comment

Choose a reason for hiding this comment

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

Looks good!

Make TestOOMExitPropagation resilient to host-dependent OOM timing by retrying with higher pressure and skipping when OOM cannot be triggered reliably within bounded time, while preserving strict assertions when OOM is observed.

Made-with: Cursor
@rgarcia rgarcia merged commit f8f791b into main Mar 2, 2026
2 of 3 checks passed
@rgarcia rgarcia deleted the feat/firecracker-hypervisor branch March 2, 2026 16:40
Copy link

@cursor cursor bot left a comment

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 2 potential issues.

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

@echo "Binaries downloaded successfully"

# Firecracker version to embed
FIRECRACKER_VERSION := v1.14.2
Copy link

Choose a reason for hiding this comment

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

Non-existent Firecracker version v1.14.2 referenced

High Severity

FIRECRACKER_VERSION is set to v1.14.2, but this release does not exist on the Firecracker GitHub releases page (the latest is v1.14.1). The download-firecracker-binaries target will fail with a 404 when curl tries to fetch the tarball, breaking build-linux, dev-linux, test-linux, and release-prep.

Additional Locations (1)

Fix in Cursor Fix in Web

type drive struct {
DriveID string `json:"drive_id"`
IsRootDevice bool `json:"is_root_device"`
IsReadOnly bool `json:"is_read_only,omitempty"`
Copy link

Choose a reason for hiding this comment

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

Boolean omitempty silently drops required API field

Medium Severity

The IsReadOnly field on the drive struct uses omitempty, which causes Go's JSON encoder to omit is_read_only entirely when the value is false. Since Firecracker's API typically requires this field on drive PUT requests, non-read-only drives (like overlays) may be rejected or behave unexpectedly if the server changes its default handling. The sibling field IsRootDevice correctly omits the omitempty tag.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants