Skip to content

Commit

Permalink
SDK GameServer() function for retrieving backing GameServer configu…
Browse files Browse the repository at this point in the history
…ration.

Extended the gRPC SDK to include a `GameServer()` function for both Go, C++
and REST by extending the backing `sdk.proto` and implementing the functionality
in the sdk sidecar.

This is the start of work needed for googleforgames#277.
  • Loading branch information
markmandel committed Jul 15, 2018
1 parent f85fa1a commit 5647b40
Show file tree
Hide file tree
Showing 37 changed files with 7,532 additions and 115 deletions.
2 changes: 2 additions & 0 deletions docs/governance/templates/release_issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and copy it into a release issue. Fill in relevent values, found inside {}
- [ ] Run `make gen-changelog` to generate the CHANGELOG.md (if release candidate `make gen-changelog RELEASE_VERSION={version}.rc`)
- [ ] Ensure the [helm `tag` value][values] is correct (should be the {version} if a full release, {version}.rc if release candidate)
- [ ] Run `make gen-install`
- [ ] Ensure all example images exist on gcr.io/agones-images
- [ ] If full release, update documentation with updated example images tags
- [ ] If RC release, update all ⚠️⚠️⚠️ warnings to: "**This is currently a release candidate feature**"
- [ ] If full release, remove all instances of "⚠️⚠️⚠️ **This is currently a development feature and has not been released** ⚠️⚠️⚠️"
- [ ] If full release, update install docs with the new release version
Expand Down
15 changes: 14 additions & 1 deletion docs/sdk_rest_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,17 @@ Call when the GameServer session is over and it's time to shut down

