Skip to content

Commit

Permalink
Merge branch 'main' into refactor-simple-game-server
Browse files Browse the repository at this point in the history
  • Loading branch information
agones-bot committed Jun 25, 2024
2 parents 1614bf0 + 56337c8 commit 8bec16b
Show file tree
Hide file tree
Showing 18 changed files with 150 additions and 32 deletions.
1 change: 1 addition & 0 deletions build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ common_mounts = -v $(build_path)/.config/gcloud:/root/.config/gcloud \
-v $(build_path)/.gomod:/go/pkg/mod

# Its possible for this to change in the future, so it gets its own variable.
REGISTRY ?= local
workdir_path = $(mount_path)

build_version = $(call sha,$(build_path)/build-image/Dockerfile)
Expand Down
8 changes: 7 additions & 1 deletion cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const (
sidecarCPULimitFlag = "sidecar-cpu-limit"
sidecarMemoryRequestFlag = "sidecar-memory-request"
sidecarMemoryLimitFlag = "sidecar-memory-limit"
sidecarRunAsUserFlag = "sidecar-run-as-user"
sdkServerAccountFlag = "sdk-service-account"
pullSidecarFlag = "always-pull-sidecar"
minPortFlag = "min-port"
Expand Down Expand Up @@ -214,7 +215,7 @@ func main() {
gsController := gameservers.NewController(controllerHooks, health,
ctlConf.PortRanges, ctlConf.SidecarImage, ctlConf.AlwaysPullSidecar,
ctlConf.SidecarCPURequest, ctlConf.SidecarCPULimit,
ctlConf.SidecarMemoryRequest, ctlConf.SidecarMemoryLimit, ctlConf.SdkServiceAccount,
ctlConf.SidecarMemoryRequest, ctlConf.SidecarMemoryLimit, ctlConf.SidecarRunAsUser, ctlConf.SdkServiceAccount,
kubeClient, kubeInformerFactory, extClient, agonesClient, agonesInformerFactory)
gsSetController := gameserversets.NewController(health, gsCounter,
kubeClient, extClient, agonesClient, agonesInformerFactory)
Expand Down Expand Up @@ -260,6 +261,7 @@ func parseEnvFlags() config {
viper.SetDefault(sidecarCPULimitFlag, "0")
viper.SetDefault(sidecarMemoryRequestFlag, "0")
viper.SetDefault(sidecarMemoryLimitFlag, "0")
viper.SetDefault(sidecarRunAsUserFlag, "1000")
viper.SetDefault(pullSidecarFlag, false)
viper.SetDefault(sdkServerAccountFlag, "agones-sdk")
viper.SetDefault(certFileFlag, filepath.Join(base, "certs", "server.crt"))
Expand All @@ -284,6 +286,7 @@ func parseEnvFlags() config {
pflag.String(sidecarCPURequestFlag, viper.GetString(sidecarCPURequestFlag), "Flag to overwrite the GameServer sidecar container's cpu request. Can also use SIDECAR_CPU_REQUEST env variable")
pflag.String(sidecarMemoryLimitFlag, viper.GetString(sidecarMemoryLimitFlag), "Flag to overwrite the GameServer sidecar container's memory limit. Can also use SIDECAR_MEMORY_LIMIT env variable")
pflag.String(sidecarMemoryRequestFlag, viper.GetString(sidecarMemoryRequestFlag), "Flag to overwrite the GameServer sidecar container's memory request. Can also use SIDECAR_MEMORY_REQUEST env variable")
pflag.Int32(sidecarRunAsUserFlag, viper.GetInt32(sidecarRunAsUserFlag), "Flag to indicate the GameServer sidecar container's UID. Can also use SIDECAR_RUN_AS_USER env variable")
pflag.Bool(pullSidecarFlag, viper.GetBool(pullSidecarFlag), "For development purposes, set the sidecar image to have a ImagePullPolicy of Always. Can also use ALWAYS_PULL_SIDECAR env variable")
pflag.String(sdkServerAccountFlag, viper.GetString(sdkServerAccountFlag), "Overwrite what service account default for GameServer Pods. Defaults to Can also use SDK_SERVICE_ACCOUNT")
pflag.Int32(minPortFlag, 0, "Required. The minimum port that that a GameServer can be allocated to. Can also use MIN_PORT env variable.")
Expand Down Expand Up @@ -315,6 +318,7 @@ func parseEnvFlags() config {
runtime.Must(viper.BindEnv(sidecarCPURequestFlag))
runtime.Must(viper.BindEnv(sidecarMemoryLimitFlag))
runtime.Must(viper.BindEnv(sidecarMemoryRequestFlag))
runtime.Must(viper.BindEnv(sidecarRunAsUserFlag))
runtime.Must(viper.BindEnv(pullSidecarFlag))
runtime.Must(viper.BindEnv(sdkServerAccountFlag))
runtime.Must(viper.BindEnv(minPortFlag))
Expand Down Expand Up @@ -378,6 +382,7 @@ func parseEnvFlags() config {
SidecarCPULimit: limitCPU,
SidecarMemoryRequest: requestMemory,
SidecarMemoryLimit: limitMemory,
SidecarRunAsUser: int(viper.GetInt32(sidecarRunAsUserFlag)),
SdkServiceAccount: viper.GetString(sdkServerAccountFlag),
AlwaysPullSidecar: viper.GetBool(pullSidecarFlag),
KeyFile: viper.GetString(keyFileFlag),
Expand Down Expand Up @@ -430,6 +435,7 @@ type config struct {
SidecarCPULimit resource.Quantity
SidecarMemoryRequest resource.Quantity
SidecarMemoryLimit resource.Quantity
SidecarRunAsUser int
SdkServiceAccount string
AlwaysPullSidecar bool
PrometheusMetrics bool
Expand Down
3 changes: 2 additions & 1 deletion examples/simple-game-server/Dockerfile.windows
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

# Build Stage
ARG WINDOWS_VERSION=ltsc2019
ARG IMAGE_TAG=""

FROM --platform=linux/amd64 golang:1.21.6 as builder
WORKDIR /go/src
Expand All @@ -29,7 +30,7 @@ WORKDIR /go/src/agones.dev/agones/examples/simple-game-server
RUN GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o simple-game-server.exe *.go

RUN ls -ltr /go/src/agones.dev/agones/examples/simple-game-server
FROM mcr.microsoft.com/windows/servercore:${WINDOWS_VERSION}
FROM mcr.microsoft.com/windows/servercore:${WINDOWS_VERSION}${IMAGE_TAG}

WORKDIR /

Expand Down
6 changes: 5 additions & 1 deletion examples/simple-game-server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ BUILDX_WINDOWS_BUILDER = windows-builder
# For the full list of tags see https://hub.docker.com/_/microsoft-windows-servercore.
# GKE-Windows version map: https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-cluster-windows#version_mapping
WINDOWS_VERSIONS = ltsc2019 ltsc2022

# https://github.com/microsoft/Windows-Containers/issues/493: Pin the LTSC2019 image to an older sha
LTSC2019_IMAGE_TAG = "@sha256:6fdf140282a2f809dae9b13fe441635867f0a27c33a438771673b8da8f3348a4"

WINDOWS_DOCKER_PUSH_ARGS = # When pushing set to --push.
# Build with Windows support
WITH_WINDOWS ?= 1
Expand Down Expand Up @@ -108,7 +112,7 @@ push-windows-image-%:
build-windows-image-%: ensure-windows-buildx
cd $(root_path) && DOCKER_CLI_EXPERIMENTAL=enabled \
docker buildx build --platform windows/amd64 --builder $(BUILDX_WINDOWS_BUILDER) -f $(project_path)Dockerfile.windows \
--tag=$(server_tag)-windows_amd64-$* --build-arg WINDOWS_VERSION=$* . $(WINDOWS_DOCKER_PUSH_ARGS)
--tag=$(server_tag)-windows_amd64-$* --build-arg WINDOWS_VERSION=$* --build-arg IMAGE_TAG=$(if $(filter ltsc2019,$*),$(LTSC2019_IMAGE_TAG),) . $(WINDOWS_DOCKER_PUSH_ARGS)

ensure-windows-buildx:
# Windows image builds must be directed to a specific buildx context.
Expand Down
3 changes: 2 additions & 1 deletion examples/xonotic/Dockerfile.windows
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
# See https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility
# for details.
ARG WINDOWS_VERSION=ltsc2019
ARG IMAGE_TAG=""

# Build Stage
FROM --platform=linux/amd64 golang:1.21.6 as base
Expand All @@ -53,7 +54,7 @@ RUN curl -o xonotic.zip https://dl.xonotic.org/xonotic-0.8.6.zip && \


# Final Image
FROM mcr.microsoft.com/windows/servercore:${WINDOWS_VERSION}
FROM mcr.microsoft.com/windows/servercore:${WINDOWS_VERSION}${IMAGE_TAG}

WORKDIR C:/Xonotic

Expand Down
5 changes: 4 additions & 1 deletion examples/xonotic/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ PROD_REPO ?= us-docker.pkg.dev/agones-images/examples
WINDOWS_VERSIONS = ltsc2019 ltsc2022
BUILDX_WINDOWS_BUILDER = windows-builder

# https://github.com/microsoft/Windows-Containers/issues/493: Pin the LTSC2019 image to an older sha
LTSC2019_IMAGE_TAG = "@sha256:6fdf140282a2f809dae9b13fe441635867f0a27c33a438771673b8da8f3348a4"

# Build with Windows support
WITH_WINDOWS ?= 1

Expand Down Expand Up @@ -86,7 +89,7 @@ push-windows-image-%:

build-windows-image-%: ensure-windows-buildx
docker buildx build --platform windows/amd64 --builder $(BUILDX_WINDOWS_BUILDER) -f $(project_path)Dockerfile.windows \
--tag=$(server_tag)-windows_amd64-$* --build-arg WINDOWS_VERSION=$* . $(WINDOWS_DOCKER_PUSH_ARGS)
--tag=$(server_tag)-windows_amd64-$* --build-arg WINDOWS_VERSION=$* --build-arg IMAGE_TAG=$(if $(filter ltsc2019,$*),$(LTSC2019_IMAGE_TAG),) . $(WINDOWS_DOCKER_PUSH_ARGS)

ensure-windows-buildx:
# Windows image builds must be directed to a specific buildx context.
Expand Down
2 changes: 2 additions & 0 deletions install/helm/agones/templates/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ spec:
value: {{ .Values.agones.image.sdk.memoryRequest | quote }}
- name: SIDECAR_MEMORY_LIMIT
value: {{ .Values.agones.image.sdk.memoryLimit | quote }}
- name: SIDECAR_RUN_AS_USER
value: "1000"
- name: SDK_SERVICE_ACCOUNT
value: {{ .Values.agones.serviceaccount.sdk.name | quote }}
- name: PROMETHEUS_EXPORTER
Expand Down
2 changes: 2 additions & 0 deletions install/yaml/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17084,6 +17084,8 @@ spec:
value: "0"
- name: SIDECAR_MEMORY_LIMIT
value: "0"
- name: SIDECAR_RUN_AS_USER
value: "1000"
- name: SDK_SERVICE_ACCOUNT
value: "agones-sdk"
- name: PROMETHEUS_EXPORTER
Expand Down
8 changes: 8 additions & 0 deletions pkg/apis/agones/v1/gameserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,14 @@ func (gss *GameServerSpec) validateFeatureGates(fldPath *field.Path) field.Error
}
}

if !runtime.FeatureEnabled(runtime.FeaturePortPolicyNone) {
for i, p := range gss.Ports {
if p.PortPolicy == None {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("ports").Index(i).Child("portPolicy"), fmt.Sprintf("Value cannot be set to %s unless feature flag %s is enabled", None, runtime.FeaturePortPolicyNone)))
}
}
}

return allErrs
}

Expand Down
49 changes: 48 additions & 1 deletion pkg/apis/agones/v1/gameserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,52 @@ func TestGameServerValidateFeatures(t *testing.T) {
},
},
},
{
description: "PortPolicyNone is disabled, PortPolicy field set to None",
feature: fmt.Sprintf("%s=false", runtime.FeaturePortPolicyNone),
gs: GameServer{
Spec: GameServerSpec{
Ports: []GameServerPort{
{
Name: "main",
ContainerPort: 7777,
PortPolicy: None,
},
},
Container: "testing",
Lists: map[string]ListStatus{},
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "testing", Image: "testing/image"}}},
},
},
},
want: field.ErrorList{
field.Forbidden(
field.NewPath("spec.ports[0].portPolicy"),
"Value cannot be set to None unless feature flag PortPolicyNone is enabled",
),
},
},
{
description: "PortPolicyNone is enabled, PortPolicy field set to None",
feature: fmt.Sprintf("%s=true", runtime.FeaturePortPolicyNone),
gs: GameServer{
Spec: GameServerSpec{
Ports: []GameServerPort{
{
Name: "main",
ContainerPort: 7777,
PortPolicy: None,
},
},
Container: "testing",
Lists: map[string]ListStatus{},
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "testing", Image: "testing/image"}}},
},
},
},
},
}

