diff --git a/docs/cluster.md b/docs/cluster.md index 7fa0e90..67f4795 100644 --- a/docs/cluster.md +++ b/docs/cluster.md @@ -123,7 +123,7 @@ curl -s -H "Authorization: Bearer $TOKEN" http://node-a:7777/v1/info | jq . ```json { "pools": [ - {"key": {"template": "base:24.04", "net": "none", "size": "small", "engine": "ch"}, + {"key": {"template": "base:24.04", "net": "none", "size": "small"}, "warm": 4, "refilling": 0, "target": 4, "golden": true} ], "claimed": 2, diff --git a/docs/deploy.md b/docs/deploy.md index 7df8ebc..2a5d873 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -110,7 +110,7 @@ sandboxd reads one JSON file (`-config`, default | `archive_after_seconds` | 0 (off) | tier below hibernation: a hibernated claim idle this long is checkpointed to the store and its local VM dropped, freeing the node entirely; the next call restores it transparently (a checkpoint restore's latency). Requires `idle_hibernate_seconds > 0` and must exceed it. Node-wide for unpooled keys; per-pool overrides for that pool | | `archive_delete_after_seconds` | 0 (keep) | purge an archived claim's store checkpoint this long after it was archived, reclaiming storage; the claim is then gone for good. Same node-wide/per-pool split | | `mesh` | unset | join a cluster ([Clusters](cluster.md)); unset = single node | -| `pools[]` | — | warm pools, keyed by `(template, net, size, engine)`. `warm` defaults to 4; `net` is `none` or `egress`; `size` is a tier, below; `engine` is `ch` (default) or `fc` to cold-boot that key under Firecracker. Retune online without a restart via [`PUT /v1/pools`](sandboxd-api.md#put-v1pools) — omitted pools drain. This is the **first-boot seed**: once a node takes a `PUT /v1/pools`, the applied set persists to `/pools.json` and overrides this section on every later boot (a startup log notes it); delete `pools.json` to return to config-owned pools. Egress stays config-owned either way. See [state ownership](cluster.md#state-ownership) | +| `pools[]` | — | warm pools, keyed by `(template, net, size)`. `warm` defaults to 4; `net` is `none` or `egress`; `size` is a tier, below. Retune online without a restart via [`PUT /v1/pools`](sandboxd-api.md#put-v1pools) — omitted pools drain. This is the **first-boot seed**: once a node takes a `PUT /v1/pools`, the applied set persists to `/pools.json` and overrides this section on every later boot (a startup log notes it); delete `pools.json` to return to config-owned pools. Egress stays config-owned either way. See [state ownership](cluster.md#state-ownership) | Size tiers (free-form CPU/memory is deliberately not accepted — it would fragment the warm pools): @@ -157,8 +157,7 @@ mounts the device before finalizing the claim: `mode: "ro"` (the default) attaches and mounts read-only; `mode: "rw"` requires the catalog entry's `writable: true` and attaches and mounts read-write. Setup failure destroys the VM without quiescing — the claim was never handed out, so no workload -write happened — and a popped warm VM is refilled normally. Firecracker -volume claims are rejected. +write happened — and a popped warm VM is refilled normally. A multi-volume claim brings every volume up concurrently: each volume's own marker→attach→mount order is preserved, but cocoon serializes the hypervisor diff --git a/docs/sandboxd-api.md b/docs/sandboxd-api.md index e40fe87..d254342 100644 --- a/docs/sandboxd-api.md +++ b/docs/sandboxd-api.md @@ -32,10 +32,8 @@ Auth: `Authorization: Bearer ` (when configured). "require_promoted": false} ``` -- `net` defaults to `none`, `size` to `small`, `engine` to `ch`. The pool key - is `(template, net, size, engine)`; `engine: "fc"` cold-boots that key under - Firecracker, and clones inherit the hypervisor pinned in the golden's - snapshot +- `net` defaults to `none`, `size` to `small`; the pool key is + `(template, net, size)` - `ttl_seconds` 0 means the server default (5 minutes); capped at 24h. The owning node reaps the sandbox after the TTL even if the client vanishes - `claim_ref` is an optional opaque caller reference echoed by the scoped @@ -48,8 +46,7 @@ Auth: `Authorization: Bearer ` (when configured). defaults to `/volumes/`; a custom value must be absolute and clean, outside the guest OS tree, unique, and non-nesting within the request. `mode` is `"ro"` (default, omitted) or `"rw"`; `"rw"` requires the catalog - entry's `writable: true` (see [deploy](deploy.md#dataset-volumes)). Volumes - require Cloud Hypervisor + entry's `writable: true` (see [deploy](deploy.md#dataset-volumes)) - `volumes_attach_only` (default `false`) attaches every requested volume without mounting it, handing the whole mount contract to the workload. It requires at least one volume, and rejects any entry carrying a `mount` — @@ -175,7 +172,7 @@ Errors: 400 unknown template axis, invalid/duplicate volumes, `volumes_attach_only` with no volumes or with an entry carrying a `mount`, `mode: "rw"` against a non-writable entry, or a volume that is unknown or forbidden (the -latter two are deliberately indistinguishable), Firecracker with volumes, or +latter two are deliberately indistinguishable), or bad body; 401 bad api token; 409 egress requested on a node without an egress attachment, a writable name already claimed in a conflicting mode (volume busy — a live writer excludes every other claim for that name, live readers @@ -280,7 +277,7 @@ node (name-based calls route via gossip); a shared checkpoint store makes every node resolve it. Under exactly this key: ```json -{"key": {"template": "myproj:v1", "net": "none", "size": "small", "engine": "ch"}, +{"key": {"template": "myproj:v1", "net": "none", "size": "small"}, "content_digest": "sha256:…"} ``` @@ -522,7 +519,7 @@ Auth: root only (tenant tokens get 403). Node pools, claim count, and mesh peers: ```json -{"pools": [{"key": {"template": "base:24.04", "net": "none", "size": "small", "engine": "ch"}, +{"pools": [{"key": {"template": "base:24.04", "net": "none", "size": "small"}, "warm": 4, "refilling": 0, "target": 4, "golden": true}], "claimed": 2, "hibernated": 1, diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 3e174bd..3a96f6b 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -27,7 +27,7 @@ import ( sandbox "github.com/cocoonstack/sandbox/sdk/go" ) -var testKey = types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} +var testKey = types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall} func TestEndToEnd(t *testing.T) { stack := startStack(t, "node-token", config.PoolSpec{PoolKey: testKey, Warm: 1}) @@ -446,9 +446,6 @@ func TestClaimRefRoundTrip(t *testing.T) { if list[i].ClaimRef != "ns/workload" { t.Errorf("claim_ref %q, want ns/workload", list[i].ClaimRef) } - if list[i].Key.Engine != sandbox.EngineCH { - t.Errorf("engine %q, want the defaulted ch — the SDK key must carry the axis", list[i].Key.Engine) - } } // TestAttachOnlyVolumeEndToEnd drives one attach-only writable claim through diff --git a/sandboxd/engine/engine.go b/sandboxd/engine/engine.go index 43bfccc..06c3e9b 100644 --- a/sandboxd/engine/engine.go +++ b/sandboxd/engine/engine.go @@ -358,11 +358,6 @@ func (e *Engine) restoreArgs() []string { func (e *Engine) runColdArgs(name string, key types.PoolKey) []string { spec, _ := key.Size.Spec() args := []string{"vm", "run", argName, name, argOutput, formatJSON, "--cpu", strconv.Itoa(spec.CPU), "--memory", spec.Memory, e.directIOArg()} - if key.Engine == types.EngineFC { - // Firecracker is a per-pool cold-boot choice; clones inherit the - // hypervisor from the golden's pinned snapshot, so only RunCold flags it. - args = append(args, "--fc") - } args = append(args, e.netArgs(name, key, true)...) return append(args, key.Template) } diff --git a/sandboxd/pool/claim.go b/sandboxd/pool/claim.go index f34f25e..cd42f0c 100644 --- a/sandboxd/pool/claim.go +++ b/sandboxd/pool/claim.go @@ -30,7 +30,7 @@ func (m *Manager) ClaimWarm(ctx context.Context, key types.PoolKey, ttl time.Dur if err := m.validate(key); err != nil { return nil, err } - volumeSpecs, err := m.resolveVolumes(ctx, key, tenant, volumes) + volumeSpecs, err := m.resolveVolumes(ctx, tenant, volumes) if err != nil { return nil, err } @@ -506,7 +506,7 @@ func (m *Manager) claimProvision(ctx context.Context, key types.PoolKey, ttl tim if err := m.validate(key); err != nil { return nil, err } - volumeSpecs, err := m.resolveVolumes(ctx, key, tenant, volumes) + volumeSpecs, err := m.resolveVolumes(ctx, tenant, volumes) if err != nil { return nil, err } diff --git a/sandboxd/pool/egress_test.go b/sandboxd/pool/egress_test.go index 52a9bef..8b54780 100644 --- a/sandboxd/pool/egress_test.go +++ b/sandboxd/pool/egress_test.go @@ -21,7 +21,7 @@ import ( ) var ( - egKey = types.PoolKey{Template: "rt:24.04", Net: types.NetEgress, Size: types.SizeSmall, Engine: types.EngineCH} + egKey = types.PoolKey{Template: "rt:24.04", Net: types.NetEgress, Size: types.SizeSmall} egPolicy = &egress.Policy{Allow: []egress.Rule{{Host: "example.com", Secret: "gh"}}} ) diff --git a/sandboxd/pool/intercept_test.go b/sandboxd/pool/intercept_test.go index 5bd01e8..d210e1f 100644 --- a/sandboxd/pool/intercept_test.go +++ b/sandboxd/pool/intercept_test.go @@ -11,7 +11,7 @@ import ( "github.com/cocoonstack/sandbox/sandboxd/types" ) -var interceptKey = types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} +var interceptKey = types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall} func TestGoldenBuildInstallsCAForInterceptPool(t *testing.T) { eng := newFakeEngine() diff --git a/sandboxd/pool/pool_test.go b/sandboxd/pool/pool_test.go index e1ce3cd..0ac304e 100644 --- a/sandboxd/pool/pool_test.go +++ b/sandboxd/pool/pool_test.go @@ -21,7 +21,7 @@ import ( "github.com/cocoonstack/sandbox/sandboxd/types" ) -var testKey = types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} +var testKey = types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall} func TestClaimWarmHitTransfersOwnership(t *testing.T) { eng := newFakeEngine() diff --git a/sandboxd/pool/poolstore_test.go b/sandboxd/pool/poolstore_test.go index c545b2f..c0e6a10 100644 --- a/sandboxd/pool/poolstore_test.go +++ b/sandboxd/pool/poolstore_test.go @@ -12,8 +12,8 @@ import ( ) var ( - seedKey = types.PoolKey{Template: "seed:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} - apiKey = types.PoolKey{Template: "api:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} + seedKey = types.PoolKey{Template: "seed:24.04", Net: types.NetNone, Size: types.SizeSmall} + apiKey = types.PoolKey{Template: "api:24.04", Net: types.NetNone, Size: types.SizeSmall} ) func TestPersistedPoolsSurviveRestart(t *testing.T) { diff --git a/sandboxd/pool/promote_test.go b/sandboxd/pool/promote_test.go index 66798ee..bab58ef 100644 --- a/sandboxd/pool/promote_test.go +++ b/sandboxd/pool/promote_test.go @@ -26,7 +26,7 @@ func TestPromoteThenClaimClonesFromTemplate(t *testing.T) { if len(eng.snapSaves) != 1 || !slices.Contains(eng.snapRemoves, eng.snapSaves[0]) { t.Errorf("snapSaves=%v snapRemoves=%v, want one transient snapshot dropped", eng.snapSaves, eng.snapRemoves) } - key := types.PoolKey{Template: "tpl:x", Net: parent.Key.Net, Size: parent.Key.Size, Engine: parent.Key.Engine} + key := types.PoolKey{Template: "tpl:x", Net: parent.Key.Net, Size: parent.Key.Size} if gotKey != key { t.Errorf("returned key %+v, want %+v (the parent's axes)", gotKey, key) } @@ -146,12 +146,12 @@ func TestDeleteTemplate(t *testing.T) { if _, _, err := m.Promote(t.Context(), parent.ID, Cred{Token: parent.Token}, "tpl:del", ""); err != nil { t.Fatalf("Promote: %v", err) } - key := types.PoolKey{Template: "tpl:del", Net: testKey.Net, Size: testKey.Size, Engine: testKey.Engine} + key := types.PoolKey{Template: "tpl:del", Net: testKey.Net, Size: testKey.Size} if err := m.DeleteTemplate(t.Context(), testKey, ""); !errors.Is(err, ErrPooledTemplate) { t.Errorf("pooled delete: %v, want ErrPooledTemplate", err) } - if err := m.DeleteTemplate(t.Context(), types.PoolKey{Template: "nope", Net: testKey.Net, Size: testKey.Size, Engine: testKey.Engine}, ""); !errors.Is(err, ErrUnknownTemplate) { + if err := m.DeleteTemplate(t.Context(), types.PoolKey{Template: "nope", Net: testKey.Net, Size: testKey.Size}, ""); !errors.Is(err, ErrUnknownTemplate) { t.Errorf("unknown delete: %v, want ErrUnknownTemplate", err) } if err := m.DeleteTemplate(t.Context(), key, ""); err != nil { @@ -276,7 +276,7 @@ func TestPromoteFailsClosedOnMetaError(t *testing.T) { if _, _, err := m.Promote(t.Context(), a.ID, Cred{Token: a.Token}, "shared:v1", "acme"); err != nil { t.Fatalf("promote: %v", err) } - key := types.PoolKey{Template: "shared:v1", Net: testKey.Net, Size: testKey.Size, Engine: testKey.Engine} + key := types.PoolKey{Template: "shared:v1", Net: testKey.Net, Size: testKey.Size} meta := filepath.Join(m.dataDir, "checkpoints", store.TemplateID(key.Hash()), store.MetaFile) if err := os.Chmod(meta, 0o000); err != nil { t.Fatalf("chmod: %v", err) diff --git a/sandboxd/pool/template.go b/sandboxd/pool/template.go index 255ff4a..5762230 100644 --- a/sandboxd/pool/template.go +++ b/sandboxd/pool/template.go @@ -42,7 +42,7 @@ func (m *Manager) Promote(ctx context.Context, id string, cred Cred, template, t if !sb.Key.Capturable() { return types.PoolKey{}, "", ErrNoEgressFork } - key := types.PoolKey{Template: template, Net: sb.Key.Net, Size: sb.Key.Size, Engine: sb.Key.Engine} + key := types.PoolKey{Template: template, Net: sb.Key.Net, Size: sb.Key.Size} if m.pooledHash(key.Hash()) { // A configured pool owns this key — promoting over it would // silently change what refills produce. diff --git a/sandboxd/pool/volume.go b/sandboxd/pool/volume.go index 42f1616..3401326 100644 --- a/sandboxd/pool/volume.go +++ b/sandboxd/pool/volume.go @@ -135,7 +135,7 @@ func (m *Manager) VolumePlacement(key types.PoolKey, tenant string, names []stri return local, nil } -func (m *Manager) resolveVolumes(ctx context.Context, key types.PoolKey, tenant string, requested []types.Volume) ([]resolvedVolume, error) { +func (m *Manager) resolveVolumes(ctx context.Context, tenant string, requested []types.Volume) ([]resolvedVolume, error) { if len(requested) == 0 { return nil, nil } @@ -145,9 +145,6 @@ func (m *Manager) resolveVolumes(ctx context.Context, key types.PoolKey, tenant if err != nil { return nil, fmt.Errorf("%w: %v", ErrBadVolume, err) } - if key.Engine != types.EngineCH { - return nil, fmt.Errorf("%w: volumes require engine ch", ErrBadVolume) - } resolved := make([]resolvedVolume, 0, len(applied)) for _, volume := range applied { entry, ok := m.volumes[volume.Name] diff --git a/sandboxd/pool/volume_rw_test.go b/sandboxd/pool/volume_rw_test.go index 9bd8ea1..2e20d82 100644 --- a/sandboxd/pool/volume_rw_test.go +++ b/sandboxd/pool/volume_rw_test.go @@ -147,7 +147,7 @@ func TestConfirmVolumesCleanCatchesMarkerAfterAdmission(t *testing.T) { // The reader resolves a clean image; a writable claim then fails between // that resolve and admission, leaving its marker but no hold behind. - resolved, err := m.resolveVolumes(t.Context(), testKey, "", readOnly) + resolved, err := m.resolveVolumes(t.Context(), "", readOnly) if err != nil { t.Fatalf("resolveVolumes: %v", err) } @@ -166,7 +166,7 @@ func TestConfirmVolumesCleanCatchesMarkerAfterAdmission(t *testing.T) { } m.unreserveVolumes(appliedVolumes(resolved)) - writable, err := m.resolveVolumes(t.Context(), testKey, "", []types.Volume{{Name: "scratch", Mode: types.VolumeModeRW}}) + writable, err := m.resolveVolumes(t.Context(), "", []types.Volume{{Name: "scratch", Mode: types.VolumeModeRW}}) if err != nil { t.Fatalf("resolveVolumes writable: %v", err) } diff --git a/sandboxd/pool/volume_test.go b/sandboxd/pool/volume_test.go index 6b6b89b..617cc1f 100644 --- a/sandboxd/pool/volume_test.go +++ b/sandboxd/pool/volume_test.go @@ -268,7 +268,6 @@ func TestClaimProvisionRejectsInvalidVolumesBeforeProvision(t *testing.T) { {"too many", testKey, nil, tooMany}, {"unknown", testKey, []config.VolumeSpec{{Name: "data", Path: path}}, []types.Volume{{Name: "other"}}}, {"invalid mount", testKey, []config.VolumeSpec{{Name: "data", Path: path}}, []types.Volume{{Name: "data", Mount: "relative"}}}, - {"firecracker", types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineFC}, []config.VolumeSpec{{Name: "data", Path: path}}, []types.Volume{{Name: "data"}}}, } { t.Run(tt.name, func(t *testing.T) { eng := newFakeEngine() @@ -472,7 +471,7 @@ func TestVolumePlacementChecksAccessAndLocalAvailability(t *testing.T) { if local, err := m.VolumePlacement(testKey, "", []string{"peer-only"}); err != nil || local { t.Errorf("root peer-only placement=(%v, %v), want false, nil", local, err) } - badKey := types.PoolKey{Template: "rt:24.04", Net: "lan", Size: types.SizeSmall, Engine: types.EngineCH} + badKey := types.PoolKey{Template: "rt:24.04", Net: "lan", Size: types.SizeSmall} if _, err := m.VolumePlacement(badKey, "", []string{"local"}); !errors.Is(err, ErrBadKey) { t.Errorf("invalid key error=%v, want ErrBadKey", err) } diff --git a/sandboxd/server/metrics.go b/sandboxd/server/metrics.go index f3d69e1..84597d9 100644 --- a/sandboxd/server/metrics.go +++ b/sandboxd/server/metrics.go @@ -47,11 +47,11 @@ func (s *Server) handleMetrics(w http.ResponseWriter, _ *http.Request) { metric("pool_warm", "gauge", "claim-ready VMs per pool") for _, p := range pools { - _, _ = fmt.Fprintf(w, "sandboxd_pool_warm{template=%q,net=%q,size=%q,engine=%q} %d\n", p.Key.Template, p.Key.Net, p.Key.Size, p.Key.Engine, p.Warm) + _, _ = fmt.Fprintf(w, "sandboxd_pool_warm{template=%q,net=%q,size=%q} %d\n", p.Key.Template, p.Key.Net, p.Key.Size, p.Warm) } metric("pool_target", "gauge", "warm watermark per pool") for _, p := range pools { - _, _ = fmt.Fprintf(w, "sandboxd_pool_target{template=%q,net=%q,size=%q,engine=%q} %d\n", p.Key.Template, p.Key.Net, p.Key.Size, p.Key.Engine, p.Target) + _, _ = fmt.Fprintf(w, "sandboxd_pool_target{template=%q,net=%q,size=%q} %d\n", p.Key.Template, p.Key.Net, p.Key.Size, p.Target) } if s.placer != nil { diff --git a/sandboxd/server/server.go b/sandboxd/server/server.go index 5d46153..b24f54e 100644 --- a/sandboxd/server/server.go +++ b/sandboxd/server/server.go @@ -270,9 +270,6 @@ func (s *Server) handleClaim(w http.ResponseWriter, r *http.Request) { func (s *Server) handleVolumeClaim(w http.ResponseWriter, r *http.Request, req types.ClaimRequest, key types.PoolKey, hash, tenant string) { volumes, err := types.ValidateVolumes(req.Volumes, req.VolumesAttachOnly) - if err == nil && key.Engine != types.EngineCH { - err = errors.New("volumes require engine ch") - } if err != nil { writeErr(w, http.StatusBadRequest, fmt.Errorf("%w: %v", pool.ErrBadVolume, err).Error()) return diff --git a/sandboxd/server/server_test.go b/sandboxd/server/server_test.go index af24364..093aa95 100644 --- a/sandboxd/server/server_test.go +++ b/sandboxd/server/server_test.go @@ -56,7 +56,7 @@ func TestClaimHappyPath(t *testing.T) { if cr.TemplateDigest != "sha256:claim-digest" { t.Errorf("template digest %q, want sha256:claim-digest", cr.TemplateDigest) } - want := types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} + want := types.PoolKey{Template: "rt:24.04", Net: types.NetNone, Size: types.SizeSmall} if gotKey != want { t.Errorf("key %+v, want defaults %+v", gotKey, want) } @@ -738,7 +738,7 @@ func TestPromoteAndDeleteTemplateFlow(t *testing.T) { if got := del("Bearer sekret", "template=tpl:x&net=none&size=small"); got != http.StatusNoContent { t.Errorf("delete status %d, want 204", got) } - want := types.PoolKey{Template: "tpl:x", Net: types.NetNone, Size: types.SizeSmall, Engine: types.EngineCH} + want := types.PoolKey{Template: "tpl:x", Net: types.NetNone, Size: types.SizeSmall} if gotKey != want { t.Errorf("delete key %+v, want %+v (claim defaults applied)", gotKey, want) } @@ -1394,7 +1394,6 @@ func TestVolumeClaimRejectsShapeBeforePlacement(t *testing.T) { `{"template":"rt:24.04","volumes":["data"]}`, `{"template":"rt:24.04","volumes":[{"name":"data"},{"name":"data"}]}`, `{"template":"rt:24.04","volumes":[{"name":"cocoon-data"}]}`, - `{"template":"rt:24.04","engine":"fc","volumes":[{"name":"data"}]}`, `{"template":"rt:24.04","volumes":[{"name":"data","mount":"relative"}]}`, `{"template":"rt:24.04","volumes":[{"name":"data","mount":"/datasets"},{"name":"other","mount":"/datasets/nested"}]}`, `{"template":"rt:24.04","volumes":[{"name":"a"},{"name":"b"},{"name":"c"},{"name":"d"},{"name":"e"},{"name":"f"},{"name":"g"},{"name":"h"},{"name":"i"}]}`, diff --git a/sandboxd/types/api.go b/sandboxd/types/api.go index 49b578f..880ee13 100644 --- a/sandboxd/types/api.go +++ b/sandboxd/types/api.go @@ -22,7 +22,6 @@ type ClaimRequest struct { Template string `json:"template"` Net NetShape `json:"net,omitempty"` Size Size `json:"size,omitempty"` - Engine Engine `json:"engine,omitempty"` Volumes []Volume `json:"volumes,omitempty"` // VolumesAttachOnly attaches every requested volume without mounting it: // the workload finds the device by its serial and owns the mount contract. @@ -40,7 +39,7 @@ type ClaimRequest struct { // Key resolves the requested pool key with the wire defaults filled. func (r ClaimRequest) Key() PoolKey { - return PoolKey{Template: r.Template, Net: r.Net, Size: r.Size, Engine: r.Engine}.Defaulted() + return PoolKey{Template: r.Template, Net: r.Net, Size: r.Size}.Defaulted() } // ClaimResponse is the wire reply of POST /v1/claim. A successful claim diff --git a/sandboxd/types/types.go b/sandboxd/types/types.go index 8dad034..dde7992 100644 --- a/sandboxd/types/types.go +++ b/sandboxd/types/types.go @@ -29,9 +29,6 @@ const ( RestoreOnDemand RestoreMode = "ondemand" RestoreMmap RestoreMode = "mmap" - EngineCH Engine = "ch" - EngineFC Engine = "fc" - MaxClaimVolumes = 8 // Also the guest `mount -o` option literals (engine.MountVolume): renaming @@ -82,21 +79,6 @@ func (m RestoreMode) Validate() error { } } -// Engine selects the hypervisor backend cocoon boots a pool's VMs on: Cloud -// Hypervisor (default) or Firecracker. It is a pool axis so a CH pool and an -// FC pool with the same template/net/size stay distinct goldens. -type Engine string - -// Validate accepts the empty default (resolved to EngineCH) plus known engines. -func (e Engine) Validate() error { - switch e { - case "", EngineCH, EngineFC: - return nil - default: - return fmt.Errorf("unknown engine %q", e) - } -} - // Size is a T-shirt resource tier. type Size string @@ -120,7 +102,6 @@ type PoolKey struct { Template string `json:"template"` Net NetShape `json:"net"` Size Size `json:"size"` - Engine Engine `json:"engine,omitempty"` } // Capturable reports whether state capture (fork, checkpoint, promote) is @@ -135,7 +116,6 @@ func (k PoolKey) Capturable() bool { func (k PoolKey) Defaulted() PoolKey { k.Net = cmp.Or(k.Net, NetNone) k.Size = cmp.Or(k.Size, SizeSmall) - k.Engine = cmp.Or(k.Engine, EngineCH) return k } @@ -144,7 +124,7 @@ func (k PoolKey) Defaulted() PoolKey { // names, so a targeted collision with a configured pool's hash must stay a // second-preimage problem, never a brute-forceable one. func (k PoolKey) Hash() string { - sum := sha256.Sum256([]byte(k.Template + "|" + string(k.Net) + "|" + string(k.Size) + "|" + string(k.Engine))) + sum := sha256.Sum256([]byte(k.Template + "|" + string(k.Net) + "|" + string(k.Size))) return hex.EncodeToString(sum[:16]) } @@ -161,9 +141,6 @@ func (k PoolKey) Validate() error { if _, ok := k.Size.Spec(); !ok { return fmt.Errorf("unknown size %q", k.Size) } - if err := k.Engine.Validate(); err != nil { - return err - } return nil } diff --git a/sdk/go/info.go b/sdk/go/info.go index 4b7107f..42c3c23 100644 --- a/sdk/go/info.go +++ b/sdk/go/info.go @@ -25,7 +25,6 @@ type PoolKey struct { Template string `json:"template"` Net NetShape `json:"net"` Size Size `json:"size"` - Engine Engine `json:"engine,omitempty"` } // PoolStatus reports one warm pool on a node. diff --git a/sdk/go/options.go b/sdk/go/options.go index a213ab0..dde7eb6 100644 --- a/sdk/go/options.go +++ b/sdk/go/options.go @@ -11,10 +11,6 @@ const ( // NetEgress attaches the node's bridge or CNI network. NetEgress NetShape = "egress" - // EngineCH is the default hypervisor; EngineFC cold-boots under Firecracker. - EngineCH Engine = "ch" - EngineFC Engine = "fc" - Small Size = "small" Medium Size = "medium" Large Size = "large" @@ -31,9 +27,6 @@ type NetShape string // node's warm pools. type Size string -// Engine is the pool key's hypervisor axis. -type Engine string - // Volume requests one catalog entry at an optional guest mount path and mode. type Volume struct { Name string `json:"name"` diff --git a/sdk/go/pools.go b/sdk/go/pools.go index 98b2f7c..4f61767 100644 --- a/sdk/go/pools.go +++ b/sdk/go/pools.go @@ -14,7 +14,6 @@ type PoolSpec struct { Template string `json:"template"` Net NetShape `json:"net,omitempty"` Size Size `json:"size,omitempty"` - Engine Engine `json:"engine,omitempty"` Warm int `json:"warm"` WarmMax int `json:"warm_max,omitempty"` IdleHibernateSeconds int `json:"idle_hibernate_seconds,omitempty"`