```bash
$ curl -d "{}" -H "Content-Type: application/json" -X POST http://localhost:59358/shutdown
```
```

### GameServer

⚠️⚠️⚠️ **/gameserver is currently a development feature and has not been released** ⚠️⚠️⚠️

Call when you want to retrieve the backing `GameServer` configuration details

- Path: `/gameserver`
- Method: `GET`

```bash
$ curl -H "Content-Type: application/json" -X GET http://localhost:59358/gameserver
```
2 changes: 1 addition & 1 deletion examples/cpp-simple/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ REPOSITORY = gcr.io/agones-images
# Directory that this Makefile is in.
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
project_path := $(dir $(mkfile_path))
server_tag = $(REPOSITORY)/cpp-simple-server:0.1
server_tag = $(REPOSITORY)/cpp-simple-server:0.2

# _____ _
# |_ _|_ _ _ __ __ _ ___| |_ ___
Expand Down
2 changes: 1 addition & 1 deletion examples/cpp-simple/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ spec:
spec:
containers:
- name: cpp-simple
image: gcr.io/agones-images/cpp-simple-server:0.1
image: gcr.io/agones-images/cpp-simple-server:0.2
# imagePullPolicy: Always # add for development
2 changes: 1 addition & 1 deletion examples/cpp-simple/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ spec:
spec:
containers:
- name: cpp-simple
image: gcr.io/agones-images/cpp-simple-server:0.1
image: gcr.io/agones-images/cpp-simple-server:0.2
# imagePullPolicy: Always # add for development
12 changes: 12 additions & 0 deletions examples/cpp-simple/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,20 @@ int main() {
std::cout << "Could not run Ready(): "+ status.error_message() + ". Exiting!" << std::endl;
return -1;
}

std::cout << "...marked Ready" << std::endl;

std::cout << "Getting GameServer details..." << std::endl;
stable::agones::dev::sdk::GameServer gameserver;
status = sdk->GameServer(&gameserver);

if (!status.ok()) {
std::cout << "Could not run GameServer(): "+ status.error_message() + ". Exiting!" << std::endl;
return -1;
}

std::cout << "GameServer name: " << gameserver.object_meta().name() << std::endl;

for (int i = 0; i < 10; i++) {
int time = i*10;
std::cout << "Running for " + std::to_string(time) + " seconds !" << std::endl;
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/Makefile
Original file line number Diff line number Diff line change
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.1
server_tag = $(REPOSITORY)/udp-server:0.2
package = agones.dev/agones/examples/simple-udp

# _____ _
Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

FROM alpine:3.7

RUN adduser -D server
RUN adduser -D server

COPY ./bin/server /home/server/server

Expand Down
2 changes: 1 addition & 1 deletion examples/simple-udp/server/fleet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.1
image: gcr.io/agones-images/udp-server:0.2
2 changes: 1 addition & 1 deletion examples/simple-udp/server/gameserver-legacy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.1
image: gcr.io/agones-images/udp-server:0.2
2 changes: 1 addition & 1 deletion examples/simple-udp/server/gameserver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.1
image: gcr.io/agones-images/udp-server:0.2
2 changes: 1 addition & 1 deletion examples/simple-udp/server/gameserverset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ spec:
spec:
containers:
- name: simple-udp
image: gcr.io/agones-images/udp-server:0.1
image: gcr.io/agones-images/udp-server:0.2
24 changes: 24 additions & 0 deletions examples/simple-udp/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"time"

"agones.dev/agones/sdks/go"
"encoding/json"
coresdk "agones.dev/agones/pkg/sdk"
)

// main starts a UDP server that received 1024 byte sized packets at at time
Expand Down Expand Up @@ -86,6 +88,9 @@ func readWriteLoop(conn net.PacketConn, stop chan struct{}, s *sdk.SDK) {
// turns off the health pings
case "UNHEALTHY":
close(stop)

case "GAMESERVER":
writeGameServerName(s, conn, sender)
}

// echo it back
Expand All @@ -96,6 +101,25 @@ func readWriteLoop(conn net.PacketConn, stop chan struct{}, s *sdk.SDK) {
}
}

// writes the GameServer name to the connection UDP stream
func writeGameServerName(s *sdk.SDK, conn net.PacketConn, sender net.Addr) {
var gs *coresdk.GameServer
gs, err := s.GameServer()
if err != nil {
log.Fatalf("Could not retrieve GameServer: %v", err)
}
var j []byte
j, err = json.Marshal(gs)
if err != nil {
log.Fatalf("error mashalling GameServer to JSON: %v", err)
}
log.Printf("GameServer: %s \n", string(j))
msg := "NAME: " + gs.ObjectMeta.Name + "\n"
if _, err = conn.WriteTo([]byte(msg), sender); err != nil {
log.Fatalf("Could not write to udp stream: %v", err)
}
}

// doHealth sends the regular Health Pings
func doHealth(sdk *sdk.SDK, stop <-chan struct{}) {
tick := time.Tick(2 * time.Second)
Expand Down
2 changes: 1 addition & 1 deletion install/helm/agones/templates/serviceaccounts/sdk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ metadata:
rules:
- apiGroups: ["stable.agones.dev"]
resources: ["gameservers"]
verbs: ["get", "update"]
verbs: ["get", "list", "update"]
---
{{- range .Values.gameservers.namespaces }}
apiVersion: rbac.authorization.k8s.io/v1
Expand Down
2 changes: 1 addition & 1 deletion install/yaml/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ metadata:
rules:
- apiGroups: ["stable.agones.dev"]
resources: ["gameservers"]
verbs: ["get", "update"]
verbs: ["get", "list", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
Expand Down
26 changes: 26 additions & 0 deletions pkg/gameservers/localsdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package gameservers
import (
"io"

"time"

"agones.dev/agones/pkg/sdk"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -57,3 +59,27 @@ func (l *LocalSDKServer) Health(stream sdk.SDK_HealthServer) error {
logrus.Info("Health Ping Received!")
}
}

// GetGameServer returns a dummy game server.
func (l *LocalSDKServer) GetGameServer(context.Context, *sdk.Empty) (*sdk.GameServer, error) {
logrus.Info("getting GameServer details")
gs := &sdk.GameServer{
ObjectMeta: &sdk.GameServer_ObjectMeta{
Name: "local",
Namespace: "default",
Uid: "1234",
Generation: 1,
ResourceVersion: "v1",
CreationTimestamp: time.Now().Unix(),
Labels: map[string]string{"islocal": "true"},
Annotations: map[string]string{"annotation": "true"},
},
Status: &sdk.GameServer_Status{
State: "Ready",
Address: "127.0.0.1",
Ports: []*sdk.GameServer_Status_Port{{Name: "default", Port: 7777}},
},
}

return gs, nil
}
6 changes: 5 additions & 1 deletion pkg/gameservers/localsdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestLocal(t *testing.T) {
stream := newMockStream()

go func() {
err := l.Health(stream)
err = l.Health(stream)
assert.Nil(t, err)
wg.Done()
}()
Expand All @@ -48,4 +48,8 @@ func TestLocal(t *testing.T) {
close(stream.msgs)

wg.Wait()

gs, err := l.GetGameServer(ctx, e)
assert.Nil(t, err)
assert.Equal(t, "local", gs.GetObjectMeta().Name)
}
2 changes: 1 addition & 1 deletion pkg/gameservers/portallocator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ package gameservers

import (
"fmt"
"strconv"
"sync"
"testing"
"time"
"strconv"

"agones.dev/agones/pkg/apis/stable/v1alpha1"
agtesting "agones.dev/agones/pkg/testing"
Expand Down
76 changes: 75 additions & 1 deletion pkg/gameservers/sdkserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
stablev1alpha1 "agones.dev/agones/pkg/apis/stable/v1alpha1"
"agones.dev/agones/pkg/client/clientset/versioned"
typedv1alpha1 "agones.dev/agones/pkg/client/clientset/versioned/typed/stable/v1alpha1"
"agones.dev/agones/pkg/client/informers/externalversions"
"agones.dev/agones/pkg/client/listers/stable/v1alpha1"
"agones.dev/agones/pkg/sdk"
"agones.dev/agones/pkg/util/runtime"
"agones.dev/agones/pkg/util/workerqueue"
Expand All @@ -33,6 +35,7 @@ import (
"golang.org/x/net/context"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
Expand All @@ -50,7 +53,10 @@ type SDKServer struct {
logger *logrus.Entry
gameServerName string
namespace string
informerFactory externalversions.SharedInformerFactory
gameServerGetter typedv1alpha1.GameServersGetter
gameServerLister v1alpha1.GameServerLister
gameServerSynced cache.InformerSynced
server *http.Server
clock clock.Clock
healthDisabled bool
Expand All @@ -71,10 +77,19 @@ func NewSDKServer(gameServerName, namespace string,
agonesClient versioned.Interface) (*SDKServer, error) {
mux := http.NewServeMux()

// limit the informer to only working with the gameserver that the sdk is attached to
factory := externalversions.NewFilteredSharedInformerFactory(agonesClient, 30*time.Second, namespace, func(opts *metav1.ListOptions) {
s1 := fields.OneTermEqualSelector("metadata.name", gameServerName)
opts.FieldSelector = s1.String()
})
gameServers := factory.Stable().V1alpha1().GameServers()

s := &SDKServer{
gameServerName: gameServerName,
namespace: namespace,
gameServerGetter: agonesClient.StableV1alpha1(),
gameServerLister: gameServers.Lister(),
gameServerSynced: gameServers.Informer().HasSynced,
server: &http.Server{
Addr: ":8080",
Handler: mux,
Expand All @@ -87,6 +102,7 @@ func NewSDKServer(gameServerName, namespace string,
healthFailureCount: 0,
}

s.informerFactory = factory
s.logger = runtime.NewLoggerWithType(s)

eventBroadcaster := record.NewBroadcaster()
Expand Down Expand Up @@ -153,6 +169,9 @@ func (s *SDKServer) Run(stop <-chan struct{}) {
go wait.Until(s.runHealth, s.healthTimeout, stop)
}

s.informerFactory.Start(stop)
cache.WaitForCacheSync(stop, s.gameServerSynced)

s.workerqueue.Run(1, stop)
}

Expand All @@ -161,7 +180,7 @@ func (s *SDKServer) Run(stop <-chan struct{}) {
func (s *SDKServer) updateState(state stablev1alpha1.State) error {
s.logger.WithField("state", state).Info("Updating state")
gameServers := s.gameServerGetter.GameServers(s.namespace)
gs, err := gameServers.Get(s.gameServerName, metav1.GetOptions{})
gs, err := s.gameServerLister.GameServers(s.namespace).Get(s.gameServerName)
if err != nil {
return errors.Wrapf(err, "could not retrieve GameServer %s/%s", s.namespace, s.gameServerName)
}
Expand Down Expand Up @@ -216,6 +235,61 @@ func (s *SDKServer) Health(stream sdk.SDK_HealthServer) error {
}
}

// GetGameServer returns the current GameServer configuration and state from the backing GameServer CRD
func (s *SDKServer) GetGameServer(context.Context, *sdk.Empty) (*sdk.GameServer, error) {
gs, err := s.gameServerLister.GameServers(s.namespace).Get(s.gameServerName)
if err != nil {
return nil, errors.Wrapf(err, "error retrieving gameserver %s/%s", s.namespace, s.gameServerName)
}

return s.convert(gs), nil
}

// convert converts a K8s GameServer object, into a gRPC SDK GameServer object
func (s *SDKServer) convert(gs *stablev1alpha1.GameServer) *sdk.GameServer {
meta := gs.ObjectMeta
status := gs.Status
health := gs.Spec.Health
result := &sdk.GameServer{
ObjectMeta: &sdk.GameServer_ObjectMeta{
Name: meta.Name,
Namespace: meta.Namespace,
Uid: string(meta.UID),
ResourceVersion: meta.ResourceVersion,
Generation: meta.Generation,
CreationTimestamp: meta.CreationTimestamp.Unix(),
Annotations: meta.Annotations,
Labels: meta.Labels,
},
Spec: &sdk.GameServer_Spec{
Health: &sdk.GameServer_Spec_Health{
Disabled: health.Disabled,
PeriodSeconds: health.PeriodSeconds,
FailureThreshold: health.FailureThreshold,
InitialDelaySeconds: health.InitialDelaySeconds,
},
},
Status: &sdk.GameServer_Status{
State: string(status.State),
Address: status.Address,
},
}
if meta.DeletionTimestamp != nil {
result.ObjectMeta.DeletionTimestamp = meta.DeletionTimestamp.Unix()
}

// loop around and add all the ports
for _, p := range status.Ports {
grpcPort := &sdk.GameServer_Status_Port{
Name: p.Name,
Port: p.Port,
}
result.Status.Ports = append(result.Status.Ports, grpcPort)
}

return result
}

// runHealth actively checks the health, and if not
// healthy will push the Unhealthy state into the queue so
// it can be updated
Expand Down
Loading

0 comments on commit 5647b40

Please sign in to comment.