Skip to content

Commit 4bf287f

Browse files
committed
fixes namespace object limiter
Signed-off-by: songtao98 <songtao2603060@gmail.com>
1 parent 05e4dc3 commit 4bf287f

File tree

6 files changed

+91
-64
lines changed

6 files changed

+91
-64
lines changed

pkg/descheduler/apis/config/types_pluginargs.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ type MigrationObjectLimiter struct {
135135
// MaxMigrating indicates the maximum number of migrations/evictions allowed within the window time.
136136
// If configured as nil or 0, the maximum number will be calculated according to MaxMigratingPerWorkload.
137137
MaxMigrating *intstr.IntOrString
138+
// Burst indicates the limiter allows bursts of up to 'burst' to exceed within the time window.
139+
Burst int
138140
}
139141

140142
// ArbitrationArgs holds arguments used to configure the Arbitration Mechanism.

pkg/descheduler/apis/config/v1alpha2/types_pluginargs.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ type MigrationObjectLimiter struct {
136136
// MaxMigrating indicates the maximum number of migrations/evictions allowed within the window time.
137137
// If configured as 0, the maximum number will be calculated according to MaxMigratingPerWorkload.
138138
MaxMigrating *intstr.IntOrString `json:"maxMigrating,omitempty"`
139+
// Burst indicates the limiter allows bursts of up to 'burst' to exceed within the time window.
140+
Burst int `json:"burst,omitempty"`
139141
}
140142

141143
// ArbitrationArgs holds arguments used to configure the Arbitration Mechanism.

pkg/descheduler/apis/config/v1alpha2/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/descheduler/controllers/migration/controller.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -872,8 +872,13 @@ func (r *Reconciler) trackEvictedPod(pod *corev1.Pod) {
872872
continue
873873
}
874874
var maxMigratingReplicas int
875-
if expectedReplicas, err := r.controllerFinder.GetExpectedScaleForPod(pod); err == nil {
876-
maxMigrating := objectLimiterArgs.MaxMigrating
875+
maxMigrating := objectLimiterArgs.MaxMigrating
876+
// namespace limiter should only accept int value. If a percent value is provided, it will be parsed as 0, thus just return.
877+
if limiterType == deschedulerconfig.MigrationLimitObjectNamespace {
878+
if maxMigrating != nil {
879+
maxMigratingReplicas = maxMigrating.IntValue()
880+
}
881+
} else if expectedReplicas, err := r.controllerFinder.GetExpectedScaleForPod(pod); err == nil {
877882
if maxMigrating == nil {
878883
maxMigrating = r.args.MaxMigratingPerWorkload
879884
}
@@ -883,12 +888,13 @@ func (r *Reconciler) trackEvictedPod(pod *corev1.Pod) {
883888
return
884889
}
885890
limit := rate.Limit(maxMigratingReplicas) / rate.Limit(objectLimiterArgs.Duration.Seconds())
891+
burst := util.GetLimiterBurst(objectLimiterArgs.Burst)
886892

887-
r.track(limit, limiterKey, processScope, limiterType, maxMigratingReplicas)
893+
r.track(limit, limiterKey, processScope, limiterType, burst)
888894
}
889895
}
890896

