vmlab-web: the REST + WebSocket API
Everything the web console does rides this API, so it can be scripted with plain HTTP. All /api/* routes sit behind the auth gate when auth is enabled: POST /api/login ({"user","password"}) returns a bearer token, GET /api/auth probes whether login is required, and POST /api/logout revokes the session. Lab and machine names appear in paths; {action} routes accept the verb in the path (e.g. up, down, start, stop). VMs and containers share one …/machines/{name}/… path family — they are the same thing to the API even though the console presents them separately. Where a machine cannot serve a request it says why: a container has no framebuffer, so screenshot.png fails with "machine web has no display", and a VM keeps no console log, so logs fails in kind. Ask …/machines/{name}/capabilities first — it reports display, console_log, reboot and the guest agent's negotiated features, which is what the console drives its affordances from.
| Area | Endpoints |
|---|---|
| Labs | GET/POST /api/labs (list, create — the create body takes preset: "empty" (default) or "starter"; anything else is a 400), GET /api/labs/{lab} (status), POST /api/labs/{lab}/{action} (up/down/destroy/…), POST …/reload, GET …/dns, GET …/logs, POST …/pulls/{machine}/cancel (abort an in-flight registry pull) |
| Machines (VMs + containers) | POST …/machines/{name}/{action} (start/stop/restart/destroy), GET …/capabilities, POST …/sendkeys, GET …/screenshot.png, GET …/stats, GET …/logs, GET/POST …/clipboard, GET/POST …/files?path= (one file out of / into the guest over the agent — the POST body is the file's bytes, the GET answers with them; 8 MiB each way), GET …/snapshots, DELETE …/snapshots/{name} |
| Snapshots (lab-wide) | POST …/snapshots (take), POST …/snapshots/{name}/restore |
| Templates | GET …/templates, GET …/templates/ops, GET …/templates/{tpl}/remote, POST …/templates/{tpl}/build|stop|publish |
| Playbooks | GET …/playbooks, GET …/playbooks/ops, GET …/playbooks/plays (every play the lab's folders declare), POST …/playbooks/scaffold (takes the play name; the folder need not be declared yet, and names that would break the skeleton's WCL literals are rejected), POST …/machines/{name}/playbook/{action} (check/apply); config-weave packages: POST …/playbooks/pkg, POST …/playbooks/pkg/search, GET/POST …/playbooks/repos |
| Playbook designer | POST …/playbooks/doc/inspect and POST …/playbooks/doc/render (config-weave's DocJson pipeline: source ⇄ structural document), GET …/playbooks/catalog (installed packages' resource + parameter declarations, which drive the property panels) |
| Files tab | GET …/files/tree, GET/PUT/DELETE …/files/file, POST …/files/mkdir, POST …/files/rename — sandboxed to the lab directory |
| Config & designer | GET/POST …/config (raw vmlab.wcl), GET/PUT …/scripts, GET …/model + POST …/model/edit (the designer's structured model + surgical edit ops) |
| Catalogs & host | GET /api/catalog/templates|profiles|meta|oci, DELETE /api/catalog/templates/{arch}/{name}/{version}, POST /api/catalog/templates/{arch}/{name}/{version}/verify (the Templates page's Check), GET/POST/DELETE /api/registries + POST /api/registries/login, GET /api/host, GET /api/host/fs, GET /api/fastpath |
| Live streams (WS) | GET /api/events (lab/daemon event feed), GET /api/labs/{lab}/machines/{name}/tty (agent terminals), GET /api/desktop/vnc/{lab}/{vm} and GET /api/labs/{lab}/templates/{arch}/{template}/vnc (desktop protocol) |
| Guest web pages | POST /api/web/session mints the path-scoped vmlab_web cookie; the proxy itself serves /web/{lab}/{kind}/{machine}/{page}/… outside the /api/ gate |
| Docs | GET /help, GET /help/{path} — this reference book, embedded |
TOKEN=$(curl -s -X POST :7878/api/login \
-d '{"user":"admin","password":"…"}' | jq -r .token)
curl -s -H "Authorization: Bearer $TOKEN" :7878/api/labs | jq .
curl -s -X POST -H "Authorization: Bearer $TOKEN" :7878/api/labs/demo/up