Skip to main content

The k7-sdk PyPI package (import k7_sdk) wraps the K7 HTTP API in two clients. The legacy katakate name still installs but emits a deprecation warning.

  • Client — synchronous, backed by requests.
  • AsyncClient — asyncio-native, backed by httpx.

Install#

Run this on your laptop / client. A k7 node (fresh Ubuntu 24.04) does not ship python3-venv; python3 -m venv … fails until sudo apt install -y python3-venv python3-pip.

The async client raises RuntimeError at construction time if httpx isn’t installed.

Always pass verify_ssl as the cluster CA path on the default HTTPS install (./k7-ca.crt, or /etc/k7/tls/ca.crt on the node). k7 api status prints a ready-to-paste snippet that includes it.

Quickstart#

Discover the endpoint with k7 api endpoint and the key with k7 generate-api-key <name> --role user --tenant <tenant> (--role is required since 0.5.0; see Tenants and roles). Humans can use an OIDC token instead of a key: pass token_provider= a callable returning the bearer token (for example a reader for the token in ~/.config/k7/credentials.json after k7 login, a GitHub Actions ID token, or a projected ServiceAccount token). Exactly one of api_key / token_provider must be given. On the default install the API presents a certificate signed by the cluster CA (/etc/k7/tls/ca.crt on the node) — copy it to the client and pass its path as verify_ssl. Clusters installed with --api-hostname (Let’s Encrypt) work with the default verify_ssl=True. See the CLI guide for full details.

Client reference#

MethodReturnsNotes
Client(endpoint, api_key=None, verify_ssl=True, token_provider=None)—Exactly one of api_key (sent as X-API-Key) or token_provider (a Callable[[], str] called per request, sent as Authorization: Bearer). verify_ssl is True (system trust store) or a CA bundle path (cluster CA). verify_ssl=False raises ValueError on an https:// URL — there is no insecure mode; use http:// only against a --api-insecure-http development install.
whoami()dictThe caller’s identity: subject, role, tenant, namespaces, nodes (GET /api/v1/auth/whoami).
create(config: dict)SandboxProxyconfig matches SandboxConfig.
list(namespace=None)list[dict]Omit namespace to list all.
delete(name, namespace="default")dict
delete_all(namespace="default")dictReturns {message, results: [{name, success, error}]}.
get_metrics(namespace=None)list[dict]Per-sandbox cpu_usage / memory_usage.
install(nodes: list[str])dictRemote node install through the k7-node-installer (admin, development mode, --api-remote-install). Returns the 202 body with the operation id. The pre-0.5.0 playbook-upload form is gone.
install_status(operation)dictPer-node pending / running / succeeded / failed for an install operation.
pause(name, snapshot=None, namespace=...)dictScale to 0; optional VolumeSnapshot name
resume(name, namespace=...)dictScale back to 1
fork(source, new_name, namespace=..., snapshot=None)SandboxProxykql: disk clone + cold boot; k7d / k7d-fc: warm CoW fork (memory + disk)
restore(snapshot, new_name, overrides=None, keep_snapshot=True)SandboxProxyNew sandbox from a snapshot
list_snapshots(...) / get_snapshot(...) / create_snapshot(...) / delete_snapshot(...) / gc_snapshots(...)variesSnapshot lifecycle (see Snapshots API)
exec(name, command, namespace="default")dictRun a command without a proxy
logs(name, tail=200, container="sandbox", since=0, namespace=...)strSnapshot of the pod logs
nodes_storage()dictPer-node kfd thin-pool + k7d disk-pool utilization (see Nodes API). operator / admin only (403 for tenant roles).
usage(start, end, tenant=None, group_by=None)dictShowback over [start, end] (unix seconds) from the cluster’s Prometheus; group_by is a comma list of tenant,namespace,backend,state. Tenant roles see their own tenant only. See Observability and metering.
create_api_key(name, *, role, expires_days, tenant=None, namespaces=None, nodes=None)dictadmin: mint a key; the response carries the one-time token.
list_api_keys() / revoke_api_key(name)list[dict] / dictKey inventory (hashes never returned) and revocation.
dedicate_node(node, tenant) / undedicate_node(node)dictReserve a node for one tenant / release it (admin).
get_role_bindings() / put_role_bindings(bindings, deny_subjects)dictRead / replace the OIDC role bindings ConfigMap (admin).

SandboxProxy (returned by create) exposes:

  • exec(command: str) -> dict — {exit_code, stdout, stderr, duration_ms}
  • delete() -> dict — shorthand for client.delete(name, namespace)
  • pause / resume / fork — same as the client methods, scoped to this sandbox
  • snapshot(name) — named VolumeSnapshot without pausing
  • logs(tail=200, container="sandbox", since=0) — log snapshot

The proxy keeps a reference to the Client, so calling sb.exec(...) after the parent client closes will raise.

All sandbox config fields#

The create() payload accepts every field from the API schema. Common ones:

See Sandboxes API for the full table.

Info

env_file points to a path on the API node, not the client. To inject runtime env vars from the client, build them into your before_script (echo "KEY=value" > /etc/sandbox.env) or commit them to your sandbox image.

Wait until ready#

HTTP POST /sandboxes (and Client.create / k7 create) returns once Kubernetes objects exist — often while ready is still False. Poll list() before exec or curling a NodePort:

Pause, resume, fork#

pause, resume, and fork work on Client and on the SandboxProxy from create. Behavior depends on the backend:

  • kata-qemu-longhorn — fork clones the root disk via Longhorn VolumeSnapshot (the fork cold-boots, ~45 s); pause/resume scale the Deployment and the PVC survives. A docker: True sandbox’s graph PVC is cloned too.
  • k7d / k7d-fc — fork is a warm CoW copy of the whole VM (memory + disk + processes — including a live docker: True engine, ~5 ms at the VMM, ~2 s end-to-end to a Ready pod); pause/resume freeze and thaw the live VM in place. Works for sandboxes on any node — the API forwards to the per-node k7-agent when needed.

Forks inherit the source’s egress and ingress policy, but not its expose_ports Service.

See Snapshots & fork for timing notes and CLI equivalents.

Snapshots and restore#

Full HTTP detail: Snapshots API.

Async client#

AsyncClient mirrors the sync client surface (create, list, delete, delete_all, exec, get_metrics, aclose). Note that AsyncClient.exec is a top-level method (await k7.exec(name, command)) rather than a proxy method.

Concurrent sandbox fan-out#

Errors#

requests.HTTPError / httpx.HTTPStatusError are raised on non-2xx responses. The error body follows the API envelope:

Recover the structured error:

Tips#

  • Always pass namespace= if you use anything other than default. A tenant key (k7 generate-api-key NAME --role user --tenant team-a, optionally narrowed with -n) cannot list all namespaces or touch a namespace outside its tenant (403); only operator / admin keys see the whole cluster.
  • Rotate API keys with k7 revoke-api-key <name> and k7 generate-api-key <name>.
  • The same operations are available via CLI (k7 pause, k7 fork, k7 snapshot, k7 restore) — default CLI path is the HTTP API; use --core only on the cluster node.