Skip to content

Commit

Permalink
CRD implementation of alpha player tracking (#1324)
Browse files Browse the repository at this point in the history
* CRD implementation of alpha player tracking

Update to CRD implementation, and pkg/api/gameserver.go and default
value implementation.

Work on #1033

* Including feature flag locking.

Required to allow tests to pass with race checking enabled.
  • Loading branch information
markmandel committed Feb 14, 2020
1 parent 2316a45 commit 59a2e43
Show file tree
Hide file tree
Showing 8 changed files with 470 additions and 17 deletions.
28 changes: 28 additions & 0 deletions install/helm/agones/templates/crds/_gameserverspecvalidation.yaml
Expand Up @@ -148,4 +148,32 @@ properties:
type: integer type: integer
minimum: 1 minimum: 1
maximum: 2147483648 maximum: 2147483648
alpha:
type: object
title: Alpha properties for the GameServer
properties:
players:
type: object
title: Configuration of player capacity
properties:
initialCapacity:
type: integer
title: The initial player capacity of this Game Server
minimum: 0
webhook:
type: object
title: webhook to call when a player connects or disconnects
properties:
service:
properties:
name:
type: string
namespace:
type: string
path:
type: string
url:
type: string
caBundle:
type: string
{{- end }} {{- end }}
84 changes: 84 additions & 0 deletions install/yaml/install.yaml
Expand Up @@ -394,6 +394,34 @@ spec:
type: integer type: integer
minimum: 1 minimum: 1
maximum: 2147483648 maximum: 2147483648
alpha:
type: object
title: Alpha properties for the GameServer
properties:
players:
type: object
title: Configuration of player capacity
properties:
initialCapacity:
type: integer
title: The initial player capacity of this Game Server
minimum: 0
webhook:
type: object
title: webhook to call when a player connects or disconnects
properties:
service:
properties:
name:
type: string
namespace:
type: string
path:
type: string
url:
type: string
caBundle:
type: string
subresources: subresources:
# status enables the status subresource. # status enables the status subresource.
status: {} status: {}
Expand Down Expand Up @@ -680,6 +708,34 @@ spec:
type: integer type: integer
minimum: 1 minimum: 1
maximum: 2147483648 maximum: 2147483648
alpha:
type: object
title: Alpha properties for the GameServer
properties:
players:
type: object
title: Configuration of player capacity
properties:
initialCapacity:
type: integer
title: The initial player capacity of this Game Server
minimum: 0
webhook:
type: object
title: webhook to call when a player connects or disconnects
properties:
service:
properties:
name:
type: string
namespace:
type: string
path:
type: string
url:
type: string
caBundle:
type: string


--- ---
# Source: agones/templates/crds/gameserverallocationpolicy.yaml # Source: agones/templates/crds/gameserverallocationpolicy.yaml
Expand Down Expand Up @@ -982,6 +1038,34 @@ spec:
type: integer type: integer
minimum: 1 minimum: 1
maximum: 2147483648 maximum: 2147483648
alpha:
type: object
title: Alpha properties for the GameServer
properties:
players:
type: object
title: Configuration of player capacity
properties:
initialCapacity:
type: integer
title: The initial player capacity of this Game Server
minimum: 0
webhook:
type: object
title: webhook to call when a player connects or disconnects
properties:
service:
properties:
name:
type: string
namespace:
type: string
path:
type: string
url:
type: string
caBundle:
type: string
subresources: subresources:
# status enables the status subresource. # status enables the status subresource.
status: {} status: {}
Expand Down
43 changes: 37 additions & 6 deletions pkg/apis/agones/v1/gameserver.go
Expand Up @@ -19,12 +19,13 @@ import (
"fmt" "fmt"
"net" "net"


"github.com/mattbaird/jsonpatch"

"agones.dev/agones/pkg" "agones.dev/agones/pkg"
"agones.dev/agones/pkg/apis" "agones.dev/agones/pkg/apis"
"agones.dev/agones/pkg/apis/agones" "agones.dev/agones/pkg/apis/agones"
"agones.dev/agones/pkg/util/runtime"
"github.com/mattbaird/jsonpatch"
"github.com/pkg/errors" "github.com/pkg/errors"
admregv1b "k8s.io/api/admissionregistration/v1beta1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
Expand Down Expand Up @@ -150,6 +151,20 @@ type GameServerSpec struct {
SdkServer SdkServer `json:"sdkServer,omitempty"` SdkServer SdkServer `json:"sdkServer,omitempty"`
// Template describes the Pod that will be created for the GameServer // Template describes the Pod that will be created for the GameServer
Template corev1.PodTemplateSpec `json:"template"` Template corev1.PodTemplateSpec `json:"template"`
// Alpha describes the alpha properties for the GameServer.
Alpha AlphaSpec `json:"alpha,omitempty"`
}

// AlphaSpec contains the alpha properties of the GameServer.
type AlphaSpec struct {
Players PlayersSpec `json:"players"`
}

// PlayersSpec tracks the initial player capacity, and what webhooks to send events to when there are
// connection/disconnection events.
type PlayersSpec struct {
InitialCapacity int64 `json:"initialCapacity,omitempty"`
Webhook *admregv1b.WebhookClientConfig `json:"webhook,omitempty"`
} }


// GameServerState is the state for the GameServer // GameServerState is the state for the GameServer
Expand Down Expand Up @@ -210,6 +225,7 @@ type GameServerStatus struct {
Address string `json:"address"` Address string `json:"address"`
NodeName string `json:"nodeName"` NodeName string `json:"nodeName"`
ReservedUntil *metav1.Time `json:"reservedUntil"` ReservedUntil *metav1.Time `json:"reservedUntil"`
Alpha AlphaStatus `json:"alpha"`
} }


// GameServerStatusPort shows the port that was allocated to a // GameServerStatusPort shows the port that was allocated to a
Expand All @@ -219,6 +235,17 @@ type GameServerStatusPort struct {
Port int32 `json:"port"` Port int32 `json:"port"`
} }


// AlphaStatus is the alpha status values for a GameServer
type AlphaStatus struct {
Players PlayerStatus `json:"players"`
}

// PlayerStatus stores the current player capacity values
type PlayerStatus struct {
Count int64 `json:"count"`
Capacity int64 `json:"capacity"`
}

// ApplyDefaults applies default values to the GameServer if they are not already populated // ApplyDefaults applies default values to the GameServer if they are not already populated
func (gs *GameServer) ApplyDefaults() { func (gs *GameServer) ApplyDefaults() {
// VersionAnnotation is the annotation that stores // VersionAnnotation is the annotation that stores
Expand All @@ -230,7 +257,7 @@ func (gs *GameServer) ApplyDefaults() {
gs.ObjectMeta.Finalizers = append(gs.ObjectMeta.Finalizers, agones.GroupName) gs.ObjectMeta.Finalizers = append(gs.ObjectMeta.Finalizers, agones.GroupName)


gs.Spec.ApplyDefaults() gs.Spec.ApplyDefaults()
gs.applyStateDefaults() gs.applyStatusDefaults()
} }


// ApplyDefaults applies default values to the GameServerSpec if they are not already populated // ApplyDefaults applies default values to the GameServerSpec if they are not already populated
Expand Down Expand Up @@ -277,15 +304,19 @@ func (gss *GameServerSpec) applyHealthDefaults() {
} }
} }


// applyStateDefaults applies state defaults // applyStatusDefaults applies Status defaults
func (gs *GameServer) applyStateDefaults() { func (gs *GameServer) applyStatusDefaults() {
if gs.Status.State == "" { if gs.Status.State == "" {
gs.Status.State = GameServerStateCreating gs.Status.State = GameServerStateCreating
// applyStateDefaults() should be called after applyPortDefaults() // applyStatusDefaults() should be called after applyPortDefaults()
if gs.HasPortPolicy(Dynamic) || gs.HasPortPolicy(Passthrough) { if gs.HasPortPolicy(Dynamic) || gs.HasPortPolicy(Passthrough) {
gs.Status.State = GameServerStatePortAllocation gs.Status.State = GameServerStatePortAllocation
} }
} }

if runtime.FeatureEnabled(runtime.FeaturePlayerTracking) {
gs.Status.Alpha.Players.Capacity = gs.Spec.Alpha.Players.InitialCapacity
}
} }


// applyPortDefaults applies default values for all ports // applyPortDefaults applies default values for all ports
Expand Down
32 changes: 23 additions & 9 deletions pkg/apis/agones/v1/gameserver_test.go
Expand Up @@ -22,6 +22,7 @@ import (
"agones.dev/agones/pkg" "agones.dev/agones/pkg"
"agones.dev/agones/pkg/apis" "agones.dev/agones/pkg/apis"
"agones.dev/agones/pkg/apis/agones" "agones.dev/agones/pkg/apis/agones"
"agones.dev/agones/pkg/util/runtime"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -62,21 +63,25 @@ func TestGameServerApplyDefaults(t *testing.T) {
t.Parallel() t.Parallel()


type expected struct { type expected struct {
protocol corev1.Protocol protocol corev1.Protocol
state GameServerState state GameServerState
policy PortPolicy policy PortPolicy
health Health health Health
scheduling apis.SchedulingStrategy scheduling apis.SchedulingStrategy
sdkServer SdkServer sdkServer SdkServer
alphaPlayerCapacity int64
} }
data := map[string]struct { data := map[string]struct {
gameServer GameServer gameServer GameServer
container string container string
expected expected featureFlags string
expected expected
}{ }{
"set basic defaults on a very simple gameserver": { "set basic defaults on a very simple gameserver": {
featureFlags: runtime.FeaturePlayerTracking + "=true",
gameServer: GameServer{ gameServer: GameServer{
Spec: GameServerSpec{ Spec: GameServerSpec{
Alpha: AlphaSpec{Players: PlayersSpec{InitialCapacity: 10}},
Ports: []GameServerPort{{ContainerPort: 999}}, Ports: []GameServerPort{{ContainerPort: 999}},
Template: corev1.PodTemplateSpec{ Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{Containers: []corev1.Container{ Spec: corev1.PodSpec{Containers: []corev1.Container{
Expand All @@ -100,6 +105,7 @@ func TestGameServerApplyDefaults(t *testing.T) {
GRPCPort: 9357, GRPCPort: 9357,
HTTPPort: 9358, HTTPPort: 9358,
}, },
alphaPlayerCapacity: 10,
}, },
}, },
"defaults on passthrough": { "defaults on passthrough": {
Expand Down Expand Up @@ -180,6 +186,7 @@ func TestGameServerApplyDefaults(t *testing.T) {
gameServer: GameServer{ gameServer: GameServer{
Spec: GameServerSpec{ Spec: GameServerSpec{
Ports: []GameServerPort{{PortPolicy: Static}}, Ports: []GameServerPort{{PortPolicy: Static}},
Alpha: AlphaSpec{Players: PlayersSpec{InitialCapacity: 10}},
Template: corev1.PodTemplateSpec{ Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "testing", Image: "testing/image"}}}}}, Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: "testing", Image: "testing/image"}}}}},
}, },
Expand Down Expand Up @@ -319,8 +326,14 @@ func TestGameServerApplyDefaults(t *testing.T) {
}, },
} }


runtime.FeatureTestMutex.Lock()
defer runtime.FeatureTestMutex.Unlock()

for name, test := range data { for name, test := range data {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
err := runtime.ParseFeatures(test.featureFlags)
assert.NoError(t, err)

test.gameServer.ApplyDefaults() test.gameServer.ApplyDefaults()


assert.Equal(t, pkg.Version, test.gameServer.Annotations[VersionAnnotation]) assert.Equal(t, pkg.Version, test.gameServer.Annotations[VersionAnnotation])
Expand All @@ -333,6 +346,7 @@ func TestGameServerApplyDefaults(t *testing.T) {
assert.Equal(t, test.expected.scheduling, test.gameServer.Spec.Scheduling) assert.Equal(t, test.expected.scheduling, test.gameServer.Spec.Scheduling)
assert.Equal(t, test.expected.health, test.gameServer.Spec.Health) assert.Equal(t, test.expected.health, test.gameServer.Spec.Health)
assert.Equal(t, test.expected.sdkServer, test.gameServer.Spec.SdkServer) assert.Equal(t, test.expected.sdkServer, test.gameServer.Spec.SdkServer)
assert.Equal(t, test.expected.alphaPlayerCapacity, test.gameServer.Status.Alpha.Players.Capacity)
}) })
} }
} }
Expand Down

0 comments on commit 59a2e43

Please sign in to comment.