@@ -33,6 +33,7 @@ import (
33
33
"k8s.io/apimachinery/pkg/api/meta"
34
34
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35
35
"k8s.io/apimachinery/pkg/fields"
36
+ "k8s.io/apimachinery/pkg/labels"
36
37
"k8s.io/apimachinery/pkg/runtime"
37
38
"k8s.io/apimachinery/pkg/types"
38
39
"k8s.io/apimachinery/pkg/util/json"
@@ -61,6 +62,7 @@ type DrainOptions struct {
61
62
backOff clockwork.Clock
62
63
DeleteLocalData bool
63
64
Selector string
65
+ PodSelector string
64
66
mapper meta.RESTMapper
65
67
nodeInfos []* resource.Info
66
68
Out io.Writer
@@ -197,6 +199,8 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
197
199
cmd .Flags ().IntVar (& options .GracePeriodSeconds , "grace-period" , - 1 , "Period of time in seconds given to each pod to terminate gracefully. If negative, the default value specified in the pod will be used." )
198
200
cmd .Flags ().DurationVar (& options .Timeout , "timeout" , 0 , "The length of time to wait before giving up, zero means infinite" )
199
201
cmd .Flags ().StringVarP (& options .Selector , "selector" , "l" , options .Selector , "Selector (label query) to filter on" )
202
+ cmd .Flags ().StringVarP (& options .PodSelector , "pod-selector" , "" , options .PodSelector , "Label selector to filter pods on the node" )
203
+
200
204
cmdutil .AddDryRunFlag (cmd )
201
205
return cmd
202
206
}
@@ -223,6 +227,12 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
223
227
return err
224
228
}
225
229
230
+ if len (o .PodSelector ) > 0 {
231
+ if _ , err := labels .Parse (o .PodSelector ); err != nil {
232
+ return errors .New ("--pod-selector=<pod_selector> must be a valid label selector" )
233
+ }
234
+ }
235
+
226
236
o .restClient , err = o .Factory .RESTClient ()
227
237
if err != nil {
228
238
return err
@@ -328,38 +338,8 @@ func (o *DrainOptions) deleteOrEvictPodsSimple(nodeInfo *resource.Info) error {
328
338
return err
329
339
}
330
340
331
- func (o * DrainOptions ) getController (namespace string , controllerRef * metav1.OwnerReference ) (interface {}, error ) {
332
- switch controllerRef .Kind {
333
- case "ReplicationController" :
334
- return o .client .Core ().ReplicationControllers (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
335
- case "DaemonSet" :
336
- return o .client .Extensions ().DaemonSets (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
337
- case "Job" :
338
- return o .client .Batch ().Jobs (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
339
- case "ReplicaSet" :
340
- return o .client .Extensions ().ReplicaSets (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
341
- case "StatefulSet" :
342
- return o .client .AppsV1beta1 ().StatefulSets (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
343
- }
344
- return nil , fmt .Errorf ("Unknown controller kind %q" , controllerRef .Kind )
345
- }
346
-
347
- func (o * DrainOptions ) getPodController (pod corev1.Pod ) (* metav1.OwnerReference , error ) {
348
- controllerRef := metav1 .GetControllerOf (& pod )
349
- if controllerRef == nil {
350
- return nil , nil
351
- }
352
-
353
- // We assume the only reason for an error is because the controller is
354
- // gone/missing, not for any other cause.
355
- // TODO(mml): something more sophisticated than this
356
- // TODO(juntee): determine if it's safe to remove getController(),
357
- // so that drain can work for controller types that we don't know about
358
- _ , err := o .getController (pod .Namespace , controllerRef )
359
- if err != nil {
360
- return nil , err
361
- }
362
- return controllerRef , nil
341
+ func (o * DrainOptions ) getPodController (pod corev1.Pod ) * metav1.OwnerReference {
342
+ return metav1 .GetControllerOf (& pod )
363
343
}
364
344
365
345
func (o * DrainOptions ) unreplicatedFilter (pod corev1.Pod ) (bool , * warning , * fatal ) {
@@ -368,21 +348,15 @@ func (o *DrainOptions) unreplicatedFilter(pod corev1.Pod) (bool, *warning, *fata
368
348
return true , nil , nil
369
349
}
370
350
371
- controllerRef , err := o .getPodController (pod )
372
- if err != nil {
373
- // if we're forcing, remove orphaned pods with a warning
374
- if apierrors .IsNotFound (err ) && o .Force {
375
- return true , & warning {err .Error ()}, nil
376
- }
377
- return false , nil , & fatal {err .Error ()}
378
- }
351
+ controllerRef := o .getPodController (pod )
379
352
if controllerRef != nil {
380
353
return true , nil , nil
381
354
}
382
- if ! o .Force {
383
- return false , nil , & fatal { kUnmanagedFatal }
355
+ if o .Force {
356
+ return true , & warning { kUnmanagedWarning }, nil
384
357
}
385
- return true , & warning {kUnmanagedWarning }, nil
358
+
359
+ return false , nil , & fatal {kUnmanagedFatal }
386
360
}
387
361
388
362
func (o * DrainOptions ) daemonsetFilter (pod corev1.Pod ) (bool , * warning , * fatal ) {
@@ -393,23 +367,22 @@ func (o *DrainOptions) daemonsetFilter(pod corev1.Pod) (bool, *warning, *fatal)
393
367
// The exception is for pods that are orphaned (the referencing
394
368
// management resource - including DaemonSet - is not found).
395
369
// Such pods will be deleted if --force is used.
396
- controllerRef , err := o .getPodController (pod )
397
- if err != nil {
398
- // if we're forcing, remove orphaned pods with a warning
399
- if apierrors .IsNotFound (err ) && o .Force {
400
- return true , & warning {err .Error ()}, nil
401
- }
402
- return false , nil , & fatal {err .Error ()}
403
- }
370
+ controllerRef := o .getPodController (pod )
404
371
if controllerRef == nil || controllerRef .Kind != "DaemonSet" {
405
372
return true , nil , nil
406
373
}
374
+
407
375
if _ , err := o .client .Extensions ().DaemonSets (pod .Namespace ).Get (controllerRef .Name , metav1.GetOptions {}); err != nil {
376
+ // remove orphaned pods with a warning if --force is used
377
+ if apierrors .IsNotFound (err ) && o .Force {
378
+ return true , & warning {err .Error ()}, nil
379
+ }
408
380
return false , nil , & fatal {err .Error ()}
409
381
}
410
382
if ! o .IgnoreDaemonsets {
411
383
return false , nil , & fatal {kDaemonsetFatal }
412
384
}
385
+
413
386
return false , & warning {kDaemonsetWarning }, nil
414
387
}
415
388
@@ -455,7 +428,13 @@ func (ps podStatuses) Message() string {
455
428
// getPodsForDeletion receives resource info for a node, and returns all the pods from the given node that we
456
429
// are planning on deleting. If there are any pods preventing us from deleting, we return that list in an error.
457
430
func (o * DrainOptions ) getPodsForDeletion (nodeInfo * resource.Info ) (pods []corev1.Pod , err error ) {
431
+ labelSelector , err := labels .Parse (o .PodSelector )
432
+ if err != nil {
433
+ return pods , err
434
+ }
435
+
458
436
podList , err := o .client .Core ().Pods (metav1 .NamespaceAll ).List (metav1.ListOptions {
437
+ LabelSelector : labelSelector .String (),
459
438
FieldSelector : fields .SelectorFromSet (fields.Set {"spec.nodeName" : nodeInfo .Name }).String ()})
460
439
if err != nil {
461
440
return pods , err
0 commit comments