api

package
v0.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package api is the HTTP (REST) surface of the orchestrator. It wraps FleetManager and Environment operations behind a chi-based router, serves the harness, and is consumed by operations tooling. The shape of every request and response mirrors apps/orchestrator/api/openapi.yaml, which is the human-readable contract for this API.

Types in this file are hand-maintained and intentionally decoupled from the internal FleetManager/orchestrator types so that the wire contract can evolve independently of the in-process API. The conversion helpers in convert.go enforce that separation.

Index

Constants

View Source
const (
	// MaxLoginBodyBytes bounds POST /login. It is the only unauthenticated
	// body-carrying route, so it gets the tightest limit: the body is one
	// token string and nothing else.
	MaxLoginBodyBytes = 4 << 10 // 4 KiB

	// MaxJSONBodyBytes bounds ordinary authenticated JSON requests —
	// snapshot options, fork options, host registration, API key labels.
	// These are all a handful of short fields.
	MaxJSONBodyBytes = 64 << 10 // 64 KiB

	// MaxEnvironmentBodyBytes bounds POST /v1/environments, which carries an
	// inline manifest, a startup script, and a secrets map, and POST exec,
	// whose command can be a long shell line. This is the largest body the
	// API accepts.
	MaxEnvironmentBodyBytes = 1 << 20 // 1 MiB
)

Request body size limits, in bytes. Every JSON handler decodes through one of these so a single request can never make the orchestrator allocate an unbounded amount of memory.

The limits are generous relative to real payloads — they exist to bound the worst case, not to police field sizes, which the handlers validate separately. They apply to chunked bodies as well as declared Content-Length ones, because http.MaxBytesReader counts bytes actually read rather than trusting the header.

View Source
const (
	CodeNotFound        = "not_found"
	CodeConflict        = "conflict"
	CodeInvalidArgument = "invalid_argument"
	CodeUnavailable     = "unavailable"
	CodeInternal        = "internal"
	CodeUnauthorized    = "unauthorized"
	CodeUnimplemented   = "unimplemented"

	// CodePayloadTooLarge marks a request body that ran past the endpoint's
	// size limit. Distinct from CodeInvalidArgument because the body may be
	// perfectly valid JSON and simply too big, which a client can fix by
	// sending less rather than by sending something different.
	CodePayloadTooLarge = "payload_too_large"

	// CodeRouteNotFound distinguishes "this URL isn't a route this server
	// exposes" (wrong host, wrong port, not the orchestrator at all) from
	// CodeNotFound's "route exists, resource doesn't" (e.g. an unknown vm
	// or host id).
	CodeRouteNotFound = "route_not_found"
)

Standard error codes. The REST boundary uses these to give callers a stable vocabulary for programmatic handling.

View Source
const RequestIDHeader = "X-Request-ID"

RequestIDHeader is the canonical HTTP header used to carry a per-request correlation ID. Clients (typically the control-server) may set this on inbound requests to propagate an upstream ID; otherwise the middleware generates a fresh one.

View Source
const SessionCookieName = "fuse_session"

SessionCookieName is the name of the HttpOnly cookie that carries the bearer token for browser callers. A separate SPA POSTs the operator's token to /login, which sets this cookie; subsequent API requests are authenticated from it by BearerAuth via [tokenFromRequest]. The token never lives in JavaScript-readable storage.

Variables

This section is empty.

Functions

func BearerAuth

func BearerAuth(expectedToken string, keys APIKeyAuthenticator, onFailure AuthFailureFunc) func(http.Handler) http.Handler

BearerAuth returns a chi-compatible middleware that authenticates the caller as either the static master token or a live API key, and records the resulting Principal in the request context. Returns 401 with the standard Error envelope on mismatch.

The token is read from the Authorization header ("Bearer <token>") for CLI/server callers, or — when no usable header is present — from the SessionCookieName cookie for browser callers (a separate SPA stores the token in an HttpOnly cookie via POST /login rather than in JavaScript). The same token is checked against the master secret first (constant-time), then against the API key store.

