Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions go/cmd/compass-runner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ type podmanPreflighter interface {
VerifyUsernsRemapSupport(ctx context.Context) error
}

// appleContainerPreflighter is the apple-container backend's static
// host-capability probe: the `container` CLI is present and meets the version
// floor this backend's command contract relies on.
type appleContainerPreflighter interface {
VerifyAppleContainerSupport(ctx context.Context) error
}

// canaryBooter is the microVM backend's dynamic host-capability probe: it really
// boots a throwaway VM through the backend's own verbs, proving the whole boot
// chain. Kept a DISTINCT single-method interface from microVMPreflighter (not a
Expand All @@ -204,17 +211,19 @@ type canaryBooter interface {

// verifyBackendPreflight runs the selected engine's static host-capability
// preflight. It dispatches on the engine's concrete type, first match wins,
// probing the microVM backend before podman; no engine satisfies both today, so
// dispatch is deterministic. An engine exposing neither probe is a fail-closed
// startup error naming the concrete type — never a silent skip, so a backend
// added without a preflight surfaces loudly at launch rather than running
// unchecked.
// probing the microVM backend before podman and apple-container; no engine
// satisfies two of them today, so dispatch is deterministic. An engine exposing
// no probe is a fail-closed startup error naming the concrete type — never a
// silent skip, so a backend added without a preflight surfaces loudly at launch
// rather than running unchecked.
func verifyBackendPreflight(ctx context.Context, engine runtime.WorkloadRuntime) error {
switch e := engine.(type) {
case microVMPreflighter:
return runMicroVMPreflight(ctx, e, engine)
case podmanPreflighter:
return e.VerifyUsernsRemapSupport(ctx)
case appleContainerPreflighter:
return e.VerifyAppleContainerSupport(ctx)
default:
return fmt.Errorf("backend %T exposes no startup preflight probe", engine)
}
Expand Down Expand Up @@ -293,8 +302,8 @@ type backendFlags struct {
func registerBackendFlags() backendFlags {
return backendFlags{
backend: flag.String("backend", "",
"Container runtime backend: 'podman' (default, transitional) or "+
"'microvm'. Defaults to $COMPASS_RUNTIME_BACKEND."),
"Container runtime backend: 'podman' (default, transitional), "+
"'microvm' or 'apple-container'. Defaults to $COMPASS_RUNTIME_BACKEND."),
vmm: flag.String("microvm-vmm", "",
"Path to the microVM monitor binary (microvm backend). Defaults to $COMPASS_MICROVM_VMM."),
virtiofsd: flag.String("microvm-virtiofsd", "",
Expand Down Expand Up @@ -371,6 +380,10 @@ func (f backendFlags) backendConfig() (runtime.BackendConfig, error) {
DefaultMemoryMB: memoryMB,
QuotaRequired: quotaRequired,
},
// Zero, explicitly: the runner exposes no program/timeout flags for
// this backend, and NewAppleContainerCLI reads a zero field as "use the
// default" (`container` on PATH, the shared command timeout).
AppleContainer: runtime.AppleContainerConfig{},
}, nil
}

Expand Down
48 changes: 45 additions & 3 deletions go/cmd/compass-runner/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import (
// podman branch also depends on it NOT satisfying microVMPreflighter; that
// precedence is exercised by TestVerifyBackendPreflight, not asserted here.
var (
_ microVMPreflighter = (*runtime.MicroVMRuntime)(nil)
_ podmanPreflighter = (*runtime.PodmanCLI)(nil)
_ canaryBooter = (*runtime.MicroVMRuntime)(nil)
_ microVMPreflighter = (*runtime.MicroVMRuntime)(nil)
_ podmanPreflighter = (*runtime.PodmanCLI)(nil)
_ canaryBooter = (*runtime.MicroVMRuntime)(nil)
_ appleContainerPreflighter = (*runtime.AppleContainerCLI)(nil)
)

// parseMount is the operator surface for --mount: a malformed value must be
Expand Down Expand Up @@ -155,6 +156,18 @@ func (e bothProbesEngine) BootCanary(context.Context) (runtime.CanaryReport, err
return runtime.CanaryReport{}, nil
}

// appleOnlyEngine exposes only the apple-container probe.
type appleOnlyEngine struct {
runtime.WorkloadRuntime
called *bool
err error
}

func (e appleOnlyEngine) VerifyAppleContainerSupport(context.Context) error {
*e.called = true
return e.err
}

// verifyBackendPreflight dispatches on the selected engine's concrete type
// (RIG-2496): microVM first, then podman, first match wins; the matched probe
// runs and its error is returned verbatim; an engine exposing neither probe is a
Expand Down Expand Up @@ -270,3 +283,32 @@ func TestVerifyBackendPreflight(t *testing.T) {
}
})
}

// The apple-container arm of the same dispatch, kept a separate function rather
// than two more subtests on TestVerifyBackendPreflight: that one is already at
// the gocognit ceiling, and these two cases stand on their own.
func TestVerifyBackendPreflightAppleContainer(t *testing.T) {
t.Run("apple-container probe dispatched, not the fail-closed default", func(t *testing.T) {
sentinel := errors.New("preflight refused")
called := false
err := verifyBackendPreflight(context.Background(), appleOnlyEngine{called: &called, err: sentinel})
if !errors.Is(err, sentinel) {
t.Errorf("verifyBackendPreflight = %v, want the apple probe's sentinel error", err)
}
if !called {
t.Error("apple-container probe was not called")
}
})

t.Run("selected apple-container backend reaches its probe", func(t *testing.T) {
engine, err := runtime.SelectBackend(runtime.BackendConfig{Backend: "apple-container"})
if err != nil {
t.Fatalf("SelectBackend(apple-container) = %v, want the apple engine", err)
}
// Do NOT invoke the real probe (it shells out to `container
// --version`); only assert the selected engine routes to its branch.
if _, ok := engine.(appleContainerPreflighter); !ok {
t.Errorf("apple-container backend %T does not satisfy appleContainerPreflighter", engine)
}
})
}
Loading
Loading