From 6cfedd5bf0d4d40fc762e6d717d39e3c318d053b Mon Sep 17 00:00:00 2001 From: Illia Litovchenko Date: Tue, 24 Mar 2026 09:25:32 +0000 Subject: [PATCH 1/3] KUBE-1815: pods with wildcard tolerations are ignored during drain --- internal/k8s/kubernetes.go | 16 ++++++++++++++-- internal/k8s/kubernetes_test.go | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/internal/k8s/kubernetes.go b/internal/k8s/kubernetes.go index 7dcd29be..51fb7f15 100644 --- a/internal/k8s/kubernetes.go +++ b/internal/k8s/kubernetes.go @@ -457,7 +457,7 @@ func PartitionPodsForEviction(pods []*v1.Pod, castNamespace string, skipDeletedT continue } - if IsDaemonSetPod(p) || IsStaticPod(p) { + if IsDaemonSetPod(p) || IsStaticPod(p) || HasWildcardToleration(p) { nonEvictable = append(nonEvictable, p) continue } @@ -493,7 +493,19 @@ func IsControlledBy(p *v1.Pod, kind string) bool { } func IsNonEvictible(p *v1.Pod) bool { - return IsDaemonSetPod(p) || IsStaticPod(p) + return IsDaemonSetPod(p) || IsStaticPod(p) || HasWildcardToleration(p) +} + +// HasWildcardToleration returns true if the pod has a toleration that matches all taints +// (i.e. key is empty and operator is Exists). Such pods would be rescheduled back onto +// a cordoned node since they tolerate the node.kubernetes.io/unschedulable taint. +func HasWildcardToleration(p *v1.Pod) bool { + for _, t := range p.Spec.Tolerations { + if t.Key == "" && t.Operator == v1.TolerationOpExists { + return true + } + } + return false } // PatchNode patches a node with the given change function. diff --git a/internal/k8s/kubernetes_test.go b/internal/k8s/kubernetes_test.go index 967c0c29..3d8227ce 100644 --- a/internal/k8s/kubernetes_test.go +++ b/internal/k8s/kubernetes_test.go @@ -1087,6 +1087,40 @@ func TestPartitionPodsForEviction(t *testing.T) { skipDeletedTimeoutSecs: 60, wantEvictableLen: 0, }, + { + name: "pod with wildcard toleration is non-evictable", + pods: []v1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{Name: "wildcard-pod", Namespace: "default"}, + Spec: v1.PodSpec{ + Tolerations: []v1.Toleration{ + {Operator: v1.TolerationOpExists}, + }, + }, + Status: v1.PodStatus{Phase: v1.PodRunning}, + }, + }, + castNamespace: testCastNamespace, + wantNonEvictableLen: 1, + wantNonEvictablePodNames: []string{"wildcard-pod"}, + }, + { + name: "pod with specific key toleration is evictable", + pods: []v1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{Name: "specific-toleration-pod", Namespace: "default"}, + Spec: v1.PodSpec{ + Tolerations: []v1.Toleration{ + {Key: "node.kubernetes.io/unschedulable", Operator: v1.TolerationOpExists}, + }, + }, + Status: v1.PodStatus{Phase: v1.PodRunning}, + }, + }, + castNamespace: testCastNamespace, + wantEvictableLen: 1, + wantEvictablePodNames: []string{"specific-toleration-pod"}, + }, { name: "mixed pods are partitioned correctly", pods: []v1.Pod{ From 7b71c0386c90b1dfcb664178c5bb7f8c2da7225c Mon Sep 17 00:00:00 2001 From: Illia Litovchenko Date: Wed, 25 Mar 2026 15:48:50 +0000 Subject: [PATCH 2/3] review fixes --- internal/k8s/kubernetes.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/k8s/kubernetes.go b/internal/k8s/kubernetes.go index 51fb7f15..e373374a 100644 --- a/internal/k8s/kubernetes.go +++ b/internal/k8s/kubernetes.go @@ -501,6 +501,8 @@ func IsNonEvictible(p *v1.Pod) bool { // a cordoned node since they tolerate the node.kubernetes.io/unschedulable taint. func HasWildcardToleration(p *v1.Pod) bool { for _, t := range p.Spec.Tolerations { + fmt.Println(p.Name, t.Key == "" && t.Operator == v1.TolerationOpExists) + fmt.Println(t) if t.Key == "" && t.Operator == v1.TolerationOpExists { return true } From 393d54fb1e4f3ac0b9c53416461491bf894ebd9d Mon Sep 17 00:00:00 2001 From: Illia Litovchenko Date: Wed, 25 Mar 2026 15:54:25 +0000 Subject: [PATCH 3/3] review fixes --- internal/k8s/kubernetes.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/k8s/kubernetes.go b/internal/k8s/kubernetes.go index e373374a..51fb7f15 100644 --- a/internal/k8s/kubernetes.go +++ b/internal/k8s/kubernetes.go @@ -501,8 +501,6 @@ func IsNonEvictible(p *v1.Pod) bool { // a cordoned node since they tolerate the node.kubernetes.io/unschedulable taint. func HasWildcardToleration(p *v1.Pod) bool { for _, t := range p.Spec.Tolerations { - fmt.Println(p.Name, t.Key == "" && t.Operator == v1.TolerationOpExists) - fmt.Println(t) if t.Key == "" && t.Operator == v1.TolerationOpExists { return true }