keys may be nil to disable API-key auth (only the master token is accepted). If expectedToken is empty AND keys is nil, the middleware is a no-op pass-through (insecure/dev mode, matching fused's Insecure flag pattern); requests carry no Principal.

func CIDRAllowlist

func CIDRAllowlist(cidrs []string, onReject IPRejectFunc) (func(http.Handler) http.Handler, error)

CIDRAllowlist returns a middleware that rejects requests whose remote address is not within any of the given CIDR blocks. Returns 403 with the standard Error envelope on rejection.

If cidrs is empty, the middleware is a no-op pass-through (open access). CIDRs are parsed at construction time; an invalid CIDR returns an error so the server fails fast at startup rather than silently admitting traffic.

func MetricsMiddleware

func MetricsMiddleware(
	requestsTotal *prometheus.CounterVec,
	requestDuration *prometheus.HistogramVec,
	requestsInFlight prometheus.Gauge,
) func(http.Handler) http.Handler

MetricsMiddleware records RED (Rate, Errors, Duration) metrics for every HTTP request using the chi route pattern as the "route" label, keeping cardinality bounded regardless of path parameters.

func RequestID

func RequestID(ctx context.Context) string

RequestID returns the per-request ID from ctx, or "" if absent. Use this in handlers and downstream callbacks (auth/IP audit) to correlate log lines and audit events with a single request.

func RequestIDMiddleware

func RequestIDMiddleware(next http.Handler) http.Handler

RequestIDMiddleware reads X-Request-ID from the inbound request (validating it against [validRequestID]) and either trusts it or generates a fresh ID. It then:

  1. Sets the ID on the response via RequestIDHeader before any downstream handler can write the response body.
  2. Stores the ID in the request context under the typed key, so downstream code can fetch it with RequestID.

This middleware should be mounted as the outermost layer of the orchestrator router so every other middleware (CIDR, auth, metrics) and every handler observes the same ID. Always succeeds — never short-circuits the chain.

Types

type APIKey

type APIKey struct {
	ID         string     `json:"id"`
	Label      string     `json:"label,omitempty"`
	CreatedAt  time.Time  `json:"created_at"`
	LastUsedAt *time.Time `json:"last_used_at,omitempty"`
	RevokedAt  *time.Time `json:"revoked_at,omitempty"`
}

APIKey is the JSON shape of a key's metadata. The raw secret is never included here — it appears only once, in CreateAPIKeyResponse.

type APIKeyAuthenticator

type APIKeyAuthenticator interface {
	// Authenticate returns (keyID, true) for a live, non-revoked key, or
	// ("", false) if the token matches no key or the key is revoked.
	Authenticate(ctx context.Context, rawToken string) (string, bool)
}

APIKeyAuthenticator validates a presented bearer token against the set of issued API keys. It is implemented by the orchestrator's API key store. A nil APIKeyAuthenticator disables key auth (only the master token is accepted).

type APIKeyList

type APIKeyList struct {
	APIKeys []APIKey `json:"api_keys"`
}

APIKeyList is the response body for GET /v1/api-keys.

type APIKeyStore

type APIKeyStore interface {
	Authenticate(ctx context.Context, rawToken string) (string, bool)
	Create(ctx context.Context, label string, now time.Time) (apikeys.APIKeyRecord, string, error)
	List(ctx context.Context) ([]apikeys.APIKeyRecord, error)
	Revoke(ctx context.Context, id string, now time.Time) error
}

APIKeyStore is the subset of the orchestrator's API key store that the REST handlers depend on. It is an interface so handlers can be tested with a stub and so the api package does not couple to *sql.DB. It also satisfies APIKeyAuthenticator (via Authenticate), so the same value wires into BearerAuth.

type AuthFailureFunc

type AuthFailureFunc func(remoteAddr, method, path, requestID string)

AuthFailureFunc is invoked once for every rejected authentication attempt. It receives the per-request correlation ID (see RequestIDMiddleware) so audit events and log lines can be tied back to the originating request, even when the rejection happens before the handler runs.

The requestID is always non-empty when RequestIDMiddleware is mounted upstream of this middleware (the standard router order).

type CreateAPIKeyRequest

type CreateAPIKeyRequest struct {
	Label string `json:"label,omitempty"`
}

CreateAPIKeyRequest is the JSON body accepted by POST /v1/api-keys. label is an optional human memory aid ("ci", "partner-acme").

type CreateAPIKeyResponse

type CreateAPIKeyResponse struct {
	APIKey
	Key string `json:"key"`
}

CreateAPIKeyResponse is returned by POST /v1/api-keys. Key is the raw secret and is shown exactly once — it cannot be recovered afterward.

type CreateEnvironmentRequest

type CreateEnvironmentRequest struct {
	TaskID         string            `json:"task_id"`
	Spec           ResourceSpec      `json:"spec"`
	ManifestInline string            `json:"manifest_inline"`
	Secrets        map[string]string `json:"secrets,omitempty"`
	StartupScript  string            `json:"startup_script,omitempty"`
	GatewayURL     string            `json:"gateway_url,omitempty"`
	GatewayToken   string            `json:"gateway_token,omitempty"`
	Expose         []ExposeSpec      `json:"expose,omitempty"`

	// StartupScriptTimeoutSeconds bounds StartupScript. Zero uses the
	// orchestrator's default. A value above the orchestrator's configured
	// maximum is rejected with 400 rather than clamped, so a caller is never
	// left thinking it got a bound it did not get.
	StartupScriptTimeoutSeconds int64 `json:"startup_script_timeout_seconds,omitempty"`

	// SeedSnapshotID boots the environment from an existing snapshot artifact
	// (see `fuse build`) rather than from spec.image, which it is mutually
	// exclusive with. The artifact is host-local and there is no object
	// storage, so the environment is pinned to the snapshot's host and the
	// request fails if that host cannot take it, rather than silently booting
	// a base image somewhere else.
	SeedSnapshotID string `json:"seed_snapshot_id,omitempty"`
}

CreateEnvironmentRequest is the JSON body accepted by POST /v1/environments.

ManifestInline is optional raw manifest JSON, base64-encoded. When omitted, the orchestrator uses a minimal internal manifest.

type CreateSnapshotRequest

type CreateSnapshotRequest struct {
	Comment          string            `json:"comment,omitempty"`
	Mode             string            `json:"mode,omitempty"`
	RetentionSeconds int64             `json:"retention_seconds,omitempty"`
	Metadata         map[string]string `json:"metadata,omitempty"`
	ExportRef        string            `json:"export_ref,omitempty"`
	ExportStatus     string            `json:"export_status,omitempty"`
}

CreateSnapshotRequest is the optional body for POST /v1/environments/{vm}/snapshots.

type Endpoint added in v0.2.0

type Endpoint struct {
	As   string `json:"as,omitempty"`
	URL  string `json:"url"`
	Port int    `json:"port"`
}

Endpoint is a published network endpoint for an environment.

type Environment

type Environment struct {
	ID        string       `json:"id"`
	State     string       `json:"state"`
	TaskID    string       `json:"task_id"`
	HostID    string       `json:"host_id,omitempty"`
	URL       string       `json:"url"`
	Spec      ResourceSpec `json:"spec"`
	CreatedAt time.Time    `json:"created_at"`
	UpdatedAt time.Time    `json:"updated_at"`
	Error     string       `json:"error,omitempty"`
	Endpoints []Endpoint   `json:"endpoints,omitempty"`
}

Environment is the JSON shape returned for a single VM.

type EnvironmentList

type EnvironmentList struct {
	Environments []Environment `json:"environments"`
}

EnvironmentList is the response body for GET /v1/environments.

type Error

type Error struct {
	Error ErrorBody `json:"error"`
}

Error is the JSON envelope returned for every non-2xx response. It intentionally wraps a single inner Error object so clients have one place to look for machine-readable failure metadata.

type ErrorBody

type ErrorBody struct {
	Code    string            `json:"code"`
	Message string            `json:"message"`
	Details map[string]string `json:"details,omitempty"`
}

ErrorBody is the inner payload of an Error envelope.

type ExecEnvironmentRequest added in v0.4.0

type ExecEnvironmentRequest struct {
	// Cmd is the argv to run in the guest, e.g. ["ls", "-l", "/var/log"].
	// Argv needs no quoting rules and cannot be turned into an injection by
	// interpolating a value, so it is the default.
	Cmd []string `json:"cmd,omitempty"`

	// Shell runs the string under `sh -lc`. It is the explicit opt-in for
	// what argv cannot express: pipelines, redirects, and globs.
	Shell string `json:"shell,omitempty"`

	// TimeoutMS bounds the command inside the guest. Zero takes the server
	// default; anything above the server ceiling is clamped to it.
	TimeoutMS int `json:"timeout_ms,omitempty"`
}

ExecEnvironmentRequest is the JSON body accepted by POST /v1/environments/{vmId}?action=exec.

Exactly one of cmd or shell must be set.

type ExecEnvironmentResponse added in v0.4.0

type ExecEnvironmentResponse struct {
	ExitCode int    `json:"exit_code"`
	Stdout   string `json:"stdout"`
	Stderr   string `json:"stderr"`
}

ExecEnvironmentResponse is the outcome of a guest command.

A non-zero exit_code arrives with HTTP 200: the command ran and failed, which is a successful answer to the question that was asked. Stdout and stderr are separate, and are plain strings rather than base64 because exec output is overwhelmingly text and every caller would otherwise pay a decoding tax for the rare binary case.

type ExposeSpec added in v0.2.0

type ExposeSpec struct {
	Port int    `json:"port"`
	As   string `json:"as,omitempty"`
}

ExposeSpec requests that a guest port be published as a reachable endpoint.

type ForkEnvironmentRequest added in v0.2.0

type ForkEnvironmentRequest struct {
	ReuseSnapshotID string `json:"reuse_snapshot_id,omitempty"`
	Comment         string `json:"comment,omitempty"`
}

ForkEnvironmentRequest is the optional body for POST /v1/environments/{vmId}?action=fork.

type GPUDevice added in v0.7.0

type GPUDevice struct {
	UUID          string `json:"uuid,omitempty"`
	Model         string `json:"model,omitempty"`
	PCIBusID      string `json:"pci_bus_id,omitempty"`
	MemoryMB      int    `json:"memory_mb,omitempty"`
	DriverVersion string `json:"driver_version,omitempty"`
	CUDAVersion   string `json:"cuda_version,omitempty"`
	ComputeCap    string `json:"compute_cap,omitempty"`
	MIGCapable    bool   `json:"mig_capable,omitempty"`
	MIGMode       string `json:"mig_mode,omitempty"`
	IOMMUGroup    string `json:"iommu_group,omitempty"`
}

GPUDevice is the wire shape of a single probed GPU. It mirrors orchestrator.GPUDevice; every field is best-effort and omitted when the host agent could not determine it.

type Handler

type Handler struct {
	// Fleet is the FleetManager instance the handlers proxy to.
	// In production this is *orchestrator.FleetManager. Tests may
	// pass any implementation compatible with the Go method set.
	Fleet *orchestrator.FleetManager

	// Resolver turns inline manifest payloads into raw bytes.
	// Defaults to InlineResolver if left nil.
	Resolver Resolver

	// NewProvider constructs a Provider for a host URL. Required for
	// host registration (POST /v1/hosts). Nil means host registration
	// is disabled and returns 501.
	NewProvider ProviderFactory

	// AuthToken is the static Bearer token required for all endpoints.
	// Empty means no auth (insecure/dev mode).
	AuthToken string

	// Version is the orchestrator build version, stamped into the Server
	// response header on every request (e.g. "fuse-orchestrator/0.4.0").
	// Empty renders as "fuse-orchestrator/dev".
	Version string

	// APIKeys is the store of revocable API keys. When non-nil it is
	// consulted by BearerAuth as a second accept path (after the master
	// token) and backs the /v1/api-keys management endpoints. Nil
	// disables API-key auth entirely.
	APIKeys APIKeyStore

	// AllowedCIDRs is a list of CIDR blocks from which requests are
	// accepted. Empty means open access.
	AllowedCIDRs []string

	// SecureCookies sets the Secure attribute on the session cookie
	// issued by POST /login. The server wires this to whether it is
	// serving TLS; it must be true in any cross-site browser deployment
	// (SameSite=None requires Secure) and should be true in production.
	SecureCookies bool

	// OnAuthFailure is called on every rejected auth attempt. The
	// server wires this to the FleetManager's event append for audit.
	// The requestID argument is the per-request correlation ID set
	// by [RequestIDMiddleware]; it is non-empty for any request that
	// passed through the standard [Handler.Router] chain.
	OnAuthFailure AuthFailureFunc

	// OnIPReject is called when a request is rejected by the CIDR
	// allowlist. Wired the same way as OnAuthFailure.
	OnIPReject IPRejectFunc

	// Metrics holds Prometheus counter/histogram vecs for HTTP RED
	// metrics. When non-nil, a recording middleware is installed on
	// the router. The three fields correspond to the outputs of
	// orchestrator.NewPrometheusMetrics.
	MetricsRequestsTotal    *prometheus.CounterVec
	MetricsRequestDuration  *prometheus.HistogramVec
	MetricsRequestsInFlight prometheus.Gauge
}

Handler is the HTTP dependency graph for the orchestrator REST API.

func (*Handler) Router

func (h *Handler) Router() (http.Handler, error)

Router returns an http.Handler serving the orchestrator REST API. It is safe to mount at any path prefix; routes are registered with absolute paths so `chi.Mount` and `http.StripPrefix` both work.

Middleware order (outermost first):

  1. Request-ID — assigns/propagates X-Request-ID so all downstream middleware and audit callbacks share a correlation ID.
  2. Metrics — records RED metrics for every request, including those rejected by CIDR or auth.
  3. CIDR allowlist — rejects before auth so blocked IPs can't even probe for valid tokens.
  4. Bearer auth — rejects unauthenticated requests.
  5. Route handlers.

type Healthcheck

type Healthcheck struct {
	// Fleet is the FleetManager whose readiness we report. A nil
	// pointer is treated as "not initialized" and fails readiness.
	Fleet *orchestrator.FleetManager

	// Store is the durable state backend (Postgres in prod, in-memory
	// in tests). Readiness performs a cheap ListVMs against it.
	Store orchestrator.StateStore

	// CheckTimeout bounds each readiness dependency check. If zero,
	// defaults to defaultHealthCheckTimeout.
	CheckTimeout time.Duration

	// BuildVersion is the orchestrator build version reported by
	// /v1/version. Empty renders as "dev" (matching main.version's zero
	// value).
	BuildVersion string
}

Healthcheck wires /health, /ready, and /v1/version handlers.

/health: liveness probe. Always 200; no dependencies. /ready: readiness probe. 200 when state store + fleet are reachable.

503 with a JSON breakdown when any check fails.

/v1/version: identifies the process as the fuse orchestrator.

All three are plaintext / unauthenticated by design — k8s and ALB probes don't (and shouldn't) carry bearer tokens, and a CLI probing an unknown URL can't carry a confirmed token yet either. This handler is mounted on the outer mux in server/main.go alongside /metrics, outside the auth + CIDR middleware chain installed by Handler.Router.

