Skip to content

Commit cfaa2c4

Browse files
authored
Merge pull request kubernetes#88337 from mgugino-upstream-stage/drain-custom-filters
kubectl/drain add support for custom pod filters
2 parents ccbaec1 + 85004f0 commit cfaa2c4

File tree

4 files changed

+178
-88
lines changed

4 files changed

+178
-88
lines changed

staging/src/k8s.io/kubectl/pkg/drain/drain.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ type Helper struct {
6565
// won't drain otherwise
6666
SkipWaitForDeleteTimeoutSeconds int
6767

68+
// AdditionalFilters are applied sequentially after base drain filters to
69+
// exclude pods using custom logic. Any filter that returns PodDeleteStatus
70+
// with Delete == false will immediately stop execution of further filters.
71+
AdditionalFilters []PodFilter
72+
6873
Out io.Writer
6974
ErrOut io.Writer
7075

@@ -172,7 +177,7 @@ func (d *Helper) EvictPod(pod corev1.Pod, policyGroupVersion string) error {
172177
// or error if it cannot list pods. All pods that are ready to be deleted can be obtained with .Pods(),
173178
// and string with all warning can be obtained with .Warnings(), and .Errors() for all errors that
174179
// occurred during deletion.
175-
func (d *Helper) GetPodsForDeletion(nodeName string) (*podDeleteList, []error) {
180+
func (d *Helper) GetPodsForDeletion(nodeName string) (*PodDeleteList, []error) {
176181
labelSelector, err := labels.Parse(d.PodSelector)
177182
if err != nil {
178183
return nil, []error{err}
@@ -185,35 +190,37 @@ func (d *Helper) GetPodsForDeletion(nodeName string) (*podDeleteList, []error) {
185190
return nil, []error{err}
186191
}
187192

188-
pods := []podDelete{}
193+
list := filterPods(podList, d.makeFilters())
194+
if errs := list.errors(); len(errs) > 0 {
195+
return list, errs
196+
}
197+
198+
return list, nil
199+
}
189200

201+
func filterPods(podList *corev1.PodList, filters []PodFilter) *PodDeleteList {
202+
pods := []PodDelete{}
190203
for _, pod := range podList.Items {
191-
var status podDeleteStatus
192-
for _, filter := range d.makeFilters() {
204+
var status PodDeleteStatus
205+
for _, filter := range filters {
193206
status = filter(pod)
194-
if !status.delete {
207+
if !status.Delete {
195208
// short-circuit as soon as pod is filtered out
196209
// at that point, there is no reason to run pod
197210
// through any additional filters
198211
break
199212
}
200213
}
201-
// Add the pod to podDeleteList no matter what podDeleteStatus is,
202-
// those pods whose podDeleteStatus is false like DaemonSet will
214+
// Add the pod to PodDeleteList no matter what PodDeleteStatus is,
215+
// those pods whose PodDeleteStatus is false like DaemonSet will
203216
// be catched by list.errors()
204-
pods = append(pods, podDelete{
205-
pod: pod,
206-
status: status,
217+
pods = append(pods, PodDelete{
218+
Pod: pod,
219+
Status: status,
207220
})
208221
}
209-
210-
list := &podDeleteList{items: pods}
211-
212-
if errs := list.errors(); len(errs) > 0 {
213-
return list, errs
214-
}
215-
216-
return list, nil
222+
list := &PodDeleteList{items: pods}
223+
return list
217224
}
218225

219226
// DeleteOrEvictPods deletes or evicts the pods on the api server

staging/src/k8s.io/kubectl/pkg/drain/drain_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,3 +389,72 @@ func TestDeleteOrEvict(t *testing.T) {
389389
})
390390
}
391391
}
392+
393+
func mockFilterSkip(_ corev1.Pod) PodDeleteStatus {
394+
return MakePodDeleteStatusSkip()
395+
}
396+
397+
func mockFilterOkay(_ corev1.Pod) PodDeleteStatus {
398+
return MakePodDeleteStatusOkay()
399+
}
400+
401+
func TestFilterPods(t *testing.T) {
402+
tCases := []struct {
403+
description string
404+
expectedPodListLen int
405+
additionalFilters []PodFilter
406+
}{
407+
{
408+
description: "AdditionalFilter skip all",
409+
expectedPodListLen: 0,
410+
additionalFilters: []PodFilter{
411+
mockFilterSkip,
412+
mockFilterOkay,
413+
},
414+
},
415+
{
416+
description: "AdditionalFilter okay all",
417+
expectedPodListLen: 1,
418+
additionalFilters: []PodFilter{
419+
mockFilterOkay,
420+
},
421+
},
422+
{
423+
description: "AdditionalFilter Skip after Okay all skip",
424+
expectedPodListLen: 0,
425+
additionalFilters: []PodFilter{
426+
mockFilterOkay,
427+
mockFilterSkip,
428+
},
429+
},
430+
{
431+
description: "No additionalFilters okay all",
432+
expectedPodListLen: 1,
433+
},
434+
}
435+
for _, tc := range tCases {
436+
t.Run(tc.description, func(t *testing.T) {
437+
h := &Helper{
438+
Force: true,
439+
AdditionalFilters: tc.additionalFilters,
440+
}
441+
pod := corev1.Pod{
442+
ObjectMeta: metav1.ObjectMeta{
443+
Name: "pod",
444+
Namespace: "default",
445+
},
446+
}
447+
podList := corev1.PodList{
448+
Items: []corev1.Pod{
449+
pod,
450+
},
451+
}
452+
453+
list := filterPods(&podList, h.makeFilters())
454+
podsLen := len(list.Pods())
455+
if podsLen != tc.expectedPodListLen {
456+
t.Errorf("%s: unexpected evictions; actual %v; expected %v", tc.description, podsLen, tc.expectedPodListLen)
457+
}
458+
})
459+
}
460+
}

staging/src/k8s.io/kubectl/pkg/drain/filter_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ func TestSkipDeletedFilter(t *testing.T) {
6363
}
6464

6565
podDeleteStatus := h.skipDeletedFilter(pod)
66-
if podDeleteStatus.delete != tc.expectedDelete {
67-
t.Errorf("test %v: unexpected podDeleteStatus.delete; actual %v; expected %v", i, podDeleteStatus.delete, tc.expectedDelete)
66+
if podDeleteStatus.Delete != tc.expectedDelete {
67+
t.Errorf("test %v: unexpected podDeleteStatus.delete; actual %v; expected %v", i, podDeleteStatus.Delete, tc.expectedDelete)
6868
}
6969
}
7070
}

0 commit comments

Comments
 (0)