Files
llmgw/notes/c19.md
T
Ilker ManapandClaude Opus 5.5 11b5d44702 A Terraform provider for llmgw: models, quotas and guard attachments through the admin API
terraform-provider-llmgw/ is a module of its own, built on
terraform-plugin-framework, so the gateway does not carry its dependencies.
llmgw_model is a model added at runtime: scaling, class, owner and adapters
change in place, anything else replaces it; the definition is kept as
written rather than as the catalog filled it in. llmgw_quota and
llmgw_guard_attachment keep the scope as written beside the ID it resolved
to, and import by that ID. Data sources llmgw_models and llmgw_nodes.

The client lists every endpoint it calls and refuses any other; a test
checks each, and every field it sends and reads, against
docs/admin-api.openapi.json, so a change to the admin API that breaks the
provider fails here. Acceptance tests run Terraform against an admin API in
memory when TF_ACC is set. CI vets and tests the module.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 00:04:35 +02:00

3.5 KiB

C19: OpenAPI for the admin API, and a Terraform provider

CHANGELOG

The admin API described, and a Terraform provider

  • The admin API in OpenAPI 3.1. Every endpoint under /api/v1, its path and query parameters, and the schema of each request and answer with the meaning of each field, in docs/admin-api.openapi.json and served by every control plane at GET /api/v1/openapi.json (with the token, like the rest). The bearer token, the X-Llmgw-Actor header and the error shape are in it. Generated by go generate ./internal/docgen from a route table in internal/control/adminapi/routes.go and the Go types the handlers use, with the fields' comments as descriptions; a test fails when an endpoint is served and not in the table, another when the committed document is stale. Checked with openapi-spec-validator and openapi-generator-cli's validate.
  • docs/admin-api.md: how to reach the API (loopback, an SSH tunnel, admin_remote), the token at /var/lib/llmgw/admin-token, what a request must carry — an address in Host, application/json on every change, even a DELETE — and some calls with curl.
  • GET /api/v1/models/{name}: one model's whole definition as it is in force, with the defaults the catalog filled in. The listing has only its state and its profiles' names.
  • A Terraform provider, in terraform-provider-llmgw/, a module of its own so the gateway does not carry its dependencies. llmgw_model (a model added at runtime: scaling, class, owner and adapters change in place, the rest replaces it), llmgw_quota, llmgw_guard_attachment, and the llmgw_models and llmgw_nodes data sources. Its client is checked against the OpenAPI document, endpoint by endpoint and field by field, so a change to the admin API that breaks it fails its tests; CI runs them. Built and installed by hand for now: see its README.

BACKLOG

Done (branch features-c2): adminapi.Routes and internal/docgen/openapi generating docs/admin-api.openapi.json (3.1, bearer security, every route, query parameters, schemas from the Go types with their comments), served embedded at GET /api/v1/openapi.json, kept true by a route-table test and a staleness test; validated with openapi-spec-validator and openapi-generator-cli. GET /api/v1/models/{name}. docs/admin-api.md. terraform-provider-llmgw/ (terraform-plugin-framework): llmgw_model, llmgw_quota, llmgw_guard_attachment, data sources llmgw_models and llmgw_nodes; client tests against a fake admin API and the OpenAPI document; acceptance tests with Terraform and OpenTofu against the fake; one apply, empty plan, in-place change and destroy against a real llmgw server run by hand. Left: organizations, teams, projects, people and keys are not in the admin API (they are llmgw org/users/keys against the store), so not in the provider; a model's definition beyond scaling, class, owner and adapters is changed by replacing it (the API has no edit, and resources is not used yet); canary, slo, scaling.schedule and prewarm, guard role and origin are not in llmgw_model; models cannot be imported; the provider is not published to a registry and has no release build; the acceptance tests are not run in CI (they need Terraform); the document's schemas mark nothing required and give no enums; catalog.SLO's fields have no JSON tags, so they are TTFTp99 and TPOTp99 on the wire.