func (*Healthcheck) Liveness

func (h *Healthcheck) Liveness(w http.ResponseWriter, _ *http.Request)

Liveness reports that the process is up and able to serve HTTP. It deliberately does no work and depends on nothing — kubelet uses this to decide whether to restart the pod.

func (*Healthcheck) Readiness

func (h *Healthcheck) Readiness(w http.ResponseWriter, r *http.Request)

Readiness reports whether the orchestrator can currently serve traffic. It checks:

  • state_store: a bounded ListVMs call. Failures here typically mean Postgres is unreachable or the connection pool is wedged.
  • fleet: that the FleetManager is non-nil. (We can't easily check "Started" without poking at unexported state; a nil manager is the realistic failure mode at boot.)

On any failure the response is 503 with a per-check breakdown so operators can see at a glance which dependency is unhappy.

func (*Healthcheck) Version added in v0.5.0

func (h *Healthcheck) Version(w http.ResponseWriter, _ *http.Request)

Version identifies this process as the fuse orchestrator, unauthenticated so a caller can tell it apart from a host agent (or nothing at all) before it has a valid token. `fuse connect` probes this before saving a context.

type HostCapacity

type HostCapacity struct {
	CPUs      int `json:"cpus"`
	RamMB     int `json:"ram_mb"`
	StorageGB int `json:"storage_gb"`
	VMCount   int `json:"vm_count"`
	// Arch is the host's CPU architecture in GOARCH vocabulary ("amd64",
	// "arm64"). Probed from the host agent when it reports one; may be
	// declared at registration. Empty means amd64 (pre-arch hosts).
	Arch    string `json:"arch,omitempty"`
	GPUs    int    `json:"gpus,omitempty"`
	GPUKind string `json:"gpu_kind,omitempty"`

	// MIGProfiles advertises fractional GPU capacity: MIG instance count
	// by profile name (e.g. {"1g.10gb": 4}). Like GPUs, it requires
	// backend "qemu" and is declared by the operator, never probed.
	//
	// When the host reports per-instance MIG inventory (MIGInstances), this
	// map is a derived summary (count by profile) and the scheduler binds
	// specific instance uuids. A host that only declares counts (the
	// --mig-profile registration override) keeps this map as the scheduling
	// unit.
	MIGProfiles map[string]int `json:"mig_profiles,omitempty"`

	// MIGInstances is the per-instance MIG inventory probed from the host
	// agent (one entry per carved MIG GPU instance). When non-empty, the
	// scheduler switches from count-based to instance-based allocation and
	// binds concrete uuids to VMs. Strictly additive: a host that reports no
	// instances falls back to MIGProfiles. Only populated on capacity (not
	// allocated) for qemu hosts.
	MIGInstances []MIGInstance `json:"mig_instances,omitempty"`

	// MIGInstanceUUIDs is the set of MIG instance uuids currently bound to
	// VMs. Populated only on Allocated (never on Capacity), and only for
	// hosts that report per-instance MIG inventory. The durable source of
	// truth is the per-VM mig_instance_uuids binding.
	MIGInstanceUUIDs []string `json:"mig_instance_uuids,omitempty"`

	// GPUDevices is the per-device GPU detail probed from the host agent,
	// carried alongside the scalar GPUs/GPUKind counters. Only populated on
	// capacity (not allocated) for qemu hosts.
	GPUDevices []GPUDevice `json:"gpu_devices,omitempty"`
}

HostCapacity is the wire shape of a host's resource envelope.

type HostInfo

type HostInfo struct {
	ID        string            `json:"id"`
	URL       string            `json:"url"`
	Region    string            `json:"region,omitempty"`
	Backend   string            `json:"backend,omitempty"`
	Labels    map[string]string `json:"labels,omitempty"`
	State     string            `json:"state"`
	Capacity  HostCapacity      `json:"capacity"`
	Allocated HostCapacity      `json:"allocated"`
	LastSeen  time.Time         `json:"last_seen"`
	CreatedAt time.Time         `json:"created_at"`
	UpdatedAt time.Time         `json:"updated_at"`

	// Warnings carries non-fatal notices from registration (e.g. a
	// declared capacity value that exceeds what was probed from the host
	// agent). Only ever populated on the POST /v1/hosts response.
	Warnings []string `json:"warnings,omitempty"`
}

HostInfo is the JSON shape returned for a single host.

type HostList

type HostList struct {
	Hosts []HostInfo `json:"hosts"`
}

HostList is the response body for GET /v1/hosts.

type IPRejectFunc

type IPRejectFunc func(remoteAddr, method, path, requestID string)

IPRejectFunc is invoked once for every request rejected by the CIDR allowlist. Same shape and contract as AuthFailureFunc.

type InlineResolver

type InlineResolver struct{}

InlineResolver decodes the ManifestInline field as standard base64. It rejects empty inputs and any leading/trailing whitespace via the stdlib decoder's strictness.

func (InlineResolver) Resolve

Resolve implements Resolver.

type MIGInstance added in v0.9.0

type MIGInstance struct {
	UUID          string `json:"uuid,omitempty"`
	Profile       string `json:"profile,omitempty"`
	Kind          string `json:"kind,omitempty"`
	ParentGPUUUID string `json:"parent_gpu_uuid,omitempty"`
}

MIGInstance is the wire shape of a single carved MIG GPU instance. It mirrors orchestrator.MIGInstance. The orchestrator binds a specific instance uuid to a VM so it knows which instance went to which VM.

type Principal

type Principal struct {
	// Master is true when the request authenticated with the static
	// master token (ORCH_AUTH_TOKEN). When auth is disabled (empty
	// master token, insecure mode), requests are also treated as Master.
	Master bool
	// KeyID is the public id of the authenticating API key, empty for a
	// master-token request.
	KeyID string
}

Principal identifies how a request authenticated. It is stored in the request context by BearerAuth so handlers (and audit) can distinguish the master operator from an individual API key — e.g. to restrict key management to the master token.

func PrincipalFromContext

func PrincipalFromContext(ctx context.Context) (Principal, bool)

PrincipalFromContext returns the authenticated principal for the request. When auth is disabled (insecure mode) no principal is set; callers should treat a missing principal as the master operator, mirroring BearerAuth's open pass-through. The bool reports whether a principal was present.

type ProviderFactory

type ProviderFactory func(url, token string, backend orchestrator.HostBackend) orchestrator.Provider

ProviderFactory constructs a Provider for a registered host given its URL, auth token, and virtualization backend. The REST handler calls this during POST /v1/hosts to avoid importing provider-specific packages. In production a firecracker backend returns a firecracker.Provider and a qemu backend returns a qemu.Provider; tests pass a stub.

type RegisterHostRequest

type RegisterHostRequest struct {
	ID       string            `json:"id"`
	URL      string            `json:"url"`
	Token    string            `json:"token,omitempty"`
	Region   string            `json:"region,omitempty"`
	Backend  string            `json:"backend,omitempty"`
	Labels   map[string]string `json:"labels,omitempty"`
	Capacity HostCapacity      `json:"capacity"`
}

RegisterHostRequest is the JSON body accepted by POST /v1/hosts.

Backend selects the host's virtualization backend ("firecracker" or "qemu"). Omitted or empty defaults to "firecracker". Only "qemu" hosts may register with Capacity.GPUs > 0.

Labels are operator-declared key/value pairs matched against a spec's placement label selectors. They are never probed from the host agent.

type Resolver

type Resolver interface {
	Resolve(req CreateEnvironmentRequest) ([]byte, error)
}

Resolver turns a CreateEnvironmentRequest into raw manifest bytes. The default implementation understands inline base64 only; a future revision can plug in out-of-band ref resolution without touching handler code.

type ResourceSpec

type ResourceSpec struct {
	CPUs      int32  `json:"cpus,omitempty"`
	RamMB     int32  `json:"ram_mb,omitempty"`
	StorageGB int32  `json:"storage_gb,omitempty"`
	Region    string `json:"region,omitempty"`
	// Arch restricts scheduling to hosts of this CPU architecture ("amd64",
	// "arm64"; the uname spellings x86_64/aarch64 are accepted and
	// normalized). Empty means any host.
	Arch              string `json:"arch,omitempty"`
	MaxRuntimeSeconds int64  `json:"max_runtime_seconds,omitempty"`
	// IdleTimeoutSeconds destroys the environment after this many seconds
	// with no exec and no attach session. Zero means no idle expiry. Unlike
	// MaxRuntimeSeconds (a leak-detection ceiling measured from create),
	// this is measured from the last control-plane activity.
	IdleTimeoutSeconds int64  `json:"idle_timeout_seconds,omitempty"`
	Image              string `json:"image,omitempty"`
	GPUs               int32  `json:"gpus,omitempty"`
	GPUKind            string `json:"gpu_kind,omitempty"`
	// GPUProfile requests fractional GPU allocation: a MIG profile in
	// mig-parted vocabulary (e.g. "1g.10gb"). When set, GPUs counts MIG
	// instances of this profile rather than whole devices (decision D5).
	GPUProfile string `json:"gpu_profile,omitempty"`
	// HostID pins the environment to an exact host id (the Fusefile's
	// placement.host). A pin is a hard gate, not an override: the host still
	// has to be active, run the right backend, and fit the request. An
	// unknown host id is rejected as a 404 before any VM row is created.
	HostID string `json:"host_id,omitempty"`
	// Labels are placement label selectors (the Fusefile's placement.labels).
	// Every pair must match the target host's operator-declared labels.
	Labels map[string]string `json:"labels,omitempty"`
}

ResourceSpec is the JSON shape of the hardware spec attached to an environment create request or response body.

Image names a base rootfs for the provider to boot the VM from (a name the firecracker host agent resolves against its own named-rootfs directory). Empty means the provider's default base.

type Snapshot

type Snapshot struct {
	ID               string `json:"id"`
	VMID             string `json:"vm_id"`
	TaskID           string `json:"task_id,omitempty"`
	TenantID         string `json:"tenant_id,omitempty"`
	ParentSnapshotID string `json:"parent_snapshot_id,omitempty"`
	Mode             string `json:"mode,omitempty"`
	State            string `json:"state,omitempty"`
	Comment          string `json:"comment,omitempty"`
	// Name is the caller-chosen lookup key from the snapshot's metadata,
	// surfaced so a build artifact can be found without its random id.
	Name           string           `json:"name,omitempty"`
	SizeBytes      int64            `json:"size_bytes,omitempty"`
	CreatedAt      time.Time        `json:"created_at"`
	UpdatedAt      time.Time        `json:"updated_at,omitempty"`
	RetentionUntil *time.Time       `json:"retention_until,omitempty"`
	LastError      string           `json:"last_error,omitempty"`
	ExportRef      string           `json:"export_ref,omitempty"`
	Exports        []SnapshotExport `json:"exports,omitempty"`
}

Snapshot is the JSON shape of a persisted snapshot record.

type SnapshotExport

type SnapshotExport struct {
	Destination string    `json:"destination"`
	Status      string    `json:"status,omitempty"`
	RequestedAt time.Time `json:"requested_at,omitempty"`
	UpdatedAt   time.Time `json:"updated_at,omitempty"`
	LastError   string    `json:"last_error,omitempty"`
}

SnapshotExport is the JSON shape of an optional exported snapshot artifact.

type SnapshotList

type SnapshotList struct {
	Snapshots []Snapshot `json:"snapshots"`
}

SnapshotList is the response body for GET /v1/snapshots.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL