Skip to content

Commit

Permalink
Implementation of SDK.Allocate()
Browse files Browse the repository at this point in the history
Now GameServers can self Allocate!

This is just the implementation of the GO SDK at this stage (although
the gRPC libraries have been regenerated). Other languages can come in
later PRs.

This is the first part of 1st Party MatchMaking support (googleforgames#660)
  • Loading branch information
markmandel committed Apr 15, 2019
1 parent c220987 commit 55164ba
Show file tree
Hide file tree
Showing 41 changed files with 935 additions and 384 deletions.
2 changes: 1 addition & 1 deletion build/Makefile
Expand Up @@ -57,7 +57,7 @@ KIND_PROFILE ?= agones
KIND_CONTAINER_NAME=kind-$(KIND_PROFILE)-control-plane

# Game Server image to use while doing end-to-end tests
GS_TEST_IMAGE ?= gcr.io/agones-images/udp-server:0.7
GS_TEST_IMAGE ?= gcr.io/agones-images/udp-server:0.8

# Directory that this Makefile is in.
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
Expand Down
2 changes: 1 addition & 1 deletion build/boilerplate.go.txt
@@ -1,4 +1,4 @@
// Copyright 2018 Google LLC All Rights Reserved.
// Copyright 2019 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
2 changes: 1 addition & 1 deletion examples/fleet.yaml
Expand Up @@ -67,4 +67,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.7
image: gcr.io/agones-images/udp-server:0.8
2 changes: 1 addition & 1 deletion examples/simple-udp/Makefile
Expand Up @@ -27,7 +27,7 @@ REPOSITORY = gcr.io/agones-images

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
project_path := $(dir $(mkfile_path))
server_tag = $(REPOSITORY)/udp-server:0.7
server_tag = $(REPOSITORY)/udp-server:0.8
root_path = $(realpath $(project_path)/../..)

# _____ _
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/fleet-distributed.yaml
Expand Up @@ -32,7 +32,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.7
image: gcr.io/agones-images/udp-server:0.8
resources:
requests:
memory: "32Mi"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/fleet.yaml
Expand Up @@ -27,7 +27,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.7
image: gcr.io/agones-images/udp-server:0.8
resources:
requests:
memory: "64Mi"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/gameserver.yaml
Expand Up @@ -25,7 +25,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.7
image: gcr.io/agones-images/udp-server:0.8
resources:
requests:
memory: "32Mi"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/gameserverset.yaml
Expand Up @@ -31,4 +31,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.7
image: gcr.io/agones-images/udp-server:0.8
12 changes: 12 additions & 0 deletions examples/simple-udp/main.go
Expand Up @@ -94,6 +94,10 @@ func readWriteLoop(conn net.PacketConn, stop chan struct{}, s *sdk.SDK) {
case "GAMESERVER":
writeGameServerName(s, conn, sender)

// TODO: write an e2e test for this.
case "ALLOCATE":
allocate(s)

case "WATCH":
watchGameServerEvents(s)

Expand Down Expand Up @@ -126,6 +130,14 @@ func readWriteLoop(conn net.PacketConn, stop chan struct{}, s *sdk.SDK) {
}
}

// allocate attemps to allocate this gameserver
func allocate(s *sdk.SDK) {
err := s.Allocate()
if err != nil {
log.Fatalf("could not allocate gameserver: %v", err)
}
}

// readPacket reads a string from the connection
func readPacket(conn net.PacketConn, b []byte) (net.Addr, string) {
n, sender, err := conn.ReadFrom(b)
Expand Down
2 changes: 1 addition & 1 deletion install/helm/agones/templates/NOTES.txt
Expand Up @@ -19,7 +19,7 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.7
image: gcr.io/agones-images/udp-server:0.8

Finally don't forget to explore our documentation and usage guides on how to develop and host dedicated game servers on top of Agones. :

Expand Down
162 changes: 99 additions & 63 deletions pkg/sdk/sdk.pb.go

Large diffs are not rendered by default.

48 changes: 47 additions & 1 deletion pkg/sdk/sdk.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/sdkserver/localsdk.go
Expand Up @@ -121,6 +121,12 @@ func (l *LocalSDKServer) Ready(context.Context, *sdk.Empty) (*sdk.Empty, error)
return &sdk.Empty{}, nil
}

// Allocate logs that an allocate request has been received
func (l *LocalSDKServer) Allocate(context.Context, *sdk.Empty) (*sdk.Empty, error) {
logrus.Info("Allocate request has been received!")
return &sdk.Empty{}, nil
}

// Shutdown logs that the shutdown request has been received
func (l *LocalSDKServer) Shutdown(context.Context, *sdk.Empty) (*sdk.Empty, error) {
logrus.Info("Shutdown request has been received!")
Expand Down
41 changes: 41 additions & 0 deletions pkg/sdkserver/sdkserver.go
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/sirupsen/logrus"
"golang.org/x/net/context"
corev1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/clock"
Expand Down Expand Up @@ -330,6 +331,46 @@ func (s *SDKServer) Ready(ctx context.Context, e *sdk.Empty) (*sdk.Empty, error)
return e, nil
}

// Allocate set the GameServer to Allocate, as longs as it's not in UnHealthy,
// Shutdown or has a DeletionTimeStamp(). Times out after 30 seconds if it cannot
// complete the operation due to contention issues.
func (s *SDKServer) Allocate(context.Context, *sdk.Empty) (*sdk.Empty, error) {
s.logger.Info("Received self Allocate request")
err := wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (done bool, err error) {
gs, err := s.gameServer()
if err != nil {
return true, err
}

if !gs.ObjectMeta.DeletionTimestamp.IsZero() {
return true, nil
}

switch gs.Status.State {
case stablev1alpha1.GameServerStateUnhealthy:
return true, errors.New("cannot Allocate an Unhealthy GameServer")

case stablev1alpha1.GameServerStateShutdown:
return true, errors.New("cannot Allocate an Shutdown GameServer")
}

gsCopy := gs.DeepCopy()
gsCopy.Status.State = stablev1alpha1.GameServerStateAllocated
_, err = s.gameServerGetter.GameServers(s.namespace).Update(gsCopy)

// try again, with some jitter
if k8serrors.IsConflict(err) {
jitter := wait.Jitter(500*time.Millisecond, 1)
time.Sleep(jitter)
return false, nil
}

return true, errors.Wrap(err, "could not update gameserver to Allocated")
})

return &sdk.Empty{}, errors.WithStack(err)
}

// Shutdown enters the Shutdown state change for this GameServer into
// the workqueue so it can be updated
func (s *SDKServer) Shutdown(ctx context.Context, e *sdk.Empty) (*sdk.Empty, error) {
Expand Down

0 comments on commit 55164ba

Please sign in to comment.