for _, tc := range testCases {
Expand Down Expand Up @@ -1499,7 +1545,8 @@ func TestGameServerPassthroughPortAnnotation(t *testing.T) {
{Name: "containerOne", Image: "container/image"},
{Name: "containerTwo", Image: "container/image"},
{Name: "containerThree", Image: "container/image"},
{Name: "containerFour", Image: "container/image"}},
{Name: "containerFour", Image: "container/image"},
},
},
},
}}
Expand Down
11 changes: 11 additions & 0 deletions pkg/gameservers/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import (
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/utils/pointer"
)

const (
Expand Down Expand Up @@ -83,6 +84,7 @@ type Controller struct {
sidecarCPULimit resource.Quantity
sidecarMemoryRequest resource.Quantity
sidecarMemoryLimit resource.Quantity
sidecarRunAsUser int
sdkServiceAccount string
crdGetter apiextclientv1.CustomResourceDefinitionInterface
podGetter typedcorev1.PodsGetter
Expand Down Expand Up @@ -114,6 +116,7 @@ func NewController(
sidecarCPULimit resource.Quantity,
sidecarMemoryRequest resource.Quantity,
sidecarMemoryLimit resource.Quantity,
sidecarRunAsUser int,
sdkServiceAccount string,
kubeClient kubernetes.Interface,
kubeInformerFactory informers.SharedInformerFactory,
Expand All @@ -133,6 +136,7 @@ func NewController(
sidecarCPURequest: sidecarCPURequest,
sidecarMemoryLimit: sidecarMemoryLimit,
sidecarMemoryRequest: sidecarMemoryRequest,
sidecarRunAsUser: sidecarRunAsUser,
alwaysPullSidecarImage: alwaysPullSidecarImage,
sdkServiceAccount: sdkServiceAccount,
crdGetter: extClient.ApiextensionsV1().CustomResourceDefinitions(),
Expand Down Expand Up @@ -763,6 +767,13 @@ func (c *Controller) sidecar(gs *agonesv1.GameServer) corev1.Container {
if c.alwaysPullSidecarImage {
sidecar.ImagePullPolicy = corev1.PullAlways
}

sidecar.SecurityContext = &corev1.SecurityContext{
AllowPrivilegeEscalation: pointer.Bool(false),
RunAsNonRoot: pointer.Bool(true),
RunAsUser: pointer.Int64(int64(c.sidecarRunAsUser)),
}

return sidecar
}

Expand Down
12 changes: 8 additions & 4 deletions pkg/gameservers/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ import (
)

const (
ipFixture = "12.12.12.12"
ipv6Fixture = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
nodeFixtureName = "node1"
ipFixture = "12.12.12.12"
ipv6Fixture = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
nodeFixtureName = "node1"
sidecarRunAsUser = 1000
)

var GameServerKind = metav1.GroupVersionKind(agonesv1.SchemeGroupVersion.WithKind("GameServer"))
Expand Down Expand Up @@ -1306,6 +1307,9 @@ func TestControllerCreateGameServerPod(t *testing.T) {
assert.Equal(t, "FEATURE_GATES", sidecarContainer.Env[2].Name)
assert.Equal(t, "LOG_LEVEL", sidecarContainer.Env[3].Name)
assert.Equal(t, string(fixture.Spec.SdkServer.LogLevel), sidecarContainer.Env[3].Value)
assert.Equal(t, *sidecarContainer.SecurityContext.AllowPrivilegeEscalation, false)
assert.Equal(t, *sidecarContainer.SecurityContext.RunAsNonRoot, true)
assert.Equal(t, *sidecarContainer.SecurityContext.RunAsUser, int64(sidecarRunAsUser))

gsContainer := pod.Spec.Containers[1]
assert.Equal(t, fixture.Spec.Ports[0].HostPort, gsContainer.Ports[0].HostPort)
Expand Down Expand Up @@ -2257,7 +2261,7 @@ func newFakeController() (*Controller, agtesting.Mocks) {
map[string]portallocator.PortRange{agonesv1.DefaultPortRange: {MinPort: 10, MaxPort: 20}},
"sidecar:dev", false,
resource.MustParse("0.05"), resource.MustParse("0.1"),
resource.MustParse("50Mi"), resource.MustParse("100Mi"), "sdk-service-account",
resource.MustParse("50Mi"), resource.MustParse("100Mi"), sidecarRunAsUser, "sdk-service-account",
m.KubeClient, m.KubeInformerFactory, m.ExtClient, m.AgonesClient, m.AgonesInformerFactory)
c.recorder = m.FakeRecorder
return c, m
Expand Down
12 changes: 0 additions & 12 deletions sdks/csharp/sdk/AgonesSDK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,6 @@ public IAgonesBetaSDK Beta()
return beta;
}



/// <summary>
/// Connect the underlying gRPC channel.
/// </summary>
/// <returns>Always return true</returns>
[Obsolete("No need to call ConnectAsync anymore")]
public async Task<bool> ConnectAsync()
{
return true;
}

/// <summary>
/// Tells Agones that the Game Server is ready to take player connections
/// </summary>
Expand Down
1 change: 0 additions & 1 deletion sdks/csharp/sdk/IAgonesSDK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ namespace Agones
{
public interface IAgonesSDK : IDisposable
{
Task<bool> ConnectAsync();
Task<Status> ReadyAsync();
Task<Status> AllocateAsync();
Task<Status> ReserveAsync(long seconds);
Expand Down
28 changes: 24 additions & 4 deletions sdks/unity/AgonesSdk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,17 +360,37 @@ private void OnRequestCompleted(AsyncOperation _)
private class GameServerHandler : DownloadHandlerScript
{
private WatchGameServerCallback callback;
private StringBuilder stringBuilder;

public GameServerHandler(WatchGameServerCallback callback)
{
this.callback = callback;
this.stringBuilder = new StringBuilder();
}

protected override bool ReceiveData(byte[] data, int dataLength)
{
string json = Encoding.UTF8.GetString(data);
var dictionary = (Dictionary<string, object>) Json.Deserialize(json);
var gameServer = new GameServer(dictionary["result"] as Dictionary<string, object>);
this.callback(gameServer);
string dataString = Encoding.UTF8.GetString(data);
this.stringBuilder.Append(dataString);

string bufferString = stringBuilder.ToString();
int newlineIndex;

while ((newlineIndex = bufferString.IndexOf('\n')) >= 0)
{
string fullLine = bufferString.Substring(0, newlineIndex);
try
{
var dictionary = (Dictionary<string, object>) Json.Deserialize(fullLine);
var gameServer = new GameServer(dictionary["result"] as Dictionary<string, object>);
this.callback(gameServer);
}
catch (Exception ignore) {} // Ignore parse errors
bufferString = bufferString.Substring(newlineIndex + 1);
}

stringBuilder.Clear();
stringBuilder.Append(bufferString);
return true;
}
}
Expand Down
Loading

0 comments on commit 8bec16b

Please sign in to comment.