Skip to content

Commit b42f219

Browse files
authored
Merge pull request kubernetes#85571 from mgugino-upstream-stage/drain-ignore-pdbs
kubectl/drain: add disable-eviction option
2 parents 570a4d1 + 6c1d587 commit b42f219

File tree

3 files changed

+111
-79
lines changed

3 files changed

+111
-79
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func NewCmdDrain(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
192192
cmd.Flags().DurationVar(&o.drainer.Timeout, "timeout", o.drainer.Timeout, "The length of time to wait before giving up, zero means infinite")
193193
cmd.Flags().StringVarP(&o.drainer.Selector, "selector", "l", o.drainer.Selector, "Selector (label query) to filter on")
194194
cmd.Flags().StringVarP(&o.drainer.PodSelector, "pod-selector", "", o.drainer.PodSelector, "Label selector to filter pods on the node")
195+
cmd.Flags().BoolVar(&o.drainer.DisableEviction, "disable-eviction", o.drainer.DisableEviction, "Force drain to use delete, even if eviction is supported. This will bypass checking PodDisruptionBudgets, use with caution.")
195196

196197
cmdutil.AddDryRunFlag(cmd)
197198
return cmd

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ type Helper struct {
5252
DeleteLocalData bool
5353
Selector string
5454
PodSelector string
55-
Out io.Writer
56-
ErrOut io.Writer
55+
56+
// DisableEviction forces drain to use delete rather than evict
57+
DisableEviction bool
58+
59+
Out io.Writer
60+
ErrOut io.Writer
5761

5862
// TODO(justinsb): unnecessary?
5963
DryRun bool
@@ -179,17 +183,20 @@ func (d *Helper) DeleteOrEvictPods(pods []corev1.Pod) error {
179183
return nil
180184
}
181185

182-
policyGroupVersion, err := CheckEvictionSupport(d.Client)
183-
if err != nil {
184-
return err
185-
}
186-
187186
// TODO(justinsb): unnecessary?
188187
getPodFn := func(namespace, name string) (*corev1.Pod, error) {
189188
return d.Client.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
190189
}
191-
if len(policyGroupVersion) > 0 {
192-
return d.evictPods(pods, policyGroupVersion, getPodFn)
190+
191+
if !d.DisableEviction {
192+
policyGroupVersion, err := CheckEvictionSupport(d.Client)
193+
if err != nil {
194+
return err
195+
}
196+
197+
if len(policyGroupVersion) > 0 {
198+
return d.evictPods(pods, policyGroupVersion, getPodFn)
199+
}
193200
}
194201

195202
return d.deletePods(pods, getPodFn)

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

Lines changed: 94 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -245,90 +245,114 @@ func TestCheckEvictionSupport(t *testing.T) {
245245
}
246246

247247
func TestDeleteOrEvict(t *testing.T) {
248-
for _, evictionSupported := range []bool{true, false} {
249-
evictionSupported := evictionSupported
250-
t.Run(fmt.Sprintf("evictionSupported=%v", evictionSupported),
251-
func(t *testing.T) {
252-
h := &Helper{
253-
Out: os.Stdout,
254-
GracePeriodSeconds: 10,
255-
}
256-
257-
// Create 4 pods, and try to remove the first 2
258-
var expectedEvictions []policyv1beta1.Eviction
259-
var create []runtime.Object
260-
deletePods := []corev1.Pod{}
261-
for i := 1; i <= 4; i++ {
262-
pod := &corev1.Pod{}
263-
pod.Name = fmt.Sprintf("mypod-%d", i)
264-
pod.Namespace = "default"
248+
tests := []struct {
249+
description string
250+
evictionSupported bool
251+
disableEviction bool
252+
}{
253+
{
254+
description: "eviction supported/enabled",
255+
evictionSupported: true,
256+
disableEviction: false,
257+
},
258+
{
259+
description: "eviction unsupported/disabled",
260+
evictionSupported: false,
261+
disableEviction: false,
262+
},
263+
{
264+
description: "eviction supported/disabled",
265+
evictionSupported: true,
266+
disableEviction: true,
267+
},
268+
{
269+
description: "eviction unsupported/disabled",
270+
evictionSupported: false,
271+
disableEviction: false,
272+
},
273+
}
274+
for _, tc := range tests {
275+
t.Run(tc.description, func(t *testing.T) {
276+
h := &Helper{
277+
Out: os.Stdout,
278+
GracePeriodSeconds: 10,
279+
}
265280

266-
create = append(create, pod)
267-
if i <= 2 {
268-
deletePods = append(deletePods, *pod)
281+
// Create 4 pods, and try to remove the first 2
282+
var expectedEvictions []policyv1beta1.Eviction
283+
var create []runtime.Object
284+
deletePods := []corev1.Pod{}
285+
for i := 1; i <= 4; i++ {
286+
pod := &corev1.Pod{}
287+
pod.Name = fmt.Sprintf("mypod-%d", i)
288+
pod.Namespace = "default"
269289

270-
if evictionSupported {
271-
eviction := policyv1beta1.Eviction{}
272-
eviction.Kind = "Eviction"
273-
eviction.APIVersion = "policy/v1"
274-
eviction.Namespace = pod.Namespace
275-
eviction.Name = pod.Name
290+
create = append(create, pod)
291+
if i <= 2 {
292+
deletePods = append(deletePods, *pod)
276293

277-
gracePeriodSeconds := int64(h.GracePeriodSeconds)
278-
eviction.DeleteOptions = &metav1.DeleteOptions{
279-
GracePeriodSeconds: &gracePeriodSeconds,
280-
}
294+
if tc.evictionSupported && !tc.disableEviction {
295+
eviction := policyv1beta1.Eviction{}
296+
eviction.Kind = "Eviction"
297+
eviction.APIVersion = "policy/v1"
298+
eviction.Namespace = pod.Namespace
299+
eviction.Name = pod.Name
281300

282-
expectedEvictions = append(expectedEvictions, eviction)
301+
gracePeriodSeconds := int64(h.GracePeriodSeconds)
302+
eviction.DeleteOptions = &metav1.DeleteOptions{
303+
GracePeriodSeconds: &gracePeriodSeconds,
283304
}
305+
306+
expectedEvictions = append(expectedEvictions, eviction)
284307
}
285308
}
309+
}
286310

287-
// Build the fake client
288-
k := fake.NewSimpleClientset(create...)
289-
if evictionSupported {
290-
addEvictionSupport(t, k)
291-
}
292-
h.Client = k
311+
// Build the fake client
312+
k := fake.NewSimpleClientset(create...)
313+
if tc.evictionSupported {
314+
addEvictionSupport(t, k)
315+
}
316+
h.Client = k
317+
h.DisableEviction = tc.disableEviction
318+
// Do the eviction
319+
if err := h.DeleteOrEvictPods(deletePods); err != nil {
320+
t.Fatalf("error from DeleteOrEvictPods: %v", err)
321+
}
293322

294-
// Do the eviction
295-
if err := h.DeleteOrEvictPods(deletePods); err != nil {
296-
t.Fatalf("error from DeleteOrEvictPods: %v", err)
323+
// Test that other pods are still there
324+
var remainingPods []string
325+
{
326+
podList, err := k.CoreV1().Pods("").List(metav1.ListOptions{})
327+
if err != nil {
328+
t.Fatalf("error listing pods: %v", err)
297329
}
298330

299-
// Test that other pods are still there
300-
var remainingPods []string
301-
{
302-
podList, err := k.CoreV1().Pods("").List(metav1.ListOptions{})
303-
if err != nil {
304-
t.Fatalf("error listing pods: %v", err)
305-
}
306-
307-
for _, pod := range podList.Items {
308-
remainingPods = append(remainingPods, pod.Namespace+"/"+pod.Name)
309-
}
310-
sort.Strings(remainingPods)
311-
}
312-
expected := []string{"default/mypod-3", "default/mypod-4"}
313-
if !reflect.DeepEqual(remainingPods, expected) {
314-
t.Errorf("unexpected remaining pods after DeleteOrEvictPods; actual %v; expected %v", remainingPods, expected)
331+
for _, pod := range podList.Items {
332+
remainingPods = append(remainingPods, pod.Namespace+"/"+pod.Name)
315333
}
334+
sort.Strings(remainingPods)
335+
}
336+
expected := []string{"default/mypod-3", "default/mypod-4"}
337+
if !reflect.DeepEqual(remainingPods, expected) {
338+
t.Errorf("%s: unexpected remaining pods after DeleteOrEvictPods; actual %v; expected %v", tc.description, remainingPods, expected)
339+
}
316340

317-
// Test that pods were evicted as expected
318-
var actualEvictions []policyv1beta1.Eviction
319-
for _, action := range k.Actions() {
320-
if action.GetVerb() != "create" || action.GetResource().Resource != "pods" || action.GetSubresource() != "eviction" {
321-
continue
322-
}
323-
eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction)
324-
actualEvictions = append(actualEvictions, eviction)
325-
}
326-
sort.Slice(actualEvictions, func(i, j int) bool {
327-
return actualEvictions[i].Name < actualEvictions[j].Name
328-
})
329-
if !reflect.DeepEqual(actualEvictions, expectedEvictions) {
330-
t.Errorf("unexpected evictions; actual %v; expected %v", actualEvictions, expectedEvictions)
341+
// Test that pods were evicted as expected
342+
var actualEvictions []policyv1beta1.Eviction
343+
for _, action := range k.Actions() {
344+
if action.GetVerb() != "create" || action.GetResource().Resource != "pods" || action.GetSubresource() != "eviction" {
345+
continue
331346
}
347+
eviction := *action.(ktest.CreateAction).GetObject().(*policyv1beta1.Eviction)
348+
actualEvictions = append(actualEvictions, eviction)
349+
}
350+
sort.Slice(actualEvictions, func(i, j int) bool {
351+
return actualEvictions[i].Name < actualEvictions[j].Name
332352
})
353+
if !reflect.DeepEqual(actualEvictions, expectedEvictions) {
354+
t.Errorf("%s: unexpected evictions; actual %v; expected %v", tc.description, actualEvictions, expectedEvictions)
355+
}
356+
})
333357
}
334358
}

0 commit comments

Comments
 (0)