@@ -19,19 +19,14 @@ package drain
19
19
import (
20
20
"errors"
21
21
"fmt"
22
- "math"
23
- "time"
24
22
25
23
"github.com/spf13/cobra"
26
24
27
25
corev1 "k8s.io/api/core/v1"
28
- apierrors "k8s.io/apimachinery/pkg/api/errors"
29
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30
26
"k8s.io/apimachinery/pkg/labels"
31
27
"k8s.io/apimachinery/pkg/runtime/schema"
32
28
utilerrors "k8s.io/apimachinery/pkg/util/errors"
33
29
"k8s.io/apimachinery/pkg/util/sets"
34
- "k8s.io/apimachinery/pkg/util/wait"
35
30
36
31
"k8s.io/cli-runtime/pkg/genericclioptions"
37
32
"k8s.io/cli-runtime/pkg/printers"
@@ -146,14 +141,34 @@ var (
146
141
)
147
142
148
143
func NewDrainCmdOptions (f cmdutil.Factory , ioStreams genericclioptions.IOStreams ) * DrainCmdOptions {
149
- return & DrainCmdOptions {
144
+ o := & DrainCmdOptions {
150
145
PrintFlags : genericclioptions .NewPrintFlags ("drained" ).WithTypeSetter (scheme .Scheme ),
151
146
IOStreams : ioStreams ,
152
147
drainer : & drain.Helper {
153
148
GracePeriodSeconds : - 1 ,
149
+ Out : ioStreams .Out ,
154
150
ErrOut : ioStreams .ErrOut ,
155
151
},
156
152
}
153
+ o .drainer .OnPodDeletedOrEvicted = o .onPodDeletedOrEvicted
154
+ return o
155
+ }
156
+
157
+ // onPodDeletedOrEvicted is called by drain.Helper, when the pod has been deleted or evicted
158
+ func (o * DrainCmdOptions ) onPodDeletedOrEvicted (pod * corev1.Pod , usingEviction bool ) {
159
+ var verbStr string
160
+ if usingEviction {
161
+ verbStr = "evicted"
162
+ } else {
163
+ verbStr = "deleted"
164
+ }
165
+ printObj , err := o .ToPrinter (verbStr )
166
+ if err != nil {
167
+ fmt .Fprintf (o .ErrOut , "error building printer: %v\n " , err )
168
+ fmt .Fprintf (o .Out , "pod %s/%s %s\n " , pod .Namespace , pod .Name , verbStr )
169
+ } else {
170
+ printObj (pod , o .Out )
171
+ }
157
172
}
158
173
159
174
func NewCmdDrain (f cmdutil.Factory , ioStreams genericclioptions.IOStreams ) * cobra.Command {
@@ -313,7 +328,7 @@ func (o *DrainCmdOptions) deleteOrEvictPodsSimple(nodeInfo *resource.Info) error
313
328
fmt .Fprintf (o .ErrOut , "WARNING: %s\n " , warnings )
314
329
}
315
330
316
- if err := o .deleteOrEvictPods (list .Pods ()); err != nil {
331
+ if err := o .drainer . DeleteOrEvictPods (list .Pods ()); err != nil {
317
332
pendingList , newErrs := o .drainer .GetPodsForDeletion (nodeInfo .Name )
318
333
319
334
fmt .Fprintf (o .ErrOut , "There are pending pods in node %q when an error occurred: %v\n " , nodeInfo .Name , err )
@@ -328,136 +343,6 @@ func (o *DrainCmdOptions) deleteOrEvictPodsSimple(nodeInfo *resource.Info) error
328
343
return nil
329
344
}
330
345
331
- // deleteOrEvictPods deletes or evicts the pods on the api server
332
- func (o * DrainCmdOptions ) deleteOrEvictPods (pods []corev1.Pod ) error {
333
- if len (pods ) == 0 {
334
- return nil
335
- }
336
-
337
- policyGroupVersion , err := drain .CheckEvictionSupport (o .drainer .Client )
338
- if err != nil {
339
- return err
340
- }
341
-
342
- getPodFn := func (namespace , name string ) (* corev1.Pod , error ) {
343
- return o .drainer .Client .CoreV1 ().Pods (namespace ).Get (name , metav1.GetOptions {})
344
- }
345
-
346
- if len (policyGroupVersion ) > 0 {
347
- return o .evictPods (pods , policyGroupVersion , getPodFn )
348
- } else {
349
- return o .deletePods (pods , getPodFn )
350
- }
351
- }
352
-
353
- func (o * DrainCmdOptions ) evictPods (pods []corev1.Pod , policyGroupVersion string , getPodFn func (namespace , name string ) (* corev1.Pod , error )) error {
354
- returnCh := make (chan error , 1 )
355
-
356
- for _ , pod := range pods {
357
- go func (pod corev1.Pod , returnCh chan error ) {
358
- for {
359
- fmt .Fprintf (o .Out , "evicting pod %q\n " , pod .Name )
360
- err := o .drainer .EvictPod (pod , policyGroupVersion )
361
- if err == nil {
362
- break
363
- } else if apierrors .IsNotFound (err ) {
364
- returnCh <- nil
365
- return
366
- } else if apierrors .IsTooManyRequests (err ) {
367
- fmt .Fprintf (o .ErrOut , "error when evicting pod %q (will retry after 5s): %v\n " , pod .Name , err )
368
- time .Sleep (5 * time .Second )
369
- } else {
370
- returnCh <- fmt .Errorf ("error when evicting pod %q: %v" , pod .Name , err )
371
- return
372
- }
373
- }
374
- _ , err := o .waitForDelete ([]corev1.Pod {pod }, 1 * time .Second , time .Duration (math .MaxInt64 ), true , getPodFn )
375
- if err == nil {
376
- returnCh <- nil
377
- } else {
378
- returnCh <- fmt .Errorf ("error when waiting for pod %q terminating: %v" , pod .Name , err )
379
- }
380
- }(pod , returnCh )
381
- }
382
-
383
- doneCount := 0
384
- var errors []error
385
-
386
- // 0 timeout means infinite, we use MaxInt64 to represent it.
387
- var globalTimeout time.Duration
388
- if o .drainer .Timeout == 0 {
389
- globalTimeout = time .Duration (math .MaxInt64 )
390
- } else {
391
- globalTimeout = o .drainer .Timeout
392
- }
393
- globalTimeoutCh := time .After (globalTimeout )
394
- numPods := len (pods )
395
- for doneCount < numPods {
396
- select {
397
- case err := <- returnCh :
398
- doneCount ++
399
- if err != nil {
400
- errors = append (errors , err )
401
- }
402
- case <- globalTimeoutCh :
403
- return fmt .Errorf ("drain did not complete within %v" , globalTimeout )
404
- }
405
- }
406
- return utilerrors .NewAggregate (errors )
407
- }
408
-
409
- func (o * DrainCmdOptions ) deletePods (pods []corev1.Pod , getPodFn func (namespace , name string ) (* corev1.Pod , error )) error {
410
- // 0 timeout means infinite, we use MaxInt64 to represent it.
411
- var globalTimeout time.Duration
412
- if o .drainer .Timeout == 0 {
413
- globalTimeout = time .Duration (math .MaxInt64 )
414
- } else {
415
- globalTimeout = o .drainer .Timeout
416
- }
417
- for _ , pod := range pods {
418
- err := o .drainer .DeletePod (pod )
419
- if err != nil && ! apierrors .IsNotFound (err ) {
420
- return err
421
- }
422
- }
423
- _ , err := o .waitForDelete (pods , 1 * time .Second , globalTimeout , false , getPodFn )
424
- return err
425
- }
426
-
427
- func (o * DrainCmdOptions ) waitForDelete (pods []corev1.Pod , interval , timeout time.Duration , usingEviction bool , getPodFn func (string , string ) (* corev1.Pod , error )) ([]corev1.Pod , error ) {
428
- var verbStr string
429
- if usingEviction {
430
- verbStr = "evicted"
431
- } else {
432
- verbStr = "deleted"
433
- }
434
- printObj , err := o .ToPrinter (verbStr )
435
- if err != nil {
436
- return pods , err
437
- }
438
-
439
- err = wait .PollImmediate (interval , timeout , func () (bool , error ) {
440
- pendingPods := []corev1.Pod {}
441
- for i , pod := range pods {
442
- p , err := getPodFn (pod .Namespace , pod .Name )
443
- if apierrors .IsNotFound (err ) || (p != nil && p .ObjectMeta .UID != pod .ObjectMeta .UID ) {
444
- printObj (& pod , o .Out )
445
- continue
446
- } else if err != nil {
447
- return false , err
448
- } else {
449
- pendingPods = append (pendingPods , pods [i ])
450
- }
451
- }
452
- pods = pendingPods
453
- if len (pendingPods ) > 0 {
454
- return false , nil
455
- }
456
- return true , nil
457
- })
458
- return pods , err
459
- }
460
-
461
346
// RunCordonOrUncordon runs either Cordon or Uncordon. The desired value for
462
347
// "Unschedulable" is passed as the first arg.
463
348
func (o * DrainCmdOptions ) RunCordonOrUncordon (desired bool ) error {
0 commit comments