diff --git a/pkg/controller/podautoscaler/replica_calculator.go b/pkg/controller/podautoscaler/replica_calculator.go index d479a4edd84..991688de6dd 100644 --- a/pkg/controller/podautoscaler/replica_calculator.go +++ b/pkg/controller/podautoscaler/replica_calculator.go @@ -22,7 +22,7 @@ import ( "time" autoscaling "k8s.io/api/autoscaling/v2beta2" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/sets" @@ -365,11 +365,18 @@ func groupPods(pods []*v1.Pod, metrics metricsclient.PodMetricsInfo, resource v1 if pod.DeletionTimestamp != nil || pod.Status.Phase == v1.PodFailed { continue } + // Pending pods are ignored. + if pod.Status.Phase == v1.PodPending { + ignoredPods.Insert(pod.Name) + continue + } + // Pods missing metrics. metric, found := metrics[pod.Name] if !found { missingPods.Insert(pod.Name) continue } + // Unready pods are ignored. if resource == v1.ResourceCPU { var ignorePod bool _, condition := podutil.GetPodCondition(&pod.Status, v1.PodReady) diff --git a/pkg/controller/podautoscaler/replica_calculator_test.go b/pkg/controller/podautoscaler/replica_calculator_test.go index c07d7b2bb5c..22272766038 100644 --- a/pkg/controller/podautoscaler/replica_calculator_test.go +++ b/pkg/controller/podautoscaler/replica_calculator_test.go @@ -23,7 +23,7 @@ import ( "time" autoscalingv2 "k8s.io/api/autoscaling/v2beta2" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -862,6 +862,25 @@ func TestReplicaCalcScaleDownIncludeUnreadyPods(t *testing.T) { tc.runTest(t) } +func TestReplicaCalcScaleDownExcludeUnscheduledPods(t *testing.T) { + tc := replicaCalcTestCase{ + currentReplicas: 5, + expectedReplicas: 1, + podReadiness: []v1.ConditionStatus{v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse, v1.ConditionFalse, v1.ConditionFalse}, + podPhase: []v1.PodPhase{v1.PodRunning, v1.PodPending, v1.PodPending, v1.PodPending, v1.PodPending}, + resource: &resourceInfo{ + name: v1.ResourceCPU, + requests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")}, + levels: []int64{100}, + + targetUtilization: 50, + expectedUtilization: 10, + expectedValue: numContainersPerPod * 100, + }, + } + tc.runTest(t) +} + func TestReplicaCalcScaleDownIgnoreHotCpuPods(t *testing.T) { tc := replicaCalcTestCase{ currentReplicas: 5, @@ -1616,18 +1635,38 @@ func TestGroupPods(t *testing.T) { sets.NewString("lucretius"), sets.NewString("epicurus"), }, + { + name: "pending pods are ignored", + pods: []*v1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "unscheduled", + }, + Status: v1.PodStatus{ + Phase: v1.PodPending, + }, + }, + }, + metrics: metricsclient.PodMetricsInfo{}, + resource: v1.ResourceCPU, + expectReadyPodCount: 0, + expectIgnoredPods: sets.NewString("unscheduled"), + expectMissingPods: sets.NewString(), + }, } for _, tc := range tests { - readyPodCount, ignoredPods, missingPods := groupPods(tc.pods, tc.metrics, tc.resource, defaultTestingCpuInitializationPeriod, defaultTestingDelayOfInitialReadinessStatus) - if readyPodCount != tc.expectReadyPodCount { - t.Errorf("%s got readyPodCount %d, expected %d", tc.name, readyPodCount, tc.expectReadyPodCount) - } - if !ignoredPods.Equal(tc.expectIgnoredPods) { - t.Errorf("%s got unreadyPods %v, expected %v", tc.name, ignoredPods, tc.expectIgnoredPods) - } - if !missingPods.Equal(tc.expectMissingPods) { - t.Errorf("%s got missingPods %v, expected %v", tc.name, missingPods, tc.expectMissingPods) - } + t.Run(tc.name, func(t *testing.T) { + readyPodCount, ignoredPods, missingPods := groupPods(tc.pods, tc.metrics, tc.resource, defaultTestingCpuInitializationPeriod, defaultTestingDelayOfInitialReadinessStatus) + if readyPodCount != tc.expectReadyPodCount { + t.Errorf("%s got readyPodCount %d, expected %d", tc.name, readyPodCount, tc.expectReadyPodCount) + } + if !ignoredPods.Equal(tc.expectIgnoredPods) { + t.Errorf("%s got unreadyPods %v, expected %v", tc.name, ignoredPods, tc.expectIgnoredPods) + } + if !missingPods.Equal(tc.expectMissingPods) { + t.Errorf("%s got missingPods %v, expected %v", tc.name, missingPods, tc.expectMissingPods) + } + }) } }