Skip to content

Commit cd9b7a1

Browse files
Enable counter based autoscaler to scale from 0 replicas (#4049)
* Enable counter based autoscaler to scale from 0 replicas * Disabled linter on duplicate pattern for tests * Fixing incorrect name for counter autoscaler test --------- Co-authored-by: peterzhongyi <49351430+peterzhongyi@users.noreply.github.com>
1 parent 08bc4c0 commit cd9b7a1

File tree

4 files changed

+157
-2
lines changed

4 files changed

+157
-2
lines changed

pkg/fleetautoscalers/fleetautoscalers_test.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,31 @@ func TestApplyCounterPolicy(t *testing.T) {
772772
wantErr: true,
773773
},
774774
},
775+
"Counter based fleet does not have any replicas": {
776+
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
777+
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
778+
f.Spec.Template.Spec.Counters["gamers"] = agonesv1.CounterStatus{
779+
Count: 0,
780+
Capacity: 7}
781+
f.Status.Replicas = 0
782+
f.Status.ReadyReplicas = 0
783+
f.Status.AllocatedReplicas = 0
784+
f.Status.Counters = make(map[string]agonesv1.AggregatedCounterStatus)
785+
f.Status.Counters["gamers"] = agonesv1.AggregatedCounterStatus{}
786+
}),
787+
featureFlags: string(utilruntime.FeatureCountsAndLists) + "=true",
788+
cp: &autoscalingv1.CounterPolicy{
789+
Key: "gamers",
790+
MaxCapacity: 100,
791+
MinCapacity: 10,
792+
BufferSize: intstr.FromInt(10),
793+
},
794+
want: expected{
795+
replicas: 2,
796+
limited: true,
797+
wantErr: false,
798+
},
799+
},
775800
"fleet spec does not have counter": {
776801
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
777802
f.Spec.Template.Spec.Counters = make(map[string]agonesv1.CounterStatus)
@@ -1570,7 +1595,7 @@ func TestApplyListPolicy(t *testing.T) {
15701595
wantErr: true,
15711596
},
15721597
},
1573-
"fleet does not have any replicas": {
1598+
"List based fleet does not have any replicas": {
15741599
fleet: modifiedFleet(func(f *agonesv1.Fleet) {
15751600
f.Spec.Template.Spec.Lists = make(map[string]agonesv1.ListStatus)
15761601
f.Spec.Template.Spec.Lists["gamers"] = agonesv1.ListStatus{

pkg/gameserversets/controller.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ func computeStatus(gsSet *agonesv1.GameServerSet, list []*agonesv1.GameServer) a
639639
// Initialize list status with empty lists from spec
640640
if runtime.FeatureEnabled(runtime.FeatureCountsAndLists) {
641641
status.Lists = createInitialListStatus(gsSet)
642+
status.Counters = createInitialCounterStatus(gsSet)
642643
}
643644
for _, gs := range list {
644645
if gs.IsBeingDeleted() {
@@ -700,6 +701,14 @@ func createInitialListStatus(gsSet *agonesv1.GameServerSet) map[string]agonesv1.
700701
return list
701702
}
702703

704+
func createInitialCounterStatus(gsSet *agonesv1.GameServerSet) map[string]agonesv1.AggregatedCounterStatus {
705+
counters := make(map[string]agonesv1.AggregatedCounterStatus)
706+
for name := range gsSet.Spec.Template.Spec.Counters {
707+
counters[name] = agonesv1.AggregatedCounterStatus{}
708+
}
709+
return counters
710+
}
711+
703712
// aggregateCounters adds the contents of a CounterStatus map to an AggregatedCounterStatus map.
704713
func aggregateCounters(aggCounterStatus map[string]agonesv1.AggregatedCounterStatus,
705714
counterStatus map[string]agonesv1.CounterStatus,

pkg/gameserversets/controller_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,44 @@ func TestComputeStatus(t *testing.T) {
412412
assert.Equal(t, expected, computeStatus(gsSet, list))
413413
})
414414

415+
t.Run("counters with no gameservers", func(t *testing.T) {
416+
utilruntime.FeatureTestMutex.Lock()
417+
defer utilruntime.FeatureTestMutex.Unlock()
418+
419+
require.NoError(t, utilruntime.ParseFeatures(fmt.Sprintf("%s=true", utilruntime.FeatureCountsAndLists)))
420+
421+
gsSet := defaultFixture()
422+
gsSet.Spec.Template.Spec.Counters = map[string]agonesv1.CounterStatus{
423+
"firstCounter": {Capacity: 10, Count: 1},
424+
"secondCounter": {Capacity: 10, Count: 1},
425+
}
426+
var list []*agonesv1.GameServer
427+
428+
expected := agonesv1.GameServerSetStatus{
429+
Replicas: 0,
430+
ReadyReplicas: 0,
431+
ReservedReplicas: 0,
432+
AllocatedReplicas: 0,
433+
Lists: map[string]agonesv1.AggregatedListStatus{},
434+
Counters: map[string]agonesv1.AggregatedCounterStatus{
435+
"firstCounter": {
436+
AllocatedCount: 0,
437+
AllocatedCapacity: 0,
438+
Capacity: 0,
439+
Count: 0,
440+
},
441+
"secondCounter": {
442+
AllocatedCount: 0,
443+
AllocatedCapacity: 0,
444+
Capacity: 0,
445+
Count: 0,
446+
},
447+
},
448+
}
449+
450+
assert.Equal(t, expected, computeStatus(gsSet, list))
451+
})
452+
415453
t.Run("lists", func(t *testing.T) {
416454
utilruntime.FeatureTestMutex.Lock()
417455
defer utilruntime.FeatureTestMutex.Unlock()
@@ -484,7 +522,7 @@ func TestComputeStatus(t *testing.T) {
484522
ReadyReplicas: 0,
485523
ReservedReplicas: 0,
486524
AllocatedReplicas: 0,
487-
Counters: nil,
525+
Counters: map[string]agonesv1.AggregatedCounterStatus{},
488526
Lists: map[string]agonesv1.AggregatedListStatus{
489527
"firstList": {
490528
AllocatedCount: 0,

test/e2e/fleetautoscaler_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,88 @@ func TestCounterAutoscaler(t *testing.T) {
944944
}
945945
}
946946

947+
// nolint:dupl // Linter errors on lines are duplicate of TestListAutoscalerWithNoReplicas
948+
func TestCounterAutoscalerWithNoReplicas(t *testing.T) {
949+
if !runtime.FeatureEnabled(runtime.FeatureCountsAndLists) {
950+
t.SkipNow()
951+
}
952+
t.Parallel()
953+
954+
ctx := context.Background()
955+
client := framework.AgonesClient.AgonesV1()
956+
log := e2e.TestLogger(t)
957+
958+
flt := defaultEmptyFleet(framework.Namespace)
959+
flt.Spec.Template.Spec.Counters = map[string]agonesv1.CounterStatus{
960+
"games": {
961+
Capacity: 5,
962+
},
963+
}
964+
965+
flt, err := client.Fleets(framework.Namespace).Create(ctx, flt.DeepCopy(), metav1.CreateOptions{})
966+
require.NoError(t, err)
967+
defer client.Fleets(framework.Namespace).Delete(ctx, flt.ObjectMeta.Name, metav1.DeleteOptions{}) // nolint:errcheck
968+
framework.AssertFleetCondition(t, flt, e2e.FleetReadyCount(flt.Spec.Replicas))
969+
970+
fleetautoscalers := framework.AgonesClient.AutoscalingV1().FleetAutoscalers(framework.Namespace)
971+
972+
counterFas := func(f func(fap *autoscalingv1.FleetAutoscalerPolicy)) *autoscalingv1.FleetAutoscaler {
973+
fas := autoscalingv1.FleetAutoscaler{
974+
ObjectMeta: metav1.ObjectMeta{Name: flt.ObjectMeta.Name + "-counter-autoscaler", Namespace: framework.Namespace},
975+
Spec: autoscalingv1.FleetAutoscalerSpec{
976+
FleetName: flt.ObjectMeta.Name,
977+
Policy: autoscalingv1.FleetAutoscalerPolicy{
978+
Type: autoscalingv1.CounterPolicyType,
979+
},
980+
Sync: &autoscalingv1.FleetAutoscalerSync{
981+
Type: autoscalingv1.FixedIntervalSyncType,
982+
FixedInterval: autoscalingv1.FixedIntervalSync{
983+
Seconds: 1,
984+
},
985+
},
986+
},
987+
}
988+
f(&fas.Spec.Policy)
989+
return &fas
990+
}
991+
testCases := map[string]struct {
992+
fas *autoscalingv1.FleetAutoscaler
993+
wantFasErr bool
994+
wantReplicas int32
995+
}{
996+
"Scale Up to MinCapacity": {
997+
fas: counterFas(func(fap *autoscalingv1.FleetAutoscalerPolicy) {
998+
fap.Counter = &autoscalingv1.CounterPolicy{
999+
Key: "games",
1000+
BufferSize: intstr.FromInt(3),
1001+
MinCapacity: 16,
1002+
MaxCapacity: 100,
1003+
}
1004+
}),
1005+
wantFasErr: false,
1006+
wantReplicas: 4, // Capacity:20
1007+
},
1008+
}
1009+
for name, testCase := range testCases {
1010+
t.Run(name, func(t *testing.T) {
1011+
1012+
fas, err := fleetautoscalers.Create(ctx, testCase.fas, metav1.CreateOptions{})
1013+
if testCase.wantFasErr {
1014+
assert.Error(t, err)
1015+
return
1016+
}
1017+
assert.NoError(t, err)
1018+
1019+
framework.AssertFleetCondition(t, flt, e2e.FleetReadyCount(testCase.wantReplicas))
1020+
fleetautoscalers.Delete(ctx, fas.ObjectMeta.Name, metav1.DeleteOptions{}) // nolint:errcheck
1021+
1022+
// Return to starting 0 replicas
1023+
framework.ScaleFleet(t, log, flt, 0)
1024+
framework.AssertFleetCondition(t, flt, e2e.FleetReadyCount(0))
1025+
})
1026+
}
1027+
}
1028+
9471029
func TestCounterAutoscalerAllocated(t *testing.T) {
9481030
if !runtime.FeatureEnabled(runtime.FeatureCountsAndLists) {
9491031
t.SkipNow()
@@ -1209,6 +1291,7 @@ func TestListAutoscaler(t *testing.T) {
12091291
}
12101292
}
12111293

1294+
// nolint:dupl // Linter errors on lines are duplicate of TestCounterAutoscalerWithNoReplicas
12121295
func TestListAutoscalerWithNoReplicas(t *testing.T) {
12131296
if !runtime.FeatureEnabled(runtime.FeatureCountsAndLists) {
12141297
t.SkipNow()

0 commit comments

Comments
 (0)