Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passthrough autopilot - Adds an AutopilotPassthroughPort Feature Gate and new pod label #3809

Merged
merged 5 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions install/helm/agones/defaultfeaturegates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PlayerAllocationFilter: false
PlayerTracking: false

# Dev features
FeatureAutopilotPassthroughPort: true

# Example feature
Example: false
3 changes: 3 additions & 0 deletions pkg/apis/agones/v1/gameserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ const (
// GameServerPodLabel is the label that the name of the GameServer
// is set on the Pod the GameServer controls
GameServerPodLabel = agones.GroupName + "/gameserver"
// GameServerPortPolicyPodLabel is the label to identify the port policy
// of the pod
GameServerPortPolicyPodLabel = agones.GroupName + "/port"
// GameServerContainerAnnotation is the annotation that stores
// which container is the container that runs the dedicated game server
GameServerContainerAnnotation = agones.GroupName + "/container"
Expand Down
19 changes: 19 additions & 0 deletions pkg/cloudproduct/gke/gke.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,21 @@ func (*gkeAutopilot) ValidateScheduling(ss apis.SchedulingStrategy, fldPath *fie
}

func (*gkeAutopilot) MutateGameServerPod(gss *agonesv1.GameServerSpec, pod *corev1.Pod) error {
setPassthroughLabel(gss, pod)
setPrimaryContainer(pod, gss.Container)
podSpecSeccompUnconfined(&pod.Spec)
return nil
}

// setPassthroughLabel sets the agones.dev/port: "autopilot-passthrough" label to the game server container.
// This will help to back the container port from the allocated port using an objectSelector of this label
// in GameServers that are using Passthrough Port Policy
func setPassthroughLabel(gs *agonesv1.GameServerSpec, pod *corev1.Pod) {
if runtime.FeatureEnabled(runtime.FeatureAutopilotPassthroughPort) && hasPortPolicy(gs, agonesv1.Passthrough) {
pod.ObjectMeta.Labels[agonesv1.GameServerPortPolicyPodLabel] = "autopilot-passthrough"
}
}

// setPrimaryContainer sets the autopilot.gke.io/primary-container annotation to the game server container.
// This acts as a hint to Autopilot for which container to add resources to during resource adjustment.
// See https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-resource-requests#autopilot-resource-management
Expand Down Expand Up @@ -223,6 +233,15 @@ func setEvictionNoExtended(ev *agonesv1.Eviction, pod *corev1.Pod) error {
return nil
}

func hasPortPolicy(gs *agonesv1.GameServerSpec, portPolicy agonesv1.PortPolicy) bool {
for _, p := range gs.Ports {
if p.PortPolicy == portPolicy {
return true
}
}
return false
}

type autopilotPortAllocator struct {
minPort int32
maxPort int32
Expand Down
96 changes: 96 additions & 0 deletions pkg/cloudproduct/gke/gke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
package gke

import (
"fmt"
"testing"

"agones.dev/agones/pkg/apis"
agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
"agones.dev/agones/pkg/util/runtime"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -222,6 +224,100 @@ func TestPodSeccompUnconfined(t *testing.T) {
}
}

func TestSetPassthroughLabel(t *testing.T) {
for name, tc := range map[string]struct {
pod *corev1.Pod
wantPod *corev1.Pod
ports []agonesv1.GameServerPort
features string
}{
"gameserver with with Passthrough port policy adds label to pod": {
features: fmt.Sprintf("%s=true", runtime.FeatureAutopilotPassthroughPort),

pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Labels: map[string]string{},
},
},
ports: []agonesv1.GameServerPort{
{
Name: "awesome-udp",
PortPolicy: agonesv1.Passthrough,
ContainerPort: 1234,
Protocol: corev1.ProtocolUDP,
},
},
wantPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Labels: map[string]string{
agonesv1.GameServerPortPolicyPodLabel: "autopilot-passthrough",
},
},
},
},
vicentefb marked this conversation as resolved.
Show resolved Hide resolved
"gameserver with Static port policy does not add label to pod": {
features: fmt.Sprintf("%s=true", runtime.FeatureAutopilotPassthroughPort),

pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Labels: map[string]string{},
},
},
ports: []agonesv1.GameServerPort{
{
Name: "awesome-udp",
PortPolicy: agonesv1.Static,
ContainerPort: 1234,
Protocol: corev1.ProtocolUDP,
},
},
wantPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Labels: map[string]string{},
},
},
},
"gameserver, no feature gate, with Passthrough port policy does not add label to pod": {
features: fmt.Sprintf("%s=false", runtime.FeatureAutopilotPassthroughPort),

pod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Labels: map[string]string{},
},
},
ports: []agonesv1.GameServerPort{
{
Name: "awesome-udp",
PortPolicy: agonesv1.Passthrough,
ContainerPort: 1234,
Protocol: corev1.ProtocolUDP,
},
},
wantPod: &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{},
Labels: map[string]string{},
},
},
},
} {
t.Run(name, func(t *testing.T) {
runtime.FeatureTestMutex.Lock()
defer runtime.FeatureTestMutex.Unlock()
require.NoError(t, runtime.ParseFeatures(tc.features))
gs := (&autopilotPortAllocator{minPort: 7000, maxPort: 8000}).Allocate(&agonesv1.GameServer{Spec: agonesv1.GameServerSpec{Ports: tc.ports}})
pod := tc.pod.DeepCopy()
setPassthroughLabel(&gs.Spec, pod)
assert.Equal(t, tc.wantPod, pod)
})
}
}

func TestSetEvictionNoExtended(t *testing.T) {
emptyPodAnd := func(f func(*corev1.Pod)) *corev1.Pod {
pod := &corev1.Pod{
Expand Down
4 changes: 4 additions & 0 deletions pkg/util/runtime/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ const (
////////////////
// Dev features

// FeatureAutopilotPassthroughPort is a feature flag that enables/disables Passthrough Port Policy.
FeatureAutopilotPassthroughPort Feature = "PassthroughPortPolicy"

////////////////
// Example feature

Expand Down Expand Up @@ -109,6 +112,7 @@ var (
FeaturePlayerTracking: false,

// Dev features
FeatureAutopilotPassthroughPort: true,

// Example feature
FeatureExample: false,
Expand Down
Loading