bus-api-provider-vm — VM API provider
Runtime API
bus-api-provider-vm is the server-side provider for cloud-neutral VM/runtime
APIs.
In events mode, the provider sends VM lifecycle requests through the Bus Events
API. A deployment can pair it with bus-integration-upcloud when the backing
runtime is UpCloud.
LLM deployments can use this provider behind bus-api-provider-llm runtime
wake-up. The LLM provider should wake or check runtime readiness only for
execution requests; model catalog reads can stay local and avoid waking GPU
backends.
Authentication
Requests use Bearer JWT authentication with audience ai.hg.fi/api.
Status reads require access to vm:read. Lifecycle writes require access to
vm:write.
Send the token as Authorization: Bearer <jwt>. End users normally obtain the
token with bus auth token --resources "vm:read vm:write" after their account is
verified and approved; services use deployment-managed service tokens.
The curl examples below target the root compose.yaml nginx gateway at
LOCAL_AI_PLATFORM_PORT, which proxies to the provider. For a standalone
provider started directly on 127.0.0.1:8085, replace the base URL with
http://127.0.0.1:8085.
bus auth token --resources "vm:read vm:write"
TOKEN="$(cat ~/.config/bus/auth/api-token)"
GET /api/v1/vm/status
Returns user-visible runtime status.
Status reads are not quota-gated and are not treated as billable lifecycle
events.
The request body is empty. Success returns 200 OK with
{"status":{"state":"ready","provider":"...","details":{}}}.
The response object contains status.state (known values include ready,
starting, stopped, and unavailable), status.provider, and optional
status.details. Clients should display unknown future states as-is and treat
them as not ready unless the deployment documents otherwise.
curl -fsS \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:${LOCAL_AI_PLATFORM_PORT:-8080}/api/v1/vm/status
POST /api/v1/vm/start
Requests runtime start.
With billing enabled, the provider checks vm:write entitlement before sending
worker requests or recording lifecycle usage.
The request body is empty. Success returns 202 Accepted with
{"accepted":true,"action":"start"}.
curl -fsS -X POST \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:${LOCAL_AI_PLATFORM_PORT:-8080}/api/v1/vm/start
POST /api/v1/vm/stop
Requests runtime stop.
Use this only for runtime products where the caller is allowed to control the
target runtime.
The request body is empty. Success returns 202 Accepted with
{"accepted":true,"action":"stop"}.
curl -fsS -X POST \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:${LOCAL_AI_PLATFORM_PORT:-8080}/api/v1/vm/stop
GET /readyz
Reports provider readiness.
When BUS_EVENTS_LISTENER_REQUIRED=1, readiness is unhealthy until required
VM, usage, and billing response streams are connected.
curl -fsS http://127.0.0.1:8085/readyz
A ready provider returns 200 OK with {"ok":true}. If required Events
listeners are unavailable, readiness returns a non-2xx status with a JSON error
body.
--backend <static|events>
Selects the VM backend.
Use static for deterministic local checks. Use events for Bus Events
request/reply mode. The default is deployment-configured; standalone local
checks usually use static, while production runtime control uses events.
Static local provider:
BUS_VM_JWT_SECRET=not-a-secret-local-development-hs256-key \
bus-api-provider-vm --addr 127.0.0.1:8085 --backend static
For direct standalone curl checks against that static provider, mint the local token with the same HS256 secret and scopes:
TOKEN="$(BUS_AUTH_HS256_SECRET=not-a-secret-local-development-hs256-key bus operator token --format token issue --local --audience ai.hg.fi/api --scope 'vm:read vm:write')"
Events-backed provider:
BUS_VM_JWT_SECRET=dev-secret \
BUS_API_TOKEN="$(cat ./local/vm-provider.token)" \
bus-api-provider-vm \
--addr 127.0.0.1:8085 \
--backend events \
--events-url http://127.0.0.1:8081 \
--usage-backend events \
--billing-backend events
The provider token needs vm:read and vm:write for VM request/reply events.
Add usage:write when --usage-backend events is enabled and
billing:entitlement:check when --billing-backend events is enabled.
--events-url <url>
Sets the Bus Events API URL when Events mode is enabled.
Provide the provider token through deployment-managed configuration such as
BUS_API_TOKEN.
--backend events, --billing-backend events, and --usage-backend events
require --events-url or BUS_EVENTS_API_URL plus a provider token with the
matching VM, billing, and usage event scopes.
--billing-backend <none|events>
Enables billing entitlement checks for lifecycle write requests.
Denied requests return HTTP 402 with billing setup or quota guidance.
Default is none; use events for paid VM lifecycle plans.
--usage-backend <none|events|memory>
Enables runtime lifecycle usage records through bus-integration-usage.
Start and stop requests can record requested, finished, and failed lifecycle
events with the stable billing account UUID used by usage storage.
Default is none. Use events when usage should flow to
bus-integration-usage, or memory for deterministic local checks that should
not publish usage records to a shared Events API.
Common errors use {"error":{"type":"...","message":"..."}}. Missing or
invalid bearer tokens return 401 invalid_auth, missing identities resource
access returns 403 insufficient_access, entitlement denial returns 402,
event backend unavailability returns 503, and malformed integration
responses return 502.
For GET /api/v1/vm/status, callers should fix authentication or vm:read
resource access errors and retry later on backend 503. For
POST /api/v1/vm/start and POST /api/v1/vm/stop, callers also need
vm:write; 402 means billing setup or quota action is required before
retrying the lifecycle request.
Local Compose Stack
The BusDK superproject compose.yaml starts this provider as bus-vm with
--backend static, --usage-backend memory, and --billing-backend none.
Nginx exposes it at /api/v1/vm/* on the local API port. The static backend is
for deterministic local AI Platform checks, including /api/v1/vm/status
returning provider static; deployments that control real runtimes should use
Events mode with a VM integration backend.
Using from .bus files
Inside a .bus file, write the module target without the bus prefix:
# same as: bus api provider vm --backend events --events-url "$BUS_EVENTS_API_URL"
api provider vm --backend events --events-url "$BUS_EVENTS_API_URL"