@@ -21,6 +21,7 @@ import (
21
21
"time"
22
22
23
23
autoscalingv2 "k8s.io/api/autoscaling/v2"
24
+ "k8s.io/kubernetes/pkg/features"
24
25
"k8s.io/kubernetes/test/e2e/feature"
25
26
"k8s.io/kubernetes/test/e2e/framework"
26
27
e2eautoscaling "k8s.io/kubernetes/test/e2e/framework/autoscaling"
@@ -30,37 +31,29 @@ import (
30
31
"github.com/onsi/gomega"
31
32
)
32
33
33
- var _ = SIGDescribe (feature .HPA , framework .WithSerial (), framework .WithSlow (), "Horizontal pod autoscaling (non-default behavior)" , func () {
34
- f := framework .NewDefaultFramework ("horizontal-pod-autoscaling" )
35
- f .NamespacePodSecurityLevel = admissionapi .LevelPrivileged
34
+ const (
35
+ hpaName = "consumer"
36
36
37
- hpaName := "consumer"
37
+ podCPURequest = 500
38
+ targetCPUUtilizationPercent = 25
38
39
39
- podCPURequest := 500
40
- targetCPUUtilizationPercent := 25
40
+ fullWindowOfNewUsage = 30 * time .Second
41
+ windowWithOldUsagePasses = 30 * time .Second
42
+ newPodMetricsDelay = 15 * time .Second
43
+ metricsAvailableDelay = fullWindowOfNewUsage + windowWithOldUsagePasses + newPodMetricsDelay
41
44
42
- // usageForReplicas returns usage for (n - 0.5) replicas as if they would consume all CPU
43
- // under the target. The 0.5 replica reduction is to accommodate for the deviation between
44
- // the actual consumed cpu and requested usage by the ResourceConsumer.
45
- // HPA rounds up the recommendations. So, if the usage is e.g. for 3.5 replicas,
46
- // the recommended replica number will be 4.
47
- usageForReplicas := func (replicas int ) int {
48
- usagePerReplica := podCPURequest * targetCPUUtilizationPercent / 100
49
- return replicas * usagePerReplica - usagePerReplica / 2
50
- }
45
+ hpaReconciliationInterval = 15 * time .Second
46
+ actuationDelay = 10 * time .Second
47
+ maxHPAReactionTime = metricsAvailableDelay + hpaReconciliationInterval + actuationDelay
51
48
52
- fullWindowOfNewUsage := 30 * time .Second
53
- windowWithOldUsagePasses := 30 * time .Second
54
- newPodMetricsDelay := 15 * time .Second
55
- metricsAvailableDelay := fullWindowOfNewUsage + windowWithOldUsagePasses + newPodMetricsDelay
56
-
57
- hpaReconciliationInterval := 15 * time .Second
58
- actuationDelay := 10 * time .Second
59
- maxHPAReactionTime := metricsAvailableDelay + hpaReconciliationInterval + actuationDelay
49
+ maxConsumeCPUDelay = 30 * time .Second
50
+ waitForReplicasPollInterval = 20 * time .Second
51
+ maxResourceConsumerDelay = maxConsumeCPUDelay + waitForReplicasPollInterval
52
+ )
60
53
61
- maxConsumeCPUDelay := 30 * time . Second
62
- waitForReplicasPollInterval := 20 * time . Second
63
- maxResourceConsumerDelay := maxConsumeCPUDelay + waitForReplicasPollInterval
54
+ var _ = SIGDescribe ( feature . HPA , framework . WithSerial (), framework . WithSlow (), "Horizontal pod autoscaling (non-default behavior)" , func () {
55
+ f := framework . NewDefaultFramework ( "horizontal-pod-autoscaling" )
56
+ f . NamespacePodSecurityLevel = admissionapi . LevelPrivileged
64
57
65
58
waitBuffer := 1 * time .Minute
66
59
@@ -505,3 +498,61 @@ var _ = SIGDescribe(feature.HPA, framework.WithSerial(), framework.WithSlow(), "
505
498
})
506
499
})
507
500
})
501
+
502
+ var _ = SIGDescribe (feature .HPAConfigurableTolerance , framework .WithFeatureGate (features .HPAConfigurableTolerance ),
503
+ framework .WithSerial (), framework .WithSlow (), "Horizontal pod autoscaling (configurable tolerance)" , func () {
504
+ f := framework .NewDefaultFramework ("horizontal-pod-autoscaling" )
505
+ f .NamespacePodSecurityLevel = admissionapi .LevelPrivileged
506
+
507
+ waitBuffer := 1 * time .Minute
508
+
509
+ ginkgo .Describe ("with large configurable tolerance" , func () {
510
+ ginkgo .It ("should not scale" , func (ctx context.Context ) {
511
+ ginkgo .By ("setting up resource consumer and HPA" )
512
+ initPods := 1
513
+ initCPUUsageTotal := usageForReplicas (initPods )
514
+
515
+ rc := e2eautoscaling .NewDynamicResourceConsumer (ctx ,
516
+ hpaName , f .Namespace .Name , e2eautoscaling .KindDeployment , initPods ,
517
+ initCPUUsageTotal , 0 , 0 , int64 (podCPURequest ), 200 ,
518
+ f .ClientSet , f .ScalesGetter , e2eautoscaling .Disable , e2eautoscaling .Idle ,
519
+ )
520
+ ginkgo .DeferCleanup (rc .CleanUp )
521
+
522
+ scaleRule := e2eautoscaling .HPAScalingRuleWithToleranceMilli (10000 )
523
+ hpa := e2eautoscaling .CreateCPUHorizontalPodAutoscalerWithBehavior (ctx ,
524
+ rc , int32 (targetCPUUtilizationPercent ), 1 , 10 ,
525
+ e2eautoscaling .HPABehaviorWithScaleUpAndDownRules (scaleRule , scaleRule ),
526
+ )
527
+ ginkgo .DeferCleanup (e2eautoscaling .DeleteHPAWithBehavior , rc , hpa .Name )
528
+
529
+ waitDeadline := maxHPAReactionTime + maxResourceConsumerDelay + waitBuffer
530
+
531
+ ginkgo .By ("trying to trigger scale up" )
532
+ rc .ConsumeCPU (usageForReplicas (8 ))
533
+ waitStart := time .Now ()
534
+
535
+ rc .EnsureDesiredReplicasInRange (ctx , initPods , initPods , waitDeadline , hpa .Name )
536
+ timeWaited := time .Since (waitStart )
537
+
538
+ ginkgo .By ("verifying time waited for a scale up" )
539
+ framework .Logf ("time waited for scale up: %s" , timeWaited )
540
+ gomega .Expect (timeWaited ).To (gomega .BeNumerically (">" , waitDeadline ), "waited %s, wanted to wait more than %s" , timeWaited , waitDeadline )
541
+
542
+ ginkgo .By ("verifying number of replicas" )
543
+ replicas , err := rc .GetReplicas (ctx )
544
+ framework .ExpectNoError (err )
545
+ gomega .Expect (replicas ).To (gomega .BeNumerically ("==" , initPods ), "had %s replicas, still have %s replicas after time deadline" , initPods , replicas )
546
+ })
547
+ })
548
+ })
549
+
550
+ // usageForReplicas returns usage for (n - 0.5) replicas as if they would consume all CPU
551
+ // under the target. The 0.5 replica reduction is to accommodate for the deviation between
552
+ // the actual consumed cpu and requested usage by the ResourceConsumer.
553
+ // HPA rounds up the recommendations. So, if the usage is e.g. for 3.5 replicas,
554
+ // the recommended replica number will be 4.
555
+ func usageForReplicas (replicas int ) int {
556
+ usagePerReplica := podCPURequest * targetCPUUtilizationPercent / 100
557
+ return replicas * usagePerReplica - usagePerReplica / 2
558
+ }
0 commit comments