feat(velocity): legacy forwarding 列表跟随 CR 的 forwarding=legacy 标签实时更新 (#15)

This commit is contained in:
Lemon-miaow committed 2026-09-26 08:09:49 +08:00
1 parent 7c2fa08e85
commit 5099b2501f
15 files changed
+522 -14

No files matched your search

+3
View File
@@ -34,6 +34,9 @@ type ServerInfo struct {
// PlayerCountUnknown is true while the operator cannot read the player
// count over RCON; idle auto-stop waits until it can.
PlayerCountUnknown bool `json:"playerCountUnknown,omitempty"`
// LegacyForwarding mirrors the CR's forwarding=legacy label: the proxy
// forwards this server's players in the handshake address (#15).
LegacyForwarding bool `json:"legacyForwarding,omitempty"`
}
// CreateServerInput is the validated, structured create-server form (spec §15).
+1
View File
@@ -446,6 +446,7 @@ func serverInfo(ms *v1alpha1.MinecraftServer) *ServerInfo {
IdleStopSeconds: idleStopSeconds(ms),
PlayerCountUnknown: ms.Status.Phase == v1alpha1.PhaseRunning &&
meta.IsStatusConditionFalse(ms.Status.Conditions, v1alpha1.ConditionPlayersCounted),
LegacyForwarding: ms.Labels[v1alpha1.LabelForwarding] == v1alpha1.ForwardingLegacy,
}
}
+37
View File
@@ -2,6 +2,7 @@ package api
import (
"context"
"encoding/json"
"errors"
"sort"
"strings"
@@ -253,3 +254,39 @@ func TestSubdomainOf(t *testing.T) {
t.Fatalf("SubdomainOf(no subdomain) = %v, want nil", got)
}
}
// The forwarding=legacy label reaches the proxy as legacyForwarding on the server
// list (#15); any other value, and no label, leaves the server on modern
// forwarding and keeps the key out of the JSON.
func TestServerListCarriesLegacyForwarding(t *testing.T) {
scheme := runtime.NewScheme()
if err := v1alpha1.AddToScheme(scheme); err != nil {
t.Fatalf("scheme: %v", err)
}
labeled := func(name, value string) *v1alpha1.MinecraftServer {
ms := testServer(name, name)
ms.Labels = map[string]string{v1alpha1.LabelForwarding: value}
return ms
}
k := NewK8sCluster(fake.NewClientBuilder().WithScheme(scheme).WithObjects(
labeled("legacy18", "legacy"), labeled("shouty", "LEGACY"), labeled("modern", "modern"),
testServer("plain", "plain"),
).Build(), "minecraft")
infos, err := k.ListServers(context.Background())
if err != nil {
t.Fatalf("ListServers: %v", err)
}
for _, i := range infos {
b, err := json.Marshal(i)
if err != nil {
t.Fatal(err)
}
want := i.Name == "legacy18"
if i.LegacyForwarding != want || strings.Contains(string(b), `"legacyForwarding":true`) != want {
t.Errorf("%s: legacyForwarding = %v, JSON %s; want %v", i.Name, i.LegacyForwarding, b, want)
}
if !want && strings.Contains(string(b), "legacyForwarding") {
t.Errorf("%s: JSON carries legacyForwarding although it is off: %s", i.Name, b)
}
}
}
@@ -19,8 +19,22 @@ const (
// LabelSystemRole identifies setup-owned system servers. Its value is the
// reserved role name (for example, "login" or "lobby").
LabelSystemRole = GroupName + "/system-role"
// LabelForwarding set to ForwardingLegacy makes the proxy hand this server the
// player's identity BungeeCord-style, in the handshake address, instead of the
// proxy-wide modern forwarding (#15). It is for a 1.8-era backend behind
// ViaVersion, which drops modern forwarding's login plugin message; such a
// backend trusts whatever reaches its game port, so nothing but the proxy may.
// Only the Felis-Legacy Velocity fork acts on it. A label rather than a spec
// field: the CRD needs no change, so an existing install takes it as is; the
// operator copies no CR label onto the pod, so setting it never restarts the
// server; and felis-api never writes it, so marking a server takes kubectl on
// the cluster, which fits a switch that drops the forwarding secret.
LabelForwarding = GroupName + "/forwarding"
)
// ForwardingLegacy is the LabelForwarding value that selects legacy forwarding.
const ForwardingLegacy = "legacy"
// DesiredState is the operator-facing intent toggle (spec §4 spec.desiredState).
type DesiredState string