234 lines
8.5 KiB
Go
Executable File
234 lines
8.5 KiB
Go
Executable File
// Package runtime provides a unified abstraction over container runtimes.
|
|
//
|
|
// Sorcery-Go can deploy Essences into different execution environments
|
|
// (called "Sanctums"). This package defines the Runtime interface that
|
|
// decouples the Warding, Coven, and Reanimation logic from any specific
|
|
// container technology.
|
|
//
|
|
// Supported runtimes:
|
|
// - LXC: Traditional system containers (lxc-tools CLI)
|
|
// - Podman: OCI containers (podman CLI / REST API)
|
|
// - Firecracker: Lightweight microVMs (Firecracker VMM API via Unix socket)
|
|
// - BareMetal: Direct filesystem deployment (no container)
|
|
//
|
|
// The active runtime is selected at startup via SORCERY_GO_RUNTIME env var
|
|
// or the Runtime field in the Config struct. Each runtime adapter implements
|
|
// the Runtime interface, providing a consistent API for container lifecycle
|
|
// management, process execution, freeze/thaw, and status queries.
|
|
package runtime
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Type identifies the container runtime backend.
|
|
type Type string
|
|
|
|
const (
|
|
// RuntimeLXC uses the LXC system container tools (lxc-create, lxc-start, etc.)
|
|
RuntimeLXC Type = "lxc"
|
|
// RuntimePodman uses the Podman OCI container engine.
|
|
RuntimePodman Type = "podman"
|
|
// RuntimeFirecracker uses Firecracker microVMs.
|
|
RuntimeFirecracker Type = "firecracker"
|
|
// RuntimeBareMetal deploys directly to the host filesystem (no container).
|
|
RuntimeBareMetal Type = "baremetal"
|
|
)
|
|
|
|
// SanctumStatus describes the current state of a container/sanctum.
|
|
type SanctumStatus string
|
|
|
|
const (
|
|
StatusRunning SanctumStatus = "running"
|
|
StatusStopped SanctumStatus = "stopped"
|
|
StatusFrozen SanctumStatus = "frozen"
|
|
StatusCreating SanctumStatus = "creating"
|
|
StatusDestroyed SanctumStatus = "destroyed"
|
|
StatusUnknown SanctumStatus = "unknown"
|
|
)
|
|
|
|
// SanctumInfo provides runtime-specific information about a sanctum.
|
|
type SanctumInfo struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Runtime Type `json:"runtime"`
|
|
Status SanctumStatus `json:"status"`
|
|
Arch string `json:"arch"`
|
|
IP string `json:"ip,omitempty"`
|
|
PID uint32 `json:"pid,omitempty"`
|
|
Cgroup string `json:"cgroup,omitempty"`
|
|
Created time.Time `json:"created"`
|
|
RootFS string `json:"rootfs,omitempty"`
|
|
Metadata map[string]string `json:"metadata,omitempty"`
|
|
}
|
|
|
|
// CreateOpts holds the parameters for creating a new sanctum.
|
|
type CreateOpts struct {
|
|
// Name is the human-readable container name.
|
|
Name string
|
|
|
|
// Image is the base image or template (LXC template, OCI image, rootfs path).
|
|
Image string
|
|
|
|
// Arch is the target architecture (x86_64, aarch64).
|
|
Arch string
|
|
|
|
// RootFS is the path to the root filesystem (for baremetal or custom rootfs).
|
|
RootFS string
|
|
|
|
// NetworkConfig specifies the network attachment.
|
|
NetworkConfig *NetworkConfig
|
|
|
|
// BindMounts are host paths to bind-mount into the container.
|
|
BindMounts []BindMount
|
|
|
|
// EnvVars are environment variables to set inside the container.
|
|
EnvVars map[string]string
|
|
|
|
// Caps is the set of Linux capabilities to retain (empty = drop all).
|
|
Caps []string
|
|
|
|
// MemoryMB is the memory limit in megabytes (0 = unlimited).
|
|
MemoryMB uint64
|
|
|
|
// VCPUs is the number of virtual CPUs (for Firecracker).
|
|
VCPUs uint32
|
|
|
|
// KernelPath is the host kernel image path (for Firecracker).
|
|
KernelPath string
|
|
|
|
// RootDrivePath is the root block device path (for Firecracker).
|
|
RootDrivePath string
|
|
|
|
// ExtraConfig passes runtime-specific configuration as key-value pairs.
|
|
ExtraConfig map[string]string
|
|
}
|
|
|
|
// NetworkConfig specifies network attachment for a sanctum.
|
|
type NetworkConfig struct {
|
|
// Type is the network mode (bridge, none, host).
|
|
Type string // "bridge", "none", "host"
|
|
|
|
// Bridge is the host bridge interface name (e.g., "br0").
|
|
Bridge string
|
|
|
|
// MACAddress is the desired MAC address (empty = auto-generate).
|
|
MACAddress string
|
|
|
|
// IP is the desired IP address (empty = DHCP/auto).
|
|
IP string
|
|
}
|
|
|
|
// BindMount represents a host-to-container bind mount.
|
|
type BindMount struct {
|
|
// HostPath is the path on the host.
|
|
HostPath string
|
|
// ContainerPath is the path inside the container.
|
|
ContainerPath string
|
|
// ReadOnly makes the mount read-only.
|
|
ReadOnly bool
|
|
}
|
|
|
|
// ExecResult captures the output of a command executed inside a sanctum.
|
|
type ExecResult struct {
|
|
ExitCode int
|
|
Stdout []byte
|
|
Stderr []byte
|
|
}
|
|
|
|
// Runtime is the interface that all container runtime backends must implement.
|
|
//
|
|
// It provides a unified API for the full lifecycle of a Sanctum:
|
|
// create, start, stop, freeze/thaw, exec, and destroy. The Warding uses
|
|
// this interface to manage containers without knowing the underlying runtime.
|
|
type Runtime interface {
|
|
// Type returns the runtime type identifier (lxc, podman, firecracker, baremetal).
|
|
Type() Type
|
|
|
|
// Name returns a human-readable name for this runtime instance.
|
|
Name() string
|
|
|
|
// Probe checks whether this runtime is available on the host.
|
|
// Returns nil if the runtime tools/API are accessible.
|
|
Probe() error
|
|
|
|
// Create provisions a new sanctum with the given options.
|
|
// Returns the sanctum ID on success.
|
|
Create(ctx context.Context, opts CreateOpts) (string, error)
|
|
|
|
// Start boots or starts a stopped sanctum.
|
|
Start(ctx context.Context, sanctumID string) error
|
|
|
|
// Stop gracefully stops a running sanctum.
|
|
Stop(ctx context.Context, sanctumID string) error
|
|
|
|
// Freeze suspends all processes in a running sanctum (cgroup freezer).
|
|
Freeze(ctx context.Context, sanctumID string) error
|
|
|
|
// Thaw resumes a frozen sanctum.
|
|
Thaw(ctx context.Context, sanctumID string) error
|
|
|
|
// Destroy removes a sanctum and all its resources.
|
|
Destroy(ctx context.Context, sanctumID string) error
|
|
|
|
// Exec runs a command inside a running sanctum and returns the output.
|
|
Exec(ctx context.Context, sanctumID string, command []string, stdin []byte) (*ExecResult, error)
|
|
|
|
// Status returns the current state and info about a sanctum.
|
|
Status(ctx context.Context, sanctumID string) (*SanctumInfo, error)
|
|
|
|
// List returns all sanctums managed by this runtime.
|
|
List(ctx context.Context) ([]*SanctumInfo, error)
|
|
|
|
// CgroupPath returns the cgroup v2 path for a sanctum.
|
|
// This is used by the eBPF enforcer to attach cgroup filters.
|
|
// Returns "" if the runtime does not use cgroups (e.g., Firecracker).
|
|
CgroupPath(sanctumID string) string
|
|
}
|
|
|
|
// Factory creates a Runtime instance for the given type.
|
|
// Returns an error if the runtime type is unknown or unavailable.
|
|
func Factory(rtType Type) (Runtime, error) {
|
|
switch rtType {
|
|
case RuntimeLXC:
|
|
r := NewLXCRuntime()
|
|
if err := r.Probe(); err != nil {
|
|
return nil, err
|
|
}
|
|
return r, nil
|
|
case RuntimePodman:
|
|
r := NewPodmanRuntime()
|
|
if err := r.Probe(); err != nil {
|
|
return nil, err
|
|
}
|
|
return r, nil
|
|
case RuntimeFirecracker:
|
|
r := NewFirecrackerRuntime()
|
|
if err := r.Probe(); err != nil {
|
|
return nil, err
|
|
}
|
|
return r, nil
|
|
case RuntimeBareMetal:
|
|
return NewBareMetalRuntime(), nil
|
|
default:
|
|
return nil, fmt.Errorf("runtime: unknown runtime type %q (supported: lxc, podman, firecracker, baremetal)", rtType)
|
|
}
|
|
}
|
|
|
|
// AutoDetect tries to find an available runtime on the host.
|
|
// It probes LXC first, then Podman, then Firecracker, and falls back
|
|
// to baremetal if none are found.
|
|
func AutoDetect() (Runtime, error) {
|
|
candidates := []Type{RuntimeLXC, RuntimePodman, RuntimeFirecracker, RuntimeBareMetal}
|
|
for _, t := range candidates {
|
|
r, err := Factory(t)
|
|
if err == nil {
|
|
return r, nil
|
|
}
|
|
}
|
|
return NewBareMetalRuntime(), nil
|
|
}
|
|
|