feat(multiplayer): propagate match ID to an already-allocated pod via annotations

Investigated the Fleet-manifest wiring task flagged last commit and
found a deeper, previously-undesigned gap: Kubernetes env vars are
fixed at pod creation, but Agones allocates a match to an already-
running Ready pod well after it starts -- so there was no channel at
all for match-specific data (match ID) to reach that pod's processes.

Close it using the Agones GameServerAllocation API's documented
spec.metadata.annotations field, which Agones applies to the allocated
GameServer's own object_meta on success: server/agones.Client.Allocate
now requests cosmic-clash.io/match-id and cosmic-clash.io/allocation-id
annotations, and the supervisor reads them back from the same
/gameserver SDK call it already makes for the assigned port/address
(GameServer.ObjectMeta.Annotations), falling back to them for its own
control-plane registration only when MatchID isn't explicitly
configured -- an explicit value always wins, and a match ID resolvable
from neither source fails Start() closed before any HTTP call.

The exact object_meta vs objectMeta JSON key from a live Agones SDK
sidecar is not independently verified from this sandbox; documented
inline, and the fallback degrades safely (empty annotations map, same
as before this change) if it turns out to be wrong.

Covered by two new tests: the annotation actually flowing through to
the registration body, and fail-closed with neither config nor
annotation supplying a match ID (registerCalled stays false, not just
that Start() errors).
This commit is contained in:
Josh Creek
2026-09-01 13:34:08 +01:00
parent 4278c04d60
commit fd18cf6ac0
5 changed files with 152 additions and 14 deletions
+16
View File
@@ -37,6 +37,18 @@ type allocationRequest struct {
Selectors []struct {
MatchLabels map[string]string `json:"matchLabels"`
} `json:"selectors"`
// Metadata.Annotations is applied to the allocated GameServer's own
// object_meta by Agones on successful allocation (a documented part
// of the GameServerAllocation spec, independent of the Selectors
// used to find capacity). This is the only way match-specific data
// reaches an already-Ready pod after allocation: Kubernetes env vars
// are fixed at pod creation, long before Agones assigns a match to
// that pod, so there is no other channel for it. The allocated
// process reads these back via the SDK's own GameServer call
// (server/supervisor's existing /gameserver request).
Metadata struct {
Annotations map[string]string `json:"annotations"`
} `json:"metadata"`
} `json:"spec"`
}
@@ -139,6 +151,10 @@ func (c Client) Allocate(ctx context.Context, request domain.AllocationRequest,
body.Spec.Selectors = []struct {
MatchLabels map[string]string `json:"matchLabels"`
}{{MatchLabels: cloneLabels(labels)}}
body.Spec.Metadata.Annotations = map[string]string{
"cosmic-clash.io/match-id": request.MatchID,
"cosmic-clash.io/allocation-id": request.AllocationID,
}
encoded, err := json.Marshal(body)
if err != nil {
return AllocatedServer{}, err