Skip to content

Commit f414b2b

Browse files
committed
Fix bug: Disabled health checking not implemented
This commit fixes actually two bugs: 1) While we documented that you could disabled health checking we never actually implemented it! This fixes that. Thankfully, the work that has been done to retrieve `GameServer` details through the SDK makes this relatively easy. 2) SDK Server sidecar never had the necessary RBAC permissions to send events to the `GameServer` CRD. This is now fixed as well.
1 parent d5062ce commit f414b2b

5 files changed

Lines changed: 146 additions & 119 deletions

File tree

cmd/sdk-server/main.go

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"net"
2121
"net/http"
2222
"strings"
23-
"time"
2423

2524
"agones.dev/agones/pkg"
2625
"agones.dev/agones/pkg/client/clientset/versioned"
@@ -46,12 +45,8 @@ const (
4645
podNamespaceEnv = "POD_NAMESPACE"
4746

4847
// Flags (that can also be env vars)
49-
localFlag = "local"
50-
addressFlag = "address"
51-
healthDisabledFlag = "health-disabled"
52-
healthTimeoutFlag = "health-timeout"
53-
healthInitialDelayFlag = "health-initial-delay"
54-
healthFailureThresholdFlag = "health-failure-threshold"
48+
localFlag = "local"
49+
addressFlag = "address"
5550
)
5651

5752
var (
@@ -107,14 +102,18 @@ func main() {
107102
}
108103

109104
var s *gameservers.SDKServer
110-
s, err = gameservers.NewSDKServer(viper.GetString(gameServerNameEnv), viper.GetString(podNamespaceEnv),
111-
ctlConf.HealthDisabled, ctlConf.HealthTimeout, ctlConf.HealthFailureThreshold,
112-
ctlConf.HealthInitialDelay, kubeClient, agonesClient)
105+
s, err = gameservers.NewSDKServer(viper.GetString(gameServerNameEnv),
106+
viper.GetString(podNamespaceEnv), kubeClient, agonesClient)
113107
if err != nil {
114108
logger.WithError(err).Fatalf("Could not start sidecar")
115109
}
116110

117-
go s.Run(ctx.Done())
111+
go func() {
112+
err := s.Run(ctx.Done())
113+
if err != nil {
114+
logger.WithError(err).Fatalf("Could not run sidecar")
115+
}
116+
}()
118117
sdk.RegisterSDKServer(grpcServer, s)
119118
}
120119

