Documentation
¶
Overview ¶
Package api is the llmbox HTTP box-control API: the JSON surface the server exposes for box operations (create/get/list/destroy/logs/exec, proxies, spokes) and a Client that speaks it. The UI and any programmatic caller drive boxes through this API; the stand-alone llmbox-mcp binary is one such caller, wrapping the Client so it can serve those operations as MCP tools.
Backend is the operation contract both sides share: the server implements it, NewHandler serves an implementation over HTTP, and Client is an implementation backed by a remote server.
Index ¶
- Constants
- func NewHandler(b Backend) http.Handler
- type Backend
- type BoxSession
- type BoxView
- type Client
- func (c *Client) BoxExec(ctx context.Context, boxID, command string) (sandbox.ExecResult, error)
- func (c *Client) CreateBox(ctx context.Context, opts sandbox.CreateOptions) (BoxSession, error)
- func (c *Client) CreateProxy(ctx context.Context, boxID string, port int, description string) (ProxyInfo, error)
- func (c *Client) CreateSpoke(ctx context.Context, name, backend string, ttl time.Duration) (SpokeEnrollment, error)
- func (c *Client) DeleteProxy(ctx context.Context, boxID string, port int) error
- func (c *Client) DestroyBox(ctx context.Context, boxID string) error
- func (c *Client) DropSpoke(ctx context.Context, name string) error
- func (c *Client) ListBoxes(ctx context.Context) ([]BoxView, error)
- func (c *Client) ListJoinTokens(ctx context.Context) ([]JoinTokenInfo, error)
- func (c *Client) ListProxies(ctx context.Context, boxID string) ([]ProxyInfo, error)
- func (c *Client) LookupByBoxID(boxID string) (BoxSession, bool)
- func (c *Client) PauseBox(ctx context.Context, boxID string) error
- func (c *Client) ProxyEnabled() bool
- func (c *Client) RegenerateJoinToken(ctx context.Context, id string) (SpokeEnrollment, error)
- func (c *Client) ResumeBox(ctx context.Context, boxID string) error
- func (c *Client) RevokeJoinToken(ctx context.Context, id string) error
- func (c *Client) SetAPIKey(key string)
- func (c *Client) SetDefaultSpoke(ctx context.Context, name string) error
- func (c *Client) SpokeStatuses(ctx context.Context) ([]SpokeStatus, error)
- type JoinTokenInfo
- type ProxyInfo
- type SpokeEnrollment
- type SpokeStatus
Constants ¶
const ( PathCreateBox = "/api/v1/create-box" PathLookupBox = "/api/v1/lookup-box" PathListBoxes = "/api/v1/list-boxes" PathSpokeStatuses = "/api/v1/spoke-statuses" PathCreateSpoke = "/api/v1/create-spoke" PathDropSpoke = "/api/v1/drop-spoke" PathSetDefaultSpoke = "/api/v1/set-default-spoke" PathListJoinTokens = "/api/v1/list-join-tokens" PathRevokeJoinToken = "/api/v1/revoke-join-token" PathRegenerateJoinToken = "/api/v1/regenerate-join-token" PathDestroyBox = "/api/v1/destroy-box" PathPauseBox = "/api/v1/pause-box" PathResumeBox = "/api/v1/resume-box" PathBoxExec = "/api/v1/box-exec" PathProxyEnabled = "/api/v1/proxy-enabled" PathCreateProxy = "/api/v1/create-proxy" PathDeleteProxy = "/api/v1/delete-proxy" PathListProxies = "/api/v1/list-proxies" )
API route paths. Each maps 1:1 to a Backend method and is served/called with a single POST carrying a JSON body (an empty body for the no-argument methods).
const TokenPlaceholder = "<one-time-token>"
TokenPlaceholder stands in for the join-token secret in commands re-rendered after creation: the secret is stored only hashed, so once the create response is gone it can never be shown again.
Variables ¶
This section is empty.
Functions ¶
func NewHandler ¶
NewHandler builds the HTTP handler serving b's box operations as the JSON box- control API, one POST route per Backend method. It is meant to be mounted on the server's mux under the /api/v1/ prefix.
SECURITY — this handler performs no authentication of its own: it is pure transport. The hub mounts it behind its API auth middleware (an API key as a bearer token, or an admin login session with a CSRF header), so every route here is only reachable by an authenticated caller. Mounting it anywhere else without an equivalent gate exposes box exec/destroy to anyone who can reach it.
@arg b The backend whose operations are exposed over HTTP. @return http.Handler A mux serving the box-control routes over b.
@testcase TestBackendAPIRoundTrip drives every route through NewClient against NewHandler.
Types ¶
type Backend ¶
type Backend interface {
// CreateBox launches a box and returns its registered session.
CreateBox(ctx context.Context, opts sandbox.CreateOptions) (BoxSession, error)
// LookupByBoxID finds a box's session by its caller-assigned box ID
// (case-insensitive); ok is false when none matches.
LookupByBoxID(boxID string) (sess BoxSession, ok bool)
// ListBoxes returns all boxes managed across every spoke.
ListBoxes(ctx context.Context) ([]BoxView, error)
// SpokeStatuses returns every spoke and whether it is currently connected.
SpokeStatuses(ctx context.Context) ([]SpokeStatus, error)
// CreateSpoke mints a one-time join token enrolling a new spoke and returns it
// with the ready-to-run start command. backend picks the command's box backend
// ("docker" or "firecracker"; empty means docker); ttl<=0 uses the default.
CreateSpoke(ctx context.Context, name, backend string, ttl time.Duration) (SpokeEnrollment, error)
// DropSpoke removes a spoke's enrollment, revokes its join tokens, and
// disconnects it.
DropSpoke(ctx context.Context, name string) error
// SetDefaultSpoke makes an enrolled spoke the default that unqualified box
// creates run on.
SetDefaultSpoke(ctx context.Context, name string) error
// ListJoinTokens returns every outstanding spoke join token.
ListJoinTokens(ctx context.Context) ([]JoinTokenInfo, error)
// RevokeJoinToken deletes one outstanding join token by its ID.
RevokeJoinToken(ctx context.Context, id string) error
// RegenerateJoinToken replaces an outstanding join token with a freshly
// minted one for the same spoke (same name and backend), returning the new
// enrollment. The old token stops working; the new secret is shown once.
RegenerateJoinToken(ctx context.Context, id string) (SpokeEnrollment, error)
// DestroyBox stops and removes the box with the given box ID.
DestroyBox(ctx context.Context, boxID string) error
// PauseBox stops the compute of the box with the given box ID to save CPU/RAM,
// keeping its disk so it can be resumed later.
PauseBox(ctx context.Context, boxID string) error
// ResumeBox restarts a paused box's compute; the box comes back on the next
// ListBoxes.
ResumeBox(ctx context.Context, boxID string) error
// BoxExec runs a shell command inside the box with the given box ID.
BoxExec(ctx context.Context, boxID, command string) (sandbox.ExecResult, error)
// ProxyEnabled reports whether the HTTP proxy feature is configured.
ProxyEnabled() bool
// CreateProxy enables an HTTP proxy to a box's port and returns it. description
// is an optional human-readable note stamped onto the proxy, or "" for none.
CreateProxy(ctx context.Context, boxID string, port int, description string) (ProxyInfo, error)
// DeleteProxy disables the proxy for a box and port.
DeleteProxy(ctx context.Context, boxID string, port int) error
// ListProxies returns the enabled proxies, optionally filtered to one box.
ListProxies(ctx context.Context, boxID string) ([]ProxyInfo, error)
}
Backend is the box-operation contract the API layer needs. The server implements it; tests supply a fake.
type BoxSession ¶
BoxSession is the subset of a box's state the API surfaces. It is a flat value (no locks, no pointers into the server) so callers never reach back into the server's internals and tests can construct one directly.
type BoxView ¶
BoxView is one listed box. It is the underlying box as tracked by the hub; a box whose init script failed carries phase "broken" and its captured output in LastError.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a Backend that forwards every call to a remote box-control API. It lets a process drive boxes on an upstream llmbox server over HTTP with no in-process access to Docker, the store, or the cluster — the llmbox-mcp binary wraps one to serve those operations as MCP tools.
func NewClient ¶
NewClient builds a Client targeting the box-control API at baseURL (the upstream llmbox server's address). A nil hc uses http.DefaultClient.
@arg baseURL The upstream server's base URL, e.g. http://llmbox:8081. @arg hc The HTTP client to use; nil uses http.DefaultClient. @return *Client A backend forwarding calls to baseURL.
@testcase TestBackendAPIRoundTrip builds a client this way and drives every method.
func (*Client) BoxExec ¶
BoxExec runs a shell command inside a box by its box ID.
@arg ctx Context for the request. @arg boxID The box ID of the box to run the command in. @arg command The shell command line to run inside the box. @return sandbox.ExecResult The command's stdout, stderr, and exit code. @error error if the command cannot be run.
@testcase TestBackendAPIRoundTrip runs a command through the client.
func (*Client) CreateBox ¶
func (c *Client) CreateBox(ctx context.Context, opts sandbox.CreateOptions) (BoxSession, error)
CreateBox launches a box on the upstream server and returns its session.
@arg ctx Context for the request. @arg opts The image, box ID, description, and target spoke for the box. @return BoxSession The new box's ID, container ID, and auth token. @error error if the box cannot be created.
@testcase TestBackendAPIRoundTrip creates a box through the client.
func (*Client) CreateProxy ¶
func (c *Client) CreateProxy(ctx context.Context, boxID string, port int, description string) (ProxyInfo, error)
CreateProxy enables an HTTP proxy to a box's port on the upstream server.
@arg ctx Context for the request. @arg boxID The box ID whose port to expose. @arg port The port inside the box to forward to. @arg description An optional human-readable note for the proxy, or "" for none. @return ProxyInfo The new proxy's box ID, port, URL, slug, spoke, and description. @error error if the proxy cannot be created.
@testcase TestBackendAPIRoundTrip creates a proxy through the client.
func (*Client) CreateSpoke ¶
func (c *Client) CreateSpoke(ctx context.Context, name, backend string, ttl time.Duration) (SpokeEnrollment, error)
CreateSpoke mints a one-time join token for a new spoke on the upstream server and returns it with the ready-to-run start command.
@arg ctx Context for the request. @arg name The spoke name to enroll. @arg backend The box backend in the returned command ("docker" or "firecracker"; empty means docker). @arg ttl How long the token stays valid; <=0 uses the server default. @return SpokeEnrollment The token and start command. @error error if the token cannot be minted.
@testcase TestBackendAPIRoundTrip creates a spoke enrollment through the client.
func (*Client) DeleteProxy ¶
DeleteProxy disables the proxy for a box and port on the upstream server.
@arg ctx Context for the request. @arg boxID The box ID of the proxy to remove. @arg port The port of the proxy to remove. @error error if the proxy cannot be removed.
@testcase TestBackendAPIRoundTrip deletes a proxy through the client.
func (*Client) DestroyBox ¶
DestroyBox stops and removes the box with the given box ID on the upstream server.
@arg ctx Context for the request. @arg boxID The box ID of the box to destroy. @error error if the box cannot be destroyed.
@testcase TestBackendAPIRoundTrip destroys a box through the client.
func (*Client) DropSpoke ¶
DropSpoke removes a spoke's enrollment on the upstream server.
@arg ctx Context for the request. @arg name The spoke name to drop. @error error if the spoke cannot be dropped.
@testcase TestBackendAPIRoundTrip drops a spoke through the client.
func (*Client) ListBoxes ¶
ListBoxes returns all boxes managed by the upstream server.
@arg ctx Context for the request. @return []BoxView The managed boxes. @error error if listing boxes fails.
@testcase TestBackendAPIRoundTrip lists boxes through the client.
func (*Client) ListJoinTokens ¶
func (c *Client) ListJoinTokens(ctx context.Context) ([]JoinTokenInfo, error)
ListJoinTokens returns every outstanding spoke join token from the upstream server.
@arg ctx Context for the request. @return []JoinTokenInfo The outstanding join tokens. @error error if the tokens cannot be read.
@testcase TestBackendAPIRoundTrip lists join tokens through the client.
func (*Client) ListProxies ¶
ListProxies returns the enabled proxies on the upstream server, optionally filtered to one box.
@arg ctx Context for the request. @arg boxID The box ID to filter by, or "" for all proxies. @return []ProxyInfo The matching proxies. @error error if the proxies cannot be listed.
@testcase TestBackendAPIRoundTrip lists proxies through the client.
func (*Client) LookupByBoxID ¶
func (c *Client) LookupByBoxID(boxID string) (BoxSession, bool)
LookupByBoxID resolves a box by its box ID on the upstream server.
@arg boxID The box ID to look up. @return BoxSession The matching box's session (zero value when not found). @return bool Whether a box with that box ID exists.
@testcase TestBackendAPIRoundTrip looks a box up by box ID through the client.
func (*Client) PauseBox ¶ added in v0.1.6
PauseBox stops a box's compute by its box ID to save CPU/RAM, keeping its disk.
@arg ctx Context for the request. @arg boxID The box ID of the box to pause. @error error if the box cannot be paused.
@testcase TestBackendAPIRoundTrip pauses a box through the client.
func (*Client) ProxyEnabled ¶
ProxyEnabled reports whether the upstream server has HTTP proxying configured. A transport failure is reported as disabled.
@return bool True when proxying is enabled on the upstream server.
@testcase TestBackendAPIRoundTrip reports proxy enablement through the client.
func (*Client) RegenerateJoinToken ¶ added in v0.1.2
RegenerateJoinToken replaces an outstanding join token on the upstream server with a freshly minted one for the same spoke, returning the new enrollment (the old token stops working; the new secret is shown once).
@arg ctx Context for the request. @arg id The token ID to regenerate. @return SpokeEnrollment The fresh enrollment: name, one-time token, and start command. @error error if the token is unknown or cannot be regenerated.
@testcase TestBackendAPIRoundTrip regenerates a join token through the client.
func (*Client) ResumeBox ¶ added in v0.1.6
ResumeBox restarts a paused box's compute by its box ID; the box relaunches with a fresh session URL, visible on the next ListBoxes.
@arg ctx Context for the request. @arg boxID The box ID of the box to resume. @error error if the box cannot be resumed.
@testcase TestBackendAPIRoundTrip resumes a box through the client.
func (*Client) RevokeJoinToken ¶
RevokeJoinToken deletes one outstanding join token by ID on the upstream server.
@arg ctx Context for the request. @arg id The token ID to revoke. @error error if the token cannot be revoked.
@testcase TestBackendAPIRoundTrip revokes a join token through the client.
func (*Client) SetAPIKey ¶
SetAPIKey makes the client authenticate every request with key as a bearer token (Authorization: Bearer <key>). An empty key sends no credential.
@arg key The API key minted with `llmbox-server apikey add`, or "" for none.
@testcase TestClientSendsAPIKey sends the key as a bearer token on requests.
func (*Client) SetDefaultSpoke ¶
SetDefaultSpoke makes an enrolled spoke the default on the upstream server.
@arg ctx Context for the request. @arg name The spoke name to make the default. @error error if the default cannot be set.
@testcase TestBackendAPIRoundTrip sets the default spoke through the client.
func (*Client) SpokeStatuses ¶
func (c *Client) SpokeStatuses(ctx context.Context) ([]SpokeStatus, error)
SpokeStatuses returns every spoke and its connection status from the upstream server.
@arg ctx Context for the request. @return []SpokeStatus The spokes and their connection status. @error error if the spokes cannot be read.
@testcase TestBackendAPIRoundTrip reads spoke statuses through the client.
type JoinTokenInfo ¶
type JoinTokenInfo struct {
ID string `json:"id" jsonschema:"the opaque token ID used to revoke it"`
Name string `json:"name" jsonschema:"the spoke name the token enrolls"`
Backend string `json:"backend" jsonschema:"the box backend recorded when the token was created"`
Command string `` /* 138-byte string literal not displayed */
ExpiresAt time.Time `json:"expires_at" jsonschema:"when the token stops being accepted"`
}
JoinTokenInfo describes one outstanding spoke join token: an opaque ID to revoke it by, the spoke name it enrolls, the box backend recorded at creation, the enrollment command with TokenPlaceholder standing in for the secret, and its expiry. The token secret is never recoverable.
type ProxyInfo ¶
type ProxyInfo struct {
BoxID string `json:"box_id" jsonschema:"the box ID whose port is exposed"`
Port int `json:"port" jsonschema:"the port inside the box that is exposed"`
URL string `json:"url" jsonschema:"the URL the user opens to reach the box's port"`
Slug string `json:"slug" jsonschema:"the unguessable sub-domain label identifying the proxy"`
Spoke string `json:"spoke,omitempty" jsonschema:"the spoke the box runs on"`
// Description is the optional human-readable note supplied when the proxy was created.
Description string `json:"description,omitempty" jsonschema:"the optional human-readable note supplied when the proxy was created"`
}
ProxyInfo describes one enabled HTTP proxy: the box and port it exposes and the URL the user opens to reach it.
type SpokeEnrollment ¶
type SpokeEnrollment struct {
Name string `json:"name" jsonschema:"the spoke name the token enrolls"`
Token string `json:"token" jsonschema:"the one-time join token (shown once)"`
Command string `json:"command" jsonschema:"the copy-pasteable command that starts the spoke and enrolls it"`
}
SpokeEnrollment is the result of minting a join token for a new spoke: the one-time token and the ready-to-run command that starts the spoke with it. The token is shown once and never recoverable.
type SpokeStatus ¶
type SpokeStatus struct {
Name string `json:"name" jsonschema:"the spoke's name"`
Connected bool `json:"connected" jsonschema:"whether the spoke currently has a live connection to the hub"`
Default bool `json:"default,omitempty" jsonschema:"true for the default spoke unqualified box creates run on"`
EnrolledAt time.Time `json:"enrolled_at,omitempty" jsonschema:"when the spoke enrolled"`
}
SpokeStatus describes one enrolled cluster spoke and its health: whether it currently holds a live hub connection, and whether it is the default spoke that unqualified box creates run on.