Agones control API forFactorio
A Rust Axum + utoipa REST API for the Agones-managed Factorio dedicated server — reads GameServer status via kube-rs and ClickHouse-backed player telemetry, surfaced through the staff dashboard over a same-origin proxy.
Player count from ClickHouse
Player count comes from ClickHouse (gameops.factorio_snapshots), not RCON — RCON binds loopback-only on the gameserver pod and is unreachable cross-pod. The relay sidecar produces telemetry; factorio-ctl reads the latest snapshot.
- Prefix — routes use
/factorio/*, never/fc/*. - Status — GameServer read via kube-rs, no CRD vendoring.
What it gives you
Features
GameServer status
Reads Agones GameServer state / node / address / port via kube-rs with a raw request, so an Agones schema bump can't break the build.
ClickHouse telemetry
Player count from gameops.factorio_snapshots, produced by the relay sidecar — RCON binds loopback-only and is unreachable cross-pod.
Same-origin proxy
Cluster-internal only, surfaced through the staff dashboard via /dashboard/factorio/proxy under DASHBOARD_VIEW.
OpenAPI spec
Serves a utoipa /openapi.json for the dashboard Scalar viewer.
Responsibilities
Overview & API
Rust Axum + utoipa REST API for the Agones-managed Factorio dedicated server. Mirrors firecracker-ctl: cluster-internal only, surfaced through the staff dashboard via a same-origin proxy (/dashboard/factorio/proxy, DASHBOARD_VIEW). Routes use the /factorio/* prefix — never /fc/*, which belongs to firecracker-ctl.
This entry registers the crate so the image builds and publishes. The Kubernetes Deployment ships with replicas: 0 until the image is available, then scales to 1.
API Endpoints (read-only, this slice)
Section titled “API Endpoints (read-only, this slice)”| Method | Path | Description |
|---|---|---|
GET | /factorio/health (+ /health) | Liveness, build identity, in-cluster kube-client presence |
GET | /factorio/server | Agones GameServer status (state / node / address / port) + latest telemetry snapshot |
GET | /openapi.json | utoipa spec for the dashboard Scalar viewer |
Design
Section titled “Design”- GameServer status is read via
kube-rswith a raw request to the Agones API (no CRD vendoring), so an Agones schema bump can’t break the build. - Player count comes from ClickHouse (
gameops.factorio_snapshots), not RCON — RCON binds loopback-only on the gameserver pod and is unreachable cross-pod. The relay sidecar is the telemetry producer; factorio-ctl reads the latest snapshot.
Config & deploy
Runtime & Kubernetes
Runtime knobs
Section titled “Runtime knobs”| Env | Default | Notes |
|---|---|---|
FACTORIO_CTL_PORT | 9002 | Listen port |
FACTORIO_NAMESPACE | factorio | GameServer namespace |
FACTORIO_GAMESERVER | factorio | GameServer name |
FACTORIO_SERVER_ID | factorio-1 | Stamps telemetry lookups |
CLICKHOUSE_ENDPOINT | (unset) | When unset, telemetry fields are omitted from /factorio/server |
CLICKHOUSE_USER / CLICKHOUSE_PASSWORD | (unset) | From the clickhouse-credentials ExternalSecret |
CLICKHOUSE_DATABASE | gameops |
Kubernetes Resources
Section titled “Kubernetes Resources”In apps/kube/agones/factorio/manifests/factorio-ctl.yaml:
- Deployment —
replicas: 0until the image publishes, then scale to 1 - Service — ClusterIP on port 9002
- RBAC — ServiceAccount + Role granting
get/list/watchonagones.dev/gameservers
Follow-ups (tracking #12735)
Section titled “Follow-ups (tracking #12735)”- Mutating endpoints:
/factorio/server/restart·/factorio/server/save·/factorio/saves/*·/factorio/rotation/*·/factorio/rcon/exec·/factorio/players. - Dashboard “control” tab consuming factorio-ctl.
- Tracking issue #12735 (supersedes #11138)
- Sibling pattern —
firecracker-ctl
Questions
Frequently asked
What is factorio-ctl?
A Rust Axum plus utoipa REST API for the Agones-managed Factorio dedicated server, exposing GameServer status and telemetry to the staff dashboard through a same-origin proxy.
Where does the player count come from?
From ClickHouse (gameops.factorio_snapshots), not RCON — RCON binds loopback-only on the gameserver pod and is unreachable cross-pod, so the relay sidecar produces telemetry and factorio-ctl reads the latest snapshot.
How does it read GameServer status without breaking on Agones upgrades?
It uses kube-rs with a raw request to the Agones API rather than vendoring the CRD, so an Agones schema bump cannot break the build.