891-
func (r *Reconciler) track(limit rate.Limit, limiterKey, processScope string, limiterType deschedulerconfig.MigrationLimitObjectType, maxMigratingReplicas int) {
897+
func (r *Reconciler) track(limit rate.Limit, limiterKey, processScope string, limiterType deschedulerconfig.MigrationLimitObjectType, burst int) {
892898
r.limiterLock.Lock()
893899
defer r.limiterLock.Unlock()
894900

@@ -899,7 +905,7 @@ func (r *Reconciler) track(limit rate.Limit, limiterKey, processScope string, li
899905
}
900906
limiter := limiters[limiterKey]
901907
if limiter == nil {
902-
limiter = rate.NewLimiter(limit, maxMigratingReplicas)
908+
limiter = rate.NewLimiter(limit, burst)
903909
limiters[limiterKey] = limiter
904910
} else if limiter.Limit() != limit {
905911
limiter.SetLimit(limit)

pkg/descheduler/controllers/migration/controller_test.go

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,7 +1635,7 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
16351635
}
16361636
testObjectLimiters := deschedulerconfig.ObjectLimiterMap{
16371637
deschedulerconfig.MigrationLimitObjectWorkload: {
1638-
Duration: metav1.Duration{Duration: 1 * time.Minute},
1638+
Duration: metav1.Duration{Duration: 1 * time.Second},
16391639
MaxMigrating: &intstr.IntOrString{Type: intstr.Int, IntVal: 10},
16401640
},
16411641
}
@@ -1652,7 +1652,7 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
16521652
want bool
16531653
}{
16541654
{
1655-
name: "less than default maxMigrating",
1655+
name: "less than workload limiter",
16561656
totalReplicas: 100,
16571657
objectLimiters: testObjectLimiters,
16581658
sleepDuration: 100 * time.Millisecond,
@@ -1675,13 +1675,14 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
16751675
},
16761676
},
16771677
},
1678-
evictedPodsCount: 6,
1678+
evictedPodsCount: 1,
16791679
want: false,
16801680
},
16811681
{
1682-
name: "exceeded default maxMigrating",
1682+
name: "exceeded workload limiter",
16831683
totalReplicas: 100,
16841684
objectLimiters: testObjectLimiters,
1685+
sleepDuration: 10 * time.Millisecond,
16851686
pod: &corev1.Pod{
16861687
ObjectMeta: metav1.ObjectMeta{
16871688
OwnerReferences: ownerReferences1,
@@ -1701,14 +1702,14 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
17011702
},
17021703
},
17031704
},
1704-
evictedPodsCount: 11,
1705+
evictedPodsCount: 1,
17051706
want: true,
17061707
},
17071708
{
1708-
name: "other than workload",
1709+
name: "other workload",
17091710
totalReplicas: 100,
17101711
objectLimiters: testObjectLimiters,
1711-
sleepDuration: 100 * time.Millisecond,
1712+
sleepDuration: 10 * time.Millisecond,
17121713
pod: &corev1.Pod{
17131714
ObjectMeta: metav1.ObjectMeta{
17141715
OwnerReferences: ownerReferences1,
@@ -1728,21 +1729,22 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
17281729
},
17291730
},
17301731
},
1731-
evictedPodsCount: 11,
1732+
evictedPodsCount: 1,
17321733
evictedWorkload: &otherOwnerReferences,
17331734
want: false,
17341735
},
17351736
{
17361737
name: "disable workloadObjectLimiters",
17371738
totalReplicas: 100,
1739+
sleepDuration: 10 * time.Millisecond,
17381740
pod: &corev1.Pod{
17391741
ObjectMeta: metav1.ObjectMeta{
17401742
OwnerReferences: ownerReferences1,
17411743
Name: "test-pod",
17421744
Namespace: "test-namespace",
17431745
},
17441746
},
1745-
evictedPodsCount: 11,
1747+
evictedPodsCount: 1,
17461748
objectLimiters: deschedulerconfig.ObjectLimiterMap{
17471749
deschedulerconfig.MigrationLimitObjectWorkload: deschedulerconfig.MigrationObjectLimiter{
17481750
Duration: metav1.Duration{Duration: 0},
@@ -1763,8 +1765,9 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
17631765
want: false,
17641766
},
17651767
{
1766-
name: "default limiter",
1768+
name: "default workload limiter",
17671769
totalReplicas: 100,
1770+
sleepDuration: 10 * time.Millisecond,
17681771
pod: &corev1.Pod{
17691772
ObjectMeta: metav1.ObjectMeta{
17701773
OwnerReferences: ownerReferences1,
@@ -1784,9 +1787,42 @@ func TestRequeueJobIfObjectLimiterFailed(t *testing.T) {
17841787
},
17851788
},
17861789
},
1787-
evictedPodsCount: 11,
1790+
evictedPodsCount: 1,
17881791
want: true,
17891792
},
1793+
{
1794+
name: "workload limiter with burst",
1795+
totalReplicas: 100,
1796+
sleepDuration: 10 * time.Millisecond,
1797+
objectLimiters: deschedulerconfig.ObjectLimiterMap{
1798+
deschedulerconfig.MigrationLimitObjectWorkload: deschedulerconfig.MigrationObjectLimiter{
1799+
Duration: metav1.Duration{Duration: 1 * time.Second},
1800+
MaxMigrating: &intstr.IntOrString{Type: intstr.Int, IntVal: 10},
1801+
Burst: 2,
1802+
},
1803+
},
1804+
pod: &corev1.Pod{
1805+
ObjectMeta: metav1.ObjectMeta{
1806+
OwnerReferences: ownerReferences1,
1807+
Name: "test-pod",
1808+
Namespace: "test-namespace",
1809+
},
1810+
},
1811+
job: &sev1alpha1.PodMigrationJob{
1812+
ObjectMeta: metav1.ObjectMeta{
1813+
Name: "test",
1814+
CreationTimestamp: metav1.Time{Time: time.Now()},
1815+
},
1816+
Spec: sev1alpha1.PodMigrationJobSpec{
1817+
PodRef: &corev1.ObjectReference{
1818+
Namespace: "test-namespace",
1819+
Name: "test-pod",
1820+
},
1821+
},
1822+
},
1823+
evictedPodsCount: 1,
1824+
want: false,
1825+
},
17901826
}
17911827

17921828
for _, tt := range tests {
@@ -1845,20 +1881,13 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
18451881
UID: uuid.NewUUID(),
18461882
},
18471883
}
1848-
otherOwnerReferences := metav1.OwnerReference{
1849-
APIVersion: "apps/v1",
1850-
Controller: pointer.Bool(true),
1851-
Kind: "StatefulSet",
1852-
Name: "test-2",
1853-
UID: uuid.NewUUID(),
1854-
}
18551884
testObjectLimiters := deschedulerconfig.ObjectLimiterMap{
18561885
deschedulerconfig.MigrationLimitObjectWorkload: {
1857-
Duration: metav1.Duration{Duration: 1 * time.Minute},
1886+
Duration: metav1.Duration{Duration: 1 * time.Second},
18581887
MaxMigrating: &intstr.IntOrString{Type: intstr.Int, IntVal: 10},
18591888
},
18601889
deschedulerconfig.MigrationLimitObjectNamespace: {
1861-
Duration: metav1.Duration{Duration: 1 * time.Minute},
1890+
Duration: metav1.Duration{Duration: 1 * time.Second},
18621891
MaxMigrating: &intstr.IntOrString{Type: intstr.Int, IntVal: 5},
18631892
},
18641893
}
@@ -1871,7 +1900,7 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
18711900
pod *corev1.Pod
18721901
job *sev1alpha1.PodMigrationJob
18731902
evictedPodsCount int
1874-
evictedWorkload *metav1.OwnerReference
1903+
evictedNamespace string
18751904
want bool
18761905
}{
18771906
{
@@ -1898,14 +1927,14 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
18981927
},
18991928
},
19001929
},
1901-
evictedPodsCount: 6,
1930+
evictedPodsCount: 1,
19021931
want: true,
19031932
},
19041933
{
19051934
name: "less than both",
19061935
totalReplicas: 100,
19071936
objectLimiters: testObjectLimiters,
1908-
sleepDuration: 100 * time.Millisecond,
1937+
sleepDuration: 200 * time.Millisecond,
19091938
pod: &corev1.Pod{
19101939
ObjectMeta: metav1.ObjectMeta{
19111940
OwnerReferences: ownerReferences1,
@@ -1925,21 +1954,26 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
19251954
},
19261955
},
19271956
},
1928-
evictedPodsCount: 4,
1957+
evictedPodsCount: 1,
19291958
want: false,
19301959
},
19311960
{
19321961
name: "disable namespaceObjectLimiters",
19331962
totalReplicas: 100,
1963+
sleepDuration: 100 * time.Millisecond,
19341964
pod: &corev1.Pod{
19351965
ObjectMeta: metav1.ObjectMeta{
19361966
OwnerReferences: ownerReferences1,
19371967
Name: "test-pod",
19381968
Namespace: "test-namespace",
19391969
},
19401970
},
1941-
evictedPodsCount: 6,
1971+
evictedPodsCount: 1,
19421972
objectLimiters: deschedulerconfig.ObjectLimiterMap{
1973+
deschedulerconfig.MigrationLimitObjectWorkload: {
1974+
Duration: metav1.Duration{Duration: 1 * time.Second},
1975+
MaxMigrating: &intstr.IntOrString{Type: intstr.Int, IntVal: 10},
1976+
},
19431977
deschedulerconfig.MigrationLimitObjectNamespace: deschedulerconfig.MigrationObjectLimiter{
19441978
Duration: metav1.Duration{Duration: 0},
19451979
},
@@ -1961,17 +1995,18 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
19611995
{
19621996
name: "disable namespaceObjectLimiters and exceed workload",
19631997
totalReplicas: 100,
1998+
sleepDuration: 10 * time.Millisecond,
19641999
pod: &corev1.Pod{
19652000
ObjectMeta: metav1.ObjectMeta{
19662001
OwnerReferences: ownerReferences1,
19672002
Name: "test-pod",
19682003
Namespace: "test-namespace",
19692004
},
19702005
},
1971-
evictedPodsCount: 11,
2006+
evictedPodsCount: 1,
19722007
objectLimiters: deschedulerconfig.ObjectLimiterMap{
19732008
deschedulerconfig.MigrationLimitObjectWorkload: {
1974-
Duration: metav1.Duration{Duration: 1 * time.Minute},
2009+
Duration: metav1.Duration{Duration: 1 * time.Second},
19752010
MaxMigrating: &intstr.IntOrString{Type: intstr.Int, IntVal: 10},
19762011
},
19772012
deschedulerconfig.MigrationLimitObjectNamespace: deschedulerconfig.MigrationObjectLimiter{
@@ -1993,7 +2028,7 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
19932028
want: true,
19942029
},
19952030
{
1996-
name: "other than workload",
2031+
name: "other namespace",
19972032
totalReplicas: 100,
19982033
objectLimiters: testObjectLimiters,
19992034
sleepDuration: 100 * time.Millisecond,
@@ -2016,33 +2051,8 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
20162051
},
20172052
},
20182053
},
2019-
evictedPodsCount: 11,
2020-
evictedWorkload: &otherOwnerReferences,
2021-
want: true,
2022-
},
2023-
{
2024-
name: "default limiter",
2025-
totalReplicas: 100,
2026-
pod: &corev1.Pod{
2027-
ObjectMeta: metav1.ObjectMeta{
2028-
OwnerReferences: ownerReferences1,
2029-
Name: "test-pod",
2030-
Namespace: "test-namespace",
2031-
},
2032-
},
2033-
job: &sev1alpha1.PodMigrationJob{
2034-
ObjectMeta: metav1.ObjectMeta{
2035-
Name: "test",
2036-
CreationTimestamp: metav1.Time{Time: time.Now()},
2037-
},
2038-
Spec: sev1alpha1.PodMigrationJobSpec{
2039-
PodRef: &corev1.ObjectReference{
2040-
Namespace: "test-namespace",
2041-
Name: "test-pod",
2042-
},
2043-
},
2044-
},
2045-
evictedPodsCount: 6,
2054+
evictedPodsCount: 1,
2055+
evictedNamespace: "test-namespace-other",
20462056
want: false,
20472057
},
20482058
}
@@ -2076,10 +2086,8 @@ func TestRequeueJobIfObjectLimiterFailedWithNamespace(t *testing.T) {
20762086
if tt.evictedPodsCount > 0 {
20772087
for i := 0; i < tt.evictedPodsCount; i++ {
20782088
pod := tt.pod.DeepCopy()
2079-
if tt.evictedWorkload != nil {
2080-
pod.OwnerReferences = []metav1.OwnerReference{
2081-
*tt.evictedWorkload,
2082-
}
2089+
if tt.evictedNamespace != "" {
2090+
pod.Namespace = tt.evictedNamespace
20832091
}
20842092
reconciler.trackEvictedPod(pod)
20852093
if tt.sleepDuration > 0 {

pkg/descheduler/controllers/migration/util/util.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ func GetMaxMigrating(replicas int, intOrPercent *intstr.IntOrString) (int, error
113113
return GetMaxUnavailable(replicas, intOrPercent)
114114
}
115115

116+
func GetLimiterBurst(burst int) int {
117+
if burst == 0 {
118+
return 1
119+
}
120+
return burst
121+
}
122+
116123
// FilterPodWithMaxEvictionCost rejects if pod's eviction cost is math.MaxInt32
117124
func FilterPodWithMaxEvictionCost(pod *corev1.Pod) bool {
118125
cost, _ := extension.GetEvictionCost(pod.Annotations)

0 commit comments

Comments
 (0)