|
|
|
@@ -21,7 +21,6 @@ import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"math"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync"
|
|
|
|
@@ -754,111 +753,6 @@ func TestLegacyScaleDownIgnoresUnreadyPods(t *testing.T) {
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestTolerance(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 3,
|
|
|
|
|
desiredReplicas: 3,
|
|
|
|
|
CPUTarget: 100,
|
|
|
|
|
reportedLevels: []uint64{1010, 1030, 1020},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestToleranceCM(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 3,
|
|
|
|
|
desiredReplicas: 3,
|
|
|
|
|
metricsTarget: []autoscalingv2.MetricSpec{
|
|
|
|
|
{
|
|
|
|
|
Type: autoscalingv2.PodsMetricSourceType,
|
|
|
|
|
Pods: &autoscalingv2.PodsMetricSource{
|
|
|
|
|
MetricName: "qps",
|
|
|
|
|
TargetAverageValue: resource.MustParse("20.0"),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
reportedLevels: []uint64{20, 21, 21},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestMinReplicas(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 2,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 3,
|
|
|
|
|
desiredReplicas: 2,
|
|
|
|
|
CPUTarget: 90,
|
|
|
|
|
reportedLevels: []uint64{10, 95, 10},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestZeroReplicas(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 3,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 0,
|
|
|
|
|
desiredReplicas: 0,
|
|
|
|
|
CPUTarget: 90,
|
|
|
|
|
reportedLevels: []uint64{},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestTooFewReplicas(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 3,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 2,
|
|
|
|
|
desiredReplicas: 3,
|
|
|
|
|
CPUTarget: 90,
|
|
|
|
|
reportedLevels: []uint64{},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestTooManyReplicas(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 3,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 10,
|
|
|
|
|
desiredReplicas: 5,
|
|
|
|
|
CPUTarget: 90,
|
|
|
|
|
reportedLevels: []uint64{},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestMaxReplicas(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 2,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 3,
|
|
|
|
|
desiredReplicas: 5,
|
|
|
|
|
CPUTarget: 90,
|
|
|
|
|
reportedLevels: []uint64{8000, 9500, 1000},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.9"), resource.MustParse("1.0"), resource.MustParse("1.1")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLegacySuperfluousMetrics(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 2,
|
|
|
|
@@ -873,174 +767,6 @@ func TestLegacySuperfluousMetrics(t *testing.T) {
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestMissingMetrics(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 2,
|
|
|
|
|
maxReplicas: 6,
|
|
|
|
|
initialReplicas: 4,
|
|
|
|
|
desiredReplicas: 3,
|
|
|
|
|
CPUTarget: 100,
|
|
|
|
|
reportedLevels: []uint64{400, 95},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestEmptyMetrics(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 2,
|
|
|
|
|
maxReplicas: 6,
|
|
|
|
|
initialReplicas: 4,
|
|
|
|
|
desiredReplicas: 4,
|
|
|
|
|
CPUTarget: 100,
|
|
|
|
|
reportedLevels: []uint64{},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0"), resource.MustParse("1.0")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestEmptyCPURequest(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 1,
|
|
|
|
|
desiredReplicas: 1,
|
|
|
|
|
CPUTarget: 100,
|
|
|
|
|
reportedLevels: []uint64{200},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestEventCreated(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 1,
|
|
|
|
|
desiredReplicas: 2,
|
|
|
|
|
CPUTarget: 50,
|
|
|
|
|
reportedLevels: []uint64{200},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.2")},
|
|
|
|
|
verifyEvents: true,
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestEventNotCreated(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 2,
|
|
|
|
|
desiredReplicas: 2,
|
|
|
|
|
CPUTarget: 50,
|
|
|
|
|
reportedLevels: []uint64{200, 200},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.4"), resource.MustParse("0.4")},
|
|
|
|
|
verifyEvents: true,
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestMissingReports(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 5,
|
|
|
|
|
initialReplicas: 4,
|
|
|
|
|
desiredReplicas: 2,
|
|
|
|
|
CPUTarget: 50,
|
|
|
|
|
reportedLevels: []uint64{200},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.2")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func LegacyTestUpscaleCap(t *testing.T) {
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 1,
|
|
|
|
|
maxReplicas: 100,
|
|
|
|
|
initialReplicas: 3,
|
|
|
|
|
desiredReplicas: 6,
|
|
|
|
|
CPUTarget: 10,
|
|
|
|
|
reportedLevels: []uint64{100, 200, 300},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{resource.MustParse("0.1"), resource.MustParse("0.1"), resource.MustParse("0.1")},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestComputedToleranceAlgImplementation is a regression test which
|
|
|
|
|
// back-calculates a minimal percentage for downscaling based on a small percentage
|
|
|
|
|
// increase in pod utilization which is calibrated against the tolerance value.
|
|
|
|
|
func LegacyTestComputedToleranceAlgImplementation(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
startPods := int32(10)
|
|
|
|
|
// 150 mCPU per pod.
|
|
|
|
|
totalUsedCPUOfAllPods := uint64(startPods * 150)
|
|
|
|
|
// Each pod starts out asking for 2X what is really needed.
|
|
|
|
|
// This means we will have a 50% ratio of used/requested
|
|
|
|
|
totalRequestedCPUOfAllPods := int32(2 * totalUsedCPUOfAllPods)
|
|
|
|
|
requestedToUsed := float64(totalRequestedCPUOfAllPods / int32(totalUsedCPUOfAllPods))
|
|
|
|
|
// Spread the amount we ask over 10 pods. We can add some jitter later in reportedLevels.
|
|
|
|
|
perPodRequested := totalRequestedCPUOfAllPods / startPods
|
|
|
|
|
|
|
|
|
|
// Force a minimal scaling event by satisfying (tolerance < 1 - resourcesUsedRatio).
|
|
|
|
|
target := math.Abs(1/(requestedToUsed*(1-defaultTestingTolerance))) + .01
|
|
|
|
|
finalCPUPercentTarget := int32(target * 100)
|
|
|
|
|
resourcesUsedRatio := float64(totalUsedCPUOfAllPods) / float64(float64(totalRequestedCPUOfAllPods)*target)
|
|
|
|
|
|
|
|
|
|
// i.e. .60 * 20 -> scaled down expectation.
|
|
|
|
|
finalPods := int32(math.Ceil(resourcesUsedRatio * float64(startPods)))
|
|
|
|
|
|
|
|
|
|
// To breach tolerance we will create a utilization ratio difference of tolerance to usageRatioToleranceValue)
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|
minReplicas: 0,
|
|
|
|
|
maxReplicas: 1000,
|
|
|
|
|
initialReplicas: startPods,
|
|
|
|
|
desiredReplicas: finalPods,
|
|
|
|
|
CPUTarget: finalCPUPercentTarget,
|
|
|
|
|
reportedLevels: []uint64{
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
totalUsedCPUOfAllPods / 10,
|
|
|
|
|
},
|
|
|
|
|
reportedCPURequests: []resource.Quantity{
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested+100) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested-100) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested+10) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested-10) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested+2) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested-2) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested+1) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested-1) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested) + "m"),
|
|
|
|
|
resource.MustParse(fmt.Sprint(perPodRequested) + "m"),
|
|
|
|
|
},
|
|
|
|
|
useMetricsAPI: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
|
|
|
|
|
// Reuse the data structure above, now testing "unscaling".
|
|
|
|
|
// Now, we test that no scaling happens if we are in a very close margin to the tolerance
|
|
|
|
|
target = math.Abs(1/(requestedToUsed*(1-defaultTestingTolerance))) + .004
|
|
|
|
|
finalCPUPercentTarget = int32(target * 100)
|
|
|
|
|
tc.CPUTarget = finalCPUPercentTarget
|
|
|
|
|
tc.initialReplicas = startPods
|
|
|
|
|
tc.desiredReplicas = startPods
|
|
|
|
|
tc.runTest(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestLegacyScaleUpRCImmediately(t *testing.T) {
|
|
|
|
|
time := metav1.Time{Time: time.Now()}
|
|
|
|
|
tc := legacyTestCase{
|
|
|
|
|