agones.dev/agones@v1.53.0/pkg/gameserverallocations/allocation_cache_test.go (about) 1 // Copyright 2021 Google LLC All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gameserverallocations 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 "time" 22 23 agonesv1 "agones.dev/agones/pkg/apis/agones/v1" 24 allocationv1 "agones.dev/agones/pkg/apis/allocation/v1" 25 "agones.dev/agones/pkg/gameservers" 26 agtesting "agones.dev/agones/pkg/testing" 27 "agones.dev/agones/pkg/util/runtime" 28 "github.com/heptiolabs/healthcheck" 29 "github.com/sirupsen/logrus" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 k8sruntime "k8s.io/apimachinery/pkg/runtime" 34 "k8s.io/apimachinery/pkg/util/wait" 35 "k8s.io/apimachinery/pkg/watch" 36 k8stesting "k8s.io/client-go/testing" 37 ) 38 39 func TestAllocationCacheListSortedGameServers(t *testing.T) { 40 t.Parallel() 41 runtime.FeatureTestMutex.Lock() 42 defer runtime.FeatureTestMutex.Unlock() 43 44 gs1 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, UID: "1"}, 45 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}} 46 gs2 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, UID: "2"}, 47 Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}} 48 gs3 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, UID: "3"}, 49 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}} 50 gs4 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, UID: "4"}, 51 Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}} 52 gs5 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, UID: "5"}, 53 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 54 Players: &agonesv1.PlayerStatus{ 55 Count: 0, 56 Capacity: 10, 57 }, 58 Counters: map[string]agonesv1.CounterStatus{ 59 "players": { 60 Count: 4, 61 Capacity: 40, // Available Capacity == 36 62 }, 63 }}, 64 } 65 gs6 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, UID: "6"}, 66 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, Players: &agonesv1.PlayerStatus{ 67 Count: 2, 68 Capacity: 10, 69 }, 70 Counters: map[string]agonesv1.CounterStatus{ 71 "players": { 72 Count: 14, 73 Capacity: 40, // Available Capacity == 26 74 }, 75 }}, 76 } 77 78 fixtures := map[string]struct { 79 list []agonesv1.GameServer 80 test func(*testing.T, []*agonesv1.GameServer) 81 features string 82 gsa *allocationv1.GameServerAllocation 83 }{ 84 "allocated first (StateAllocationFilter)": { 85 list: []agonesv1.GameServer{gs1, gs2, gs3}, 86 test: func(t *testing.T, list []*agonesv1.GameServer) { 87 assert.Equal(t, []*agonesv1.GameServer{&gs3, &gs1, &gs2}, list) 88 }, 89 }, 90 "nil player status (PlayerAllocationFilter)": { 91 list: []agonesv1.GameServer{gs1, gs2, gs4}, 92 features: fmt.Sprintf("%s=true", runtime.FeaturePlayerAllocationFilter), 93 test: func(t *testing.T, list []*agonesv1.GameServer) { 94 require.Len(t, list, 3) 95 // first two items can come in any order 96 assert.ElementsMatchf(t, []*agonesv1.GameServer{&gs2, &gs4}, list[:2], "GameServer Names") 97 assert.Equal(t, &gs1, list[2]) 98 }, 99 }, 100 "least player capacity (PlayerAllocationFilter)": { 101 list: []agonesv1.GameServer{gs5, gs6}, 102 features: fmt.Sprintf("%s=true", runtime.FeaturePlayerAllocationFilter), 103 test: func(t *testing.T, list []*agonesv1.GameServer) { 104 assert.Equal(t, []*agonesv1.GameServer{&gs6, &gs5}, list) 105 }, 106 }, 107 "list ready": { 108 // node1: 1 ready, node2: 2 ready 109 list: []agonesv1.GameServer{gs1, gs2, gs4}, 110 test: func(t *testing.T, list []*agonesv1.GameServer) { 111 assert.Len(t, list, 3) 112 // first two items can come in any order 113 assert.ElementsMatchf(t, []*agonesv1.GameServer{&gs2, &gs4}, list[:2], "GameServer Names") 114 assert.Equal(t, &gs1, list[2]) 115 }, 116 }, 117 "lexicographical (node name)": { 118 list: []agonesv1.GameServer{gs2, gs1}, 119 test: func(t *testing.T, list []*agonesv1.GameServer) { 120 assert.Len(t, list, 2) 121 if !assert.Equal(t, []*agonesv1.GameServer{&gs1, &gs2}, list) { 122 for _, gs := range list { 123 logrus.WithField("name", gs.Name).Info("game server") 124 } 125 } 126 }, 127 }, 128 "counters Descending": { 129 list: []agonesv1.GameServer{gs1, gs2, gs3, gs4, gs5, gs6}, 130 features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists), 131 gsa: &allocationv1.GameServerAllocation{ 132 Spec: allocationv1.GameServerAllocationSpec{ 133 Priorities: []agonesv1.Priority{ 134 { 135 Type: "Counter", 136 Key: "players", 137 Order: "Descending", 138 }, 139 }, 140 }, 141 }, 142 test: func(t *testing.T, list []*agonesv1.GameServer) { 143 assert.Len(t, list, 6) 144 if !assert.Equal(t, []*agonesv1.GameServer{&gs3, &gs5, &gs6, &gs1, &gs2, &gs4}, list) { 145 for _, gs := range list { 146 logrus.WithField("game", gs.Name).Info("game server") 147 } 148 } 149 }, 150 }, 151 "counters Ascending": { 152 list: []agonesv1.GameServer{gs1, gs2, gs3, gs4, gs5, gs6}, 153 features: fmt.Sprintf("%s=true", runtime.FeatureCountsAndLists), 154 gsa: &allocationv1.GameServerAllocation{ 155 Spec: allocationv1.GameServerAllocationSpec{ 156 Priorities: []agonesv1.Priority{ 157 { 158 Type: "Counter", 159 Key: "players", 160 Order: "Ascending", 161 }, 162 }, 163 }, 164 }, 165 test: func(t *testing.T, list []*agonesv1.GameServer) { 166 assert.Len(t, list, 6) 167 if !assert.Equal(t, []*agonesv1.GameServer{&gs3, &gs6, &gs5, &gs1, &gs2, &gs4}, list) { 168 for _, gs := range list { 169 logrus.WithField("game", gs.Name).Info("game server") 170 } 171 } 172 }, 173 }, 174 } 175 176 for k, v := range fixtures { 177 t.Run(k, func(t *testing.T) { 178 // deliberately not resetting the Feature state, to catch any possible unknown regressions with the 179 // new feature flags 180 if v.features != "" { 181 require.NoError(t, runtime.ParseFeatures(v.features)) 182 } 183 184 cache, m := newFakeAllocationCache() 185 186 gsList := v.list 187 188 m.AgonesClient.AddReactor("list", "gameservers", func(_ k8stesting.Action) (bool, k8sruntime.Object, error) { 189 return true, &agonesv1.GameServerList{Items: gsList}, nil 190 }) 191 192 ctx, cancel := agtesting.StartInformers(m, cache.gameServerSynced) 193 defer cancel() 194 195 // This call initializes the cache 196 err := cache.syncCache() 197 assert.Nil(t, err) 198 199 err = cache.counter.Run(ctx, 0) 200 assert.Nil(t, err) 201 202 list := cache.ListSortedGameServers(v.gsa) 203 204 v.test(t, list) 205 }) 206 } 207 } 208 209 func TestListSortedGameServersPriorities(t *testing.T) { 210 t.Parallel() 211 runtime.FeatureTestMutex.Lock() 212 defer runtime.FeatureTestMutex.Unlock() 213 assert.NoError(t, runtime.ParseFeatures(string(runtime.FeatureCountsAndLists)+"=true")) 214 215 gs1 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, UID: "1"}, 216 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 217 Lists: map[string]agonesv1.ListStatus{ 218 "players": { 219 Values: []string{"player1"}, 220 Capacity: 100, // Available Capacity == 99 221 }, 222 "layers": { 223 Values: []string{"layer1", "layer2", "layer3"}, 224 Capacity: 100, // Available Capacity == 97 225 }}}} 226 gs2 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, UID: "2"}, 227 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 228 Lists: map[string]agonesv1.ListStatus{ 229 "players": { 230 Values: []string{}, 231 Capacity: 100, // Available Capacity == 100 232 }, 233 }, 234 Counters: map[string]agonesv1.CounterStatus{ 235 "assets": { 236 Count: 101, 237 Capacity: 1000, // Available Capacity = 899 238 }, 239 }}} 240 gs3 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, UID: "3"}, 241 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 242 Lists: map[string]agonesv1.ListStatus{ 243 "players": { 244 Values: []string{"player2", "player3"}, 245 Capacity: 100, // Available Capacity == 98 246 }}, 247 Counters: map[string]agonesv1.CounterStatus{ 248 "sessions": { 249 Count: 9, 250 Capacity: 1000, // Available Capacity == 991 251 }, 252 "assets": { 253 Count: 100, 254 Capacity: 1000, // Available Capacity == 900 255 }, 256 }}} 257 gs4 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, UID: "4"}, 258 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 259 Counters: map[string]agonesv1.CounterStatus{ 260 "sessions": { 261 Count: 99, 262 Capacity: 1000, // Available Capacity == 901 263 }, 264 }, 265 Lists: map[string]agonesv1.ListStatus{ 266 "players": { 267 Values: []string{"player4"}, 268 Capacity: 100, // Available Capacity == 99 269 }, 270 "layers": { 271 Values: []string{"layer4, layer5"}, 272 Capacity: 100, // Available Capacity == 98 273 }}}} 274 gs5 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, UID: "5"}, 275 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 276 Counters: map[string]agonesv1.CounterStatus{ 277 "sessions": { 278 Count: 9, 279 Capacity: 1000, // Available Capacity == 991 280 }, 281 "assets": { 282 Count: 99, 283 Capacity: 1000, // Available Capacity == 901 284 }, 285 }, 286 Lists: map[string]agonesv1.ListStatus{ 287 "layers": { 288 Values: []string{}, 289 Capacity: 100, // Available Capacity == 100 290 }}}} 291 gs6 := agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, UID: "6"}, 292 Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady, 293 Counters: map[string]agonesv1.CounterStatus{ 294 "sessions": { 295 Count: 999, 296 Capacity: 1000, // Available Capacity == 1 297 }, 298 }}} 299 300 testScenarios := map[string]struct { 301 list []agonesv1.GameServer 302 gsa *allocationv1.GameServerAllocation 303 want []*agonesv1.GameServer 304 }{ 305 "Sort by one Priority Counter Ascending": { 306 list: []agonesv1.GameServer{gs4, gs5, gs6}, 307 gsa: &allocationv1.GameServerAllocation{ 308 Spec: allocationv1.GameServerAllocationSpec{ 309 Priorities: []agonesv1.Priority{ 310 { 311 Type: "Counter", 312 Key: "sessions", 313 Order: "Ascending", 314 }, 315 }, 316 }, 317 }, 318 want: []*agonesv1.GameServer{&gs6, &gs4, &gs5}, 319 }, 320 "Sort by one Priority Counter Descending": { 321 list: []agonesv1.GameServer{gs4, gs5, gs6}, 322 gsa: &allocationv1.GameServerAllocation{ 323 Spec: allocationv1.GameServerAllocationSpec{ 324 Priorities: []agonesv1.Priority{ 325 { 326 Type: "Counter", 327 Key: "sessions", 328 Order: "Descending", 329 }, 330 }, 331 }, 332 }, 333 want: []*agonesv1.GameServer{&gs5, &gs4, &gs6}, 334 }, 335 "Sort by two Priority Counter Ascending and Ascending": { 336 list: []agonesv1.GameServer{gs3, gs5, gs6, gs4, gs1, gs2}, 337 gsa: &allocationv1.GameServerAllocation{ 338 Spec: allocationv1.GameServerAllocationSpec{ 339 Priorities: []agonesv1.Priority{ 340 { 341 Type: "Counter", 342 Key: "sessions", 343 Order: "Ascending", 344 }, 345 { 346 Type: "Counter", 347 Key: "assets", 348 Order: "Ascending", 349 }, 350 }, 351 }, 352 }, 353 want: []*agonesv1.GameServer{&gs6, &gs4, &gs3, &gs5, &gs2, &gs1}, 354 }, 355 "Sort by two Priority Counter Ascending and Descending": { 356 list: []agonesv1.GameServer{gs3, gs5, gs6, gs4, gs1, gs2}, 357 gsa: &allocationv1.GameServerAllocation{ 358 Spec: allocationv1.GameServerAllocationSpec{ 359 Priorities: []agonesv1.Priority{ 360 { 361 Type: "Counter", 362 Key: "sessions", 363 Order: "Ascending", 364 }, 365 { 366 Type: "Counter", 367 Key: "assets", 368 Order: "Descending", 369 }, 370 }, 371 }, 372 }, 373 want: []*agonesv1.GameServer{&gs6, &gs4, &gs5, &gs3, &gs2, &gs1}, 374 }, 375 "Sort by one Priority Counter game server without Counter": { 376 list: []agonesv1.GameServer{gs1, gs5, gs6, gs4}, 377 gsa: &allocationv1.GameServerAllocation{ 378 Spec: allocationv1.GameServerAllocationSpec{ 379 Priorities: []agonesv1.Priority{ 380 { 381 Type: "Counter", 382 Key: "sessions", 383 Order: "Ascending", 384 }, 385 }, 386 }, 387 }, 388 want: []*agonesv1.GameServer{&gs6, &gs4, &gs5, &gs1}, 389 }, 390 "Sort by one Priority List Ascending": { 391 list: []agonesv1.GameServer{gs3, gs2, gs1}, 392 gsa: &allocationv1.GameServerAllocation{ 393 Spec: allocationv1.GameServerAllocationSpec{ 394 Priorities: []agonesv1.Priority{ 395 { 396 Type: "List", 397 Key: "players", 398 Order: "Ascending", 399 }, 400 }, 401 }, 402 }, 403 want: []*agonesv1.GameServer{&gs3, &gs1, &gs2}, 404 }, 405 "Sort by one Priority List Descending": { 406 list: []agonesv1.GameServer{gs3, gs2, gs1}, 407 gsa: &allocationv1.GameServerAllocation{ 408 Spec: allocationv1.GameServerAllocationSpec{ 409 Priorities: []agonesv1.Priority{ 410 { 411 Type: "List", 412 Key: "players", 413 Order: "Descending", 414 }, 415 }, 416 }, 417 }, 418 want: []*agonesv1.GameServer{&gs2, &gs1, &gs3}, 419 }, 420 "Sort by two Priority List Descending and Ascending": { 421 list: []agonesv1.GameServer{gs1, gs2, gs3, gs4}, 422 gsa: &allocationv1.GameServerAllocation{ 423 Spec: allocationv1.GameServerAllocationSpec{ 424 Priorities: []agonesv1.Priority{ 425 { 426 Type: "List", 427 Key: "players", 428 Order: "Descending", 429 }, 430 { 431 Type: "List", 432 Key: "layers", 433 Order: "Ascending", 434 }, 435 }, 436 }, 437 }, 438 want: []*agonesv1.GameServer{&gs2, &gs1, &gs4, &gs3}, 439 }, 440 "Sort by two Priority List Descending and Descending": { 441 list: []agonesv1.GameServer{gs6, gs5, gs4, gs3, gs2, gs1}, 442 gsa: &allocationv1.GameServerAllocation{ 443 Spec: allocationv1.GameServerAllocationSpec{ 444 Priorities: []agonesv1.Priority{ 445 { 446 Type: "List", 447 Key: "players", 448 Order: "Descending", 449 }, 450 { 451 Type: "List", 452 Key: "layers", 453 Order: "Descending", 454 }, 455 }, 456 }, 457 }, 458 want: []*agonesv1.GameServer{&gs2, &gs4, &gs1, &gs3, &gs5, &gs6}, 459 }, 460 "Sort lexigraphically as no game server has the priority": { 461 list: []agonesv1.GameServer{gs6, gs5, gs4, gs3, gs2, gs1}, 462 gsa: &allocationv1.GameServerAllocation{ 463 Spec: allocationv1.GameServerAllocationSpec{ 464 Priorities: []agonesv1.Priority{ 465 { 466 Type: "Counter", 467 Key: "sayers", 468 Order: "Ascending", 469 }, 470 }, 471 }, 472 }, 473 want: []*agonesv1.GameServer{&gs1, &gs2, &gs3, &gs4, &gs5, &gs6}, 474 }, 475 } 476 477 for testName, testScenario := range testScenarios { 478 t.Run(testName, func(t *testing.T) { 479 480 cache, m := newFakeAllocationCache() 481 482 m.AgonesClient.AddReactor("list", "gameservers", func(_ k8stesting.Action) (bool, k8sruntime.Object, error) { 483 return true, &agonesv1.GameServerList{Items: testScenario.list}, nil 484 }) 485 486 ctx, cancel := agtesting.StartInformers(m, cache.gameServerSynced) 487 defer cancel() 488 489 // This call initializes the cache 490 err := cache.syncCache() 491 assert.Nil(t, err) 492 493 err = cache.counter.Run(ctx, 0) 494 assert.Nil(t, err) 495 496 got := cache.ListSortedGameServersPriorities(testScenario.gsa) 497 498 assert.Equal(t, testScenario.want, got) 499 }) 500 } 501 } 502 503 func TestAllocatorRunCacheSync(t *testing.T) { 504 t.Parallel() 505 cache, m := newFakeAllocationCache() 506 gsWatch := watch.NewFake() 507 508 m.AgonesClient.AddWatchReactor("gameservers", k8stesting.DefaultWatchReactor(gsWatch, nil)) 509 510 ctx, cancel := agtesting.StartInformers(m, cache.gameServerSynced) 511 defer cancel() 512 513 assertCacheEntries := func(expected int) { 514 count := 0 515 err := wait.PollUntilContextTimeout(context.Background(), time.Second, 5*time.Second, true, func(_ context.Context) (done bool, err error) { 516 count = 0 517 cache.cache.Range(func(_ string, _ *agonesv1.GameServer) bool { 518 count++ 519 return true 520 }) 521 522 return count == expected, nil 523 }) 524 525 assert.NoError(t, err, fmt.Sprintf("Should be %d values", expected)) 526 } 527 528 go func() { 529 err := cache.Run(ctx) 530 assert.Nil(t, err) 531 }() 532 533 gs := agonesv1.GameServer{ 534 ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: "default", ResourceVersion: "1"}, 535 Status: agonesv1.GameServerStatus{State: agonesv1.GameServerStateStarting}, 536 } 537 538 logrus.Info("adding ready game server") 539 gsWatch.Add(gs.DeepCopy()) 540 541 assertCacheEntries(0) 542 543 gs.Status.State = agonesv1.GameServerStateReady 544 gs.ObjectMeta.ResourceVersion = "2" 545 gsWatch.Modify(gs.DeepCopy()) 546 547 assertCacheEntries(1) 548 549 // try again, should be no change 550 gs.Status.State = agonesv1.GameServerStateReady 551 gs.ObjectMeta.ResourceVersion = "3" 552 gsWatch.Modify(gs.DeepCopy()) 553 554 assertCacheEntries(1) 555 556 // now move it to Shutdown 557 gs.Status.State = agonesv1.GameServerStateShutdown 558 gs.ObjectMeta.ResourceVersion = "4" 559 gsWatch.Modify(gs.DeepCopy()) 560 assertCacheEntries(0) 561 562 // add it back in as Allocated 563 gs.Status.State = agonesv1.GameServerStateAllocated 564 gs.ObjectMeta.ResourceVersion = "5" 565 gsWatch.Modify(gs.DeepCopy()) 566 assertCacheEntries(1) 567 568 // now move it to Shutdown 569 gs.Status.State = agonesv1.GameServerStateShutdown 570 gs.ObjectMeta.ResourceVersion = "6" 571 gsWatch.Modify(gs.DeepCopy()) 572 assertCacheEntries(0) 573 574 // do not add back in with stale resource version 575 gs.Status.State = agonesv1.GameServerStateAllocated 576 gs.ObjectMeta.ResourceVersion = "6" 577 gsWatch.Modify(gs.DeepCopy()) 578 assertCacheEntries(0) 579 580 // add back in ready gameserver 581 gs.Status.State = agonesv1.GameServerStateReady 582 gs.ObjectMeta.ResourceVersion = "7" 583 gsWatch.Modify(gs.DeepCopy()) 584 assertCacheEntries(1) 585 586 // update with deletion timestamp 587 n := metav1.Now() 588 deletedCopy := gs.DeepCopy() 589 deletedCopy.ObjectMeta.DeletionTimestamp = &n 590 deletedCopy.ObjectMeta.ResourceVersion = "8" 591 gsWatch.Modify(deletedCopy) 592 assertCacheEntries(0) 593 594 // add back in ready gameserver 595 gs.Status.State = agonesv1.GameServerStateReady 596 deletedCopy.ObjectMeta.ResourceVersion = "9" 597 gsWatch.Modify(gs.DeepCopy()) 598 assertCacheEntries(1) 599 600 // now actually delete it 601 gsWatch.Delete(gs.DeepCopy()) 602 assertCacheEntries(0) 603 } 604 605 func newFakeAllocationCache() (*AllocationCache, agtesting.Mocks) { 606 m := agtesting.NewMocks() 607 cache := NewAllocationCache(m.AgonesInformerFactory.Agones().V1().GameServers(), gameservers.NewPerNodeCounter(m.KubeInformerFactory, m.AgonesInformerFactory), healthcheck.NewHandler()) 608 return cache, m 609 }