@@ -19,6 +19,7 @@ import (
1919 "net/http"
2020 "os"
2121 "path/filepath"
22+ "reflect"
2223 "strings"
2324 "time"
2425
@@ -43,21 +44,82 @@ import (
4344)
4445
4546const (
46- sidecarFlag = "sidecar"
47- pullSidecarFlag = "always-pull-sidecar"
48- minPortFlag = "min-port"
49- maxPortFlag = "max-port"
50- certFileFlag = "cert-file"
51- keyFileFlag = "key-file"
52- controllerThreadiness = 2
47+ sidecarFlag = "sidecar"
48+ pullSidecarFlag = "always-pull-sidecar"
49+ minPortFlag = "min-port"
50+ maxPortFlag = "max-port"
51+ certFileFlag = "cert-file"
52+ keyFileFlag = "key-file"
53+ workers = 2
54+ defaultResync = 30 * time .Second
5355)
5456
5557var (
5658 logger = runtime .NewLoggerWithSource ("main" )
5759)
5860
5961// main starts the operator for the gameserver CRD
60- func main () { // nolint: gocyclo
62+ func main () {
63+ ctlConf := parseEnvFlags ()
64+ if err := ctlConf .validate (); err != nil {
65+ logger .WithError (err ).Fatal ("Could not create controller from environment or flags" )
66+ }
67+
68+ clientConf , err := rest .InClusterConfig ()
69+ if err != nil {
70+ logger .WithError (err ).Fatal ("Could not create in cluster config" )
71+ }
72+
73+ kubeClient , err := kubernetes .NewForConfig (clientConf )
74+ if err != nil {
75+ logger .WithError (err ).Fatal ("Could not create the kubernetes clientset" )
76+ }
77+
78+ extClient , err := extclientset .NewForConfig (clientConf )
79+ if err != nil {
80+ logger .WithError (err ).Fatal ("Could not create the api extension clientset" )
81+ }
82+
83+ agonesClient , err := versioned .NewForConfig (clientConf )
84+ if err != nil {
85+ logger .WithError (err ).Fatal ("Could not create the agones api clientset" )
86+ }
87+
88+ health := healthcheck .NewHandler ()
89+ wh := webhooks .NewWebHook (ctlConf .certFile , ctlConf .keyFile )
90+ agonesInformerFactory := externalversions .NewSharedInformerFactory (agonesClient , defaultResync )
91+ kubeInformationFactory := informers .NewSharedInformerFactory (kubeClient , defaultResync )
92+
93+ gsController := gameservers .NewController (wh , health ,
94+ ctlConf .minPort , ctlConf .maxPort , ctlConf .sidecarImage , ctlConf .alwaysPullSidecar ,
95+ kubeClient , kubeInformationFactory , extClient , agonesClient , agonesInformerFactory )
96+ gsSetController := gameserversets .NewController (wh , health ,
97+ kubeClient , extClient , agonesClient , agonesInformerFactory )
98+ fleetController := fleets .NewController (wh , health ,
99+ kubeClient , extClient , agonesClient , agonesInformerFactory )
100+ faController := fleetallocation .NewController (wh , kubeClient , extClient , agonesClient , agonesInformerFactory )
101+
102+ stop := signals .NewStopChannel ()
103+
104+ kubeInformationFactory .Start (stop )
105+ agonesInformerFactory .Start (stop )
106+
107+ rs := []runner {
108+ wh , gsController , gsSetController , fleetController , faController , healthServer {handler : health },
109+ }
110+ for _ , r := range rs {
111+ go func (rr runner ) {
112+ if runErr := rr .Run (workers , stop ); runErr != nil {
113+ logger .WithError (runErr ).Fatalf ("could not start runner: %s" , reflect .TypeOf (rr ))
114+ }
115+ }(r )
116+ }
117+
118+ <- stop
119+ logger .Info ("Shut down agones controllers" )
120+ }
121+
122+ func parseEnvFlags () config {
61123 exec , err := os .Executable ()
62124 if err != nil {
63125 logger .WithError (err ).Fatal ("Could not get executable path" )
@@ -101,95 +163,60 @@ func main() { // nolint: gocyclo
101163 WithField ("alwaysPullSidecarImage" , alwaysPullSidecar ).
102164 WithField ("Version" , pkg .Version ).Info ("starting gameServer operator..." )
103165
104- if minPort <= 0 || maxPort <= 0 {
105- logger .Fatal ("Min Port and Max Port values are required." )
106- } else if maxPort < minPort {
107- logger .Fatal ("Max Port cannot be set less that the Min Port" )
108- }
109-
110- config , err := rest .InClusterConfig ()
111- if err != nil {
112- logger .WithError (err ).Fatal ("Could not create in cluster config" )
166+ return config {
167+ minPort : minPort ,
168+ maxPort : maxPort ,
169+ sidecarImage : sidecarImage ,
170+ alwaysPullSidecar : alwaysPullSidecar ,
171+ keyFile : keyFile ,
172+ certFile : certFile ,
113173 }
174+ }
114175
115- kubeClient , err := kubernetes .NewForConfig (config )
116- if err != nil {
117- logger .WithError (err ).Fatal ("Could not create the kubernetes clientset" )
118- }
176+ // config stores all required configuration to create a game server controller.
177+ type config struct {
178+ minPort int32
179+ maxPort int32
180+ sidecarImage string
181+ alwaysPullSidecar bool
182+ keyFile string
183+ certFile string
184+ }
119185
120- extClient , err := extclientset .NewForConfig (config )
121- if err != nil {
122- logger .WithError (err ).Fatal ("Could not create the api extension clientset" )
186+ // validate ensures the ctlConfig data is valid.
187+ func (c config ) validate () error {
188+ if c .minPort <= 0 || c .maxPort <= 0 {
189+ return errors .New ("min Port and Max Port values are required" )
123190 }
124-
125- agonesClient , err := versioned .NewForConfig (config )
126- if err != nil {
127- logger .WithError (err ).Fatal ("Could not create the agones api clientset" )
191+ if c .maxPort < c .minPort {
192+ return errors .New ("max Port cannot be set less that the Min Port" )
128193 }
194+ return nil
195+ }
129196
130- health := healthcheck .NewHandler ()
131- wh := webhooks .NewWebHook (certFile , keyFile )
132- agonesInformerFactory := externalversions .NewSharedInformerFactory (agonesClient , 30 * time .Second )
133- kubeInformationFactory := informers .NewSharedInformerFactory (kubeClient , 30 * time .Second )
134-
135- gsController := gameservers .NewController (wh , health , minPort , maxPort , sidecarImage , alwaysPullSidecar , kubeClient , kubeInformationFactory , extClient , agonesClient , agonesInformerFactory )
136- gsSetController := gameserversets .NewController (wh , health , kubeClient , extClient , agonesClient , agonesInformerFactory )
137- fleetController := fleets .NewController (wh , health , kubeClient , extClient , agonesClient , agonesInformerFactory )
138- faController := fleetallocation .NewController (wh , kubeClient , extClient , agonesClient , agonesInformerFactory )
139-
140- stop := signals .NewStopChannel ()
141-
142- kubeInformationFactory .Start (stop )
143- agonesInformerFactory .Start (stop )
197+ type runner interface {
198+ Run (workers int , stop <- chan struct {}) error
199+ }
144200
145- go func () {
146- if err := wh .Run (stop ); err != nil { // nolint: vetshadow
147- logger .WithError (err ).Fatal ("could not run webhook server" )
148- }
149- }()
150- go func () {
151- err = gsController .Run (controllerThreadiness , stop )
152- if err != nil {
153- logger .WithError (err ).Fatal ("Could not run gameserver controller" )
154- }
155- }()
156- go func () {
157- err = gsSetController .Run (controllerThreadiness , stop )
158- if err != nil {
159- logger .WithError (err ).Fatal ("Could not run gameserverset controller" )
160- }
161- }()
162- go func () {
163- err = fleetController .Run (controllerThreadiness , stop )
164- if err != nil {
165- logger .WithError (err ).Fatal ("Could not run fleet controller" )
166- }
167- }()
168- go func () {
169- err = faController .Run (stop )
170- if err != nil {
171- logger .WithError (err ).Fatal ("Could not run fleet controller" )
172- }
173- }()
201+ type healthServer struct {
202+ handler http.Handler
203+ }
174204
175- go func () {
176- logger .Info ("Starting health check..." )
177- srv := & http.Server {
178- Addr : ":8080" ,
179- Handler : health ,
180- }
181- defer srv .Close () // nolint: errcheck
182-
183- if err := srv .ListenAndServe (); err != nil {
184- if err == http .ErrServerClosed {
185- logger .WithError (err ).Info ("health check: http server closed" )
186- } else {
187- err := errors .Wrap (err , "Could not listen on :8080" )
188- runtime .HandleError (logger .WithError (err ), err )
189- }
205+ func (h healthServer ) Run (workers int , stop <- chan struct {}) error {
206+ logger .Info ("Starting health check..." )
207+ srv := & http.Server {
208+ Addr : ":8080" ,
209+ Handler : h .handler ,
210+ }
211+ defer srv .Close () // nolint: errcheck
212+
213+ if err := srv .ListenAndServe (); err != nil {
214+ if err == http .ErrServerClosed {
215+ logger .WithError (err ).Info ("health check: http server closed" )
216+ } else {
217+ wrappedErr := errors .Wrap (err , "Could not listen on :8080" )
218+ runtime .HandleError (logger .WithError (wrappedErr ), wrappedErr )
190219 }
191- }()
192-
193- <- stop
194- logger .Info ("Shut down agones controllers" )
220+ }
221+ return nil
195222}
0 commit comments