@@ -159,49 +158,25 @@ func runGateway(ctx context.Context, grpcEndpoint string, mux *gwruntime.ServeMu
159158
func parseEnvFlags() config {
160159
viper.SetDefault(localFlag, false)
161160
viper.SetDefault(addressFlag, "localhost")
162-
viper.SetDefault(healthDisabledFlag, false)
163-
viper.SetDefault(healthTimeoutFlag, 5)
164-
viper.SetDefault(healthInitialDelayFlag, 5)
165-
viper.SetDefault(healthFailureThresholdFlag, 3)
166161
pflag.Bool(localFlag, viper.GetBool(localFlag),
167162
"Set this, or LOCAL env, to 'true' to run this binary in local development mode. Defaults to 'false'")
168163
pflag.String(addressFlag, viper.GetString(addressFlag), "The Address to bind the server grpcPort to. Defaults to 'localhost")
169-
pflag.Bool(healthDisabledFlag, viper.GetBool(healthDisabledFlag),
170-
"Set this, or HEALTH_ENABLED env, to 'true' to enable health checking on the GameServer. Defaults to 'true'")
171-
pflag.Int64(healthTimeoutFlag, viper.GetInt64(healthTimeoutFlag),
172-
"Set this or HEALTH_TIMEOUT env to the number of seconds that the health check times out at. Defaults to 5")
173-
pflag.Int64(healthInitialDelayFlag, viper.GetInt64(healthInitialDelayFlag),
174-
"Set this or HEALTH_INITIAL_DELAY env to the number of seconds that the health will wait before starting. Defaults to 5")
175-
pflag.Int64(healthFailureThresholdFlag, viper.GetInt64(healthFailureThresholdFlag),
176-
"Set this or HEALTH_FAILURE_THRESHOLD env to the number of times the health check needs to fail to be deemed unhealthy. Defaults to 3")
177164
pflag.Parse()
178165

179166
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
180167
runtime.Must(viper.BindEnv(localFlag))
181168
runtime.Must(viper.BindEnv(gameServerNameEnv))
182169
runtime.Must(viper.BindEnv(podNamespaceEnv))
183-
runtime.Must(viper.BindEnv(healthDisabledFlag))
184-
runtime.Must(viper.BindEnv(healthTimeoutFlag))
185-
runtime.Must(viper.BindEnv(healthInitialDelayFlag))
186-
runtime.Must(viper.BindEnv(healthFailureThresholdFlag))
187170
runtime.Must(viper.BindPFlags(pflag.CommandLine))
188171

189172
return config{
190-
IsLocal: viper.GetBool(localFlag),
191-
Address: viper.GetString(addressFlag),
192-
HealthDisabled: viper.GetBool(healthDisabledFlag),
193-
HealthTimeout: time.Duration(viper.GetInt64(healthTimeoutFlag)) * time.Second,
194-
HealthInitialDelay: time.Duration(viper.GetInt64(healthInitialDelayFlag)) * time.Second,
195-
HealthFailureThreshold: viper.GetInt64(healthFailureThresholdFlag),
173+
IsLocal: viper.GetBool(localFlag),
174+
Address: viper.GetString(addressFlag),
196175
}
197176
}
198177

199178
// config is all the configuration for this program
200179
type config struct {
201-
Address string
202-
IsLocal bool
203-
HealthDisabled bool
204-
HealthTimeout time.Duration
205-
HealthInitialDelay time.Duration
206-
HealthFailureThreshold int64
180+
Address string
181+
IsLocal bool
207182
}

install/helm/agones/templates/serviceaccounts/sdk.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ metadata:
3636
release: {{ .Release.Name }}
3737
heritage: {{ .Release.Service }}
3838
rules:
39+
- apiGroups: [""]
40+
resources: ["events"]
41+
verbs: ["create"]
3942
- apiGroups: ["stable.agones.dev"]
4043
resources: ["gameservers"]
4144
verbs: ["list", "update", "watch"]

install/yaml/install.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ metadata:
111111
release: agones-manual
112112
heritage: Tiller
113113
rules:
114+
- apiGroups: [""]
115+
resources: ["events"]
116+
verbs: ["create"]
114117
- apiGroups: ["stable.agones.dev"]
115118
resources: ["gameservers"]
116119
verbs: ["list", "update", "watch"]

pkg/gameservers/sdkserver.go

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -50,33 +50,30 @@ var _ sdk.SDKServer = &SDKServer{}
5050
// SDKServer is a gRPC server, that is meant to be a sidecar
5151
// for a GameServer that will update the game server status on SDK requests
5252
type SDKServer struct {
53-
logger *logrus.Entry
54-
gameServerName string
55-
namespace string
56-
informerFactory externalversions.SharedInformerFactory
57-
gameServerGetter typedv1alpha1.GameServersGetter
58-
gameServerLister v1alpha1.GameServerLister
59-
gameServerSynced cache.InformerSynced
60-
server *http.Server
61-
clock clock.Clock
62-
healthDisabled bool
63-
healthTimeout time.Duration
64-
healthFailureThreshold int64
65-
healthMutex sync.RWMutex
66-
healthLastUpdated time.Time
67-
healthFailureCount int64
68-
workerqueue *workerqueue.WorkerQueue
69-
streamMutex sync.RWMutex
70-
connectedStreams []sdk.SDK_WatchGameServerServer
71-
stop <-chan struct{}
72-
recorder record.EventRecorder
53+
logger *logrus.Entry
54+
gameServerName string
55+
namespace string
56+
informerFactory externalversions.SharedInformerFactory
57+
gameServerGetter typedv1alpha1.GameServersGetter
58+
gameServerLister v1alpha1.GameServerLister
59+
gameServerSynced cache.InformerSynced
60+
server *http.Server
61+
clock clock.Clock
62+
health stablev1alpha1.Health
63+
healthTimeout time.Duration
64+
healthMutex sync.RWMutex
65+
healthLastUpdated time.Time
66+
healthFailureCount int32
67+
workerqueue *workerqueue.WorkerQueue
68+
streamMutex sync.RWMutex
69+
connectedStreams []sdk.SDK_WatchGameServerServer
70+
stop <-chan struct{}
71+
recorder record.EventRecorder
7372
}
7473

7574
// NewSDKServer creates a SDKServer that sets up an
7675
// InClusterConfig for Kubernetes
77-
func NewSDKServer(gameServerName, namespace string,
78-
healthDisabled bool, healthTimeout time.Duration, healthFailureThreshold int64, healthInitialDelay time.Duration,
79-
kubeClient kubernetes.Interface,
76+
func NewSDKServer(gameServerName, namespace string, kubeClient kubernetes.Interface,
8077
agonesClient versioned.Interface) (*SDKServer, error) {
8178
mux := http.NewServeMux()
8279

@@ -97,13 +94,10 @@ func NewSDKServer(gameServerName, namespace string,
9794
Addr: ":8080",
9895
Handler: mux,
9996
},
100-
clock: clock.RealClock{},
101-
healthDisabled: healthDisabled,
102-
healthFailureThreshold: healthFailureThreshold,
103-
healthTimeout: healthTimeout,
104-
healthMutex: sync.RWMutex{},
105-
healthFailureCount: 0,
106-
streamMutex: sync.RWMutex{},
97+
clock: clock.RealClock{},
98+
healthMutex: sync.RWMutex{},
99+
healthFailureCount: 0,
100+
streamMutex: sync.RWMutex{},
107101
}
108102

109103
s.informerFactory = factory
@@ -140,7 +134,6 @@ func NewSDKServer(gameServerName, namespace string,
140134
}
141135
})
142136

143-
s.initHealthLastUpdated(healthInitialDelay)
144137
s.workerqueue = workerqueue.NewWorkerQueue(
145138
func(key string) error {
146139
return s.updateState(stablev1alpha1.State(key))
@@ -161,7 +154,28 @@ func (s *SDKServer) initHealthLastUpdated(healthInitialDelay time.Duration) {
161154

162155
// Run processes the rate limited queue.
163156
// Will block until stop is closed
164-
func (s *SDKServer) Run(stop <-chan struct{}) {
157+
func (s *SDKServer) Run(stop <-chan struct{}) error {
158+
s.informerFactory.Start(stop)
159+
cache.WaitForCacheSync(stop, s.gameServerSynced)
160+
161+
gs, err := s.gameServerLister.GameServers(s.namespace).Get(s.gameServerName)
162+
if err != nil {
163+
return errors.Wrapf(err, "error retrieving gameserver %s/%s", s.namespace, s.gameServerName)
164+
}
165+
166+
// grab configuration details
167+
s.health = gs.Spec.Health
168+
s.logger.WithField("health", s.health).Info("setting health configuration")
169+
s.healthTimeout = time.Duration(gs.Spec.Health.PeriodSeconds) * time.Second
170+
s.initHealthLastUpdated(time.Duration(gs.Spec.Health.InitialDelaySeconds) * time.Second)
171+
172+
// start health checking running
173+
if !s.health.Disabled {
174+
s.logger.Info("Starting GameServer health checking")
175+
go wait.Until(s.runHealth, s.healthTimeout, stop)
176+
}
177+
178+
// then start the http endpoints
165179
s.logger.Info("Starting SDKServer http health check...")
166180
go func() {
167181
if err := s.server.ListenAndServe(); err != nil {
@@ -175,16 +189,10 @@ func (s *SDKServer) Run(stop <-chan struct{}) {
175189
}()
176190
defer s.server.Close() // nolint: errcheck
177191

178-
if !s.healthDisabled {
179-
s.logger.Info("Starting GameServer health checking")
180-
go wait.Until(s.runHealth, s.healthTimeout, stop)
181-
}
182-
183-
s.informerFactory.Start(stop)
184-
cache.WaitForCacheSync(stop, s.gameServerSynced)
185192
// need this for streaming gRPC commands
186193
s.stop = stop
187194
s.workerqueue.Run(1, stop)
195+
return nil
188196
}
189197

190198
// updateState sets the GameServer Status's state to the state
@@ -371,11 +379,11 @@ func (s *SDKServer) checkHealth() {
371379
// currently healthy or not based on the configured
372380
// failure count vs failure threshold
373381
func (s *SDKServer) healthy() bool {
374-
if s.healthDisabled {
382+
if s.health.Disabled {
375383
return true
376384
}
377385

378386
s.healthMutex.RLock()
379387
defer s.healthMutex.RUnlock()
380-
return s.healthFailureCount < s.healthFailureThreshold
388+
return s.healthFailureCount < s.health.FailureThreshold
381389
}

0 commit comments

Comments
 (0)