@@ -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/strategicpatch"
@@ -59,6 +60,7 @@ type DrainOptions struct {
59
60
Timeout time.Duration
60
61
backOff clockwork.Clock
61
62
DeleteLocalData bool
63
+ PodSelector string
62
64
mapper meta.RESTMapper
63
65
nodeInfo * resource.Info
64
66
Out io.Writer
@@ -190,6 +192,7 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
190
192
cmd .Flags ().BoolVar (& options .DeleteLocalData , "delete-local-data" , false , "Continue even if there are pods using emptyDir (local data that will be deleted when the node is drained)." )
191
193
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." )
192
194
cmd .Flags ().DurationVar (& options .Timeout , "timeout" , 0 , "The length of time to wait before giving up, zero means infinite" )
195
+ cmd .Flags ().StringVarP (& options .PodSelector , "pod-selector" , "" , options .PodSelector , "Label selector to filter pods on the node" )
193
196
return cmd
194
197
}
195
198
@@ -201,6 +204,12 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error {
201
204
return cmdutil .UsageErrorf (cmd , "USAGE: %s [flags]" , cmd .Use )
202
205
}
203
206
207
+ if len (o .PodSelector ) > 0 {
208
+ if _ , err := labels .Parse (o .PodSelector ); err != nil {
209
+ return errors .New ("--pod-selector=<pod_selector> must be a valid label selector" )
210
+ }
211
+ }
212
+
204
213
if o .client , err = o .Factory .ClientSet (); err != nil {
205
214
return err
206
215
}
@@ -268,38 +277,8 @@ func (o *DrainOptions) deleteOrEvictPodsSimple() error {
268
277
return err
269
278
}
270
279
271
- func (o * DrainOptions ) getController (namespace string , controllerRef * metav1.OwnerReference ) (interface {}, error ) {
272
- switch controllerRef .Kind {
273
- case "ReplicationController" :
274
- return o .client .Core ().ReplicationControllers (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
275
- case "DaemonSet" :
276
- return o .client .Extensions ().DaemonSets (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
277
- case "Job" :
278
- return o .client .Batch ().Jobs (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
279
- case "ReplicaSet" :
280
- return o .client .Extensions ().ReplicaSets (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
281
- case "StatefulSet" :
282
- return o .client .Apps ().StatefulSets (namespace ).Get (controllerRef .Name , metav1.GetOptions {})
283
- }
284
- return nil , fmt .Errorf ("Unknown controller kind %q" , controllerRef .Kind )
285
- }
286
-
287
- func (o * DrainOptions ) getPodController (pod api.Pod ) (* metav1.OwnerReference , error ) {
288
- controllerRef := metav1 .GetControllerOf (& pod )
289
- if controllerRef == nil {
290
- return nil , nil
291
- }
292
-
293
- // We assume the only reason for an error is because the controller is
294
- // gone/missing, not for any other cause.
295
- // TODO(mml): something more sophisticated than this
296
- // TODO(juntee): determine if it's safe to remove getController(),
297
- // so that drain can work for controller types that we don't know about
298
- _ , err := o .getController (pod .Namespace , controllerRef )
299
- if err != nil {
300
- return nil , err
301
- }
302
- return controllerRef , nil
280
+ func (o * DrainOptions ) getPodController (pod api.Pod ) * metav1.OwnerReference {
281
+ return metav1 .GetControllerOf (& pod )
303
282
}
304
283
305
284
func (o * DrainOptions ) unreplicatedFilter (pod api.Pod ) (bool , * warning , * fatal ) {
@@ -308,21 +287,15 @@ func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal)
308
287
return true , nil , nil
309
288
}
310
289
311
- controllerRef , err := o .getPodController (pod )
312
- if err != nil {
313
- // if we're forcing, remove orphaned pods with a warning
314
- if apierrors .IsNotFound (err ) && o .Force {
315
- return true , & warning {err .Error ()}, nil
316
- }
317
- return false , nil , & fatal {err .Error ()}
318
- }
290
+ controllerRef := o .getPodController (pod )
319
291
if controllerRef != nil {
320
292
return true , nil , nil
321
293
}
322
- if ! o .Force {
323
- return false , nil , & fatal { kUnmanagedFatal }
294
+ if o .Force {
295
+ return true , & warning { kUnmanagedWarning }, nil
324
296
}
325
- return true , & warning {kUnmanagedWarning }, nil
297
+
298
+ return false , nil , & fatal {kUnmanagedFatal }
326
299
}
327
300
328
301
func (o * DrainOptions ) daemonsetFilter (pod api.Pod ) (bool , * warning , * fatal ) {
@@ -333,23 +306,23 @@ func (o *DrainOptions) daemonsetFilter(pod api.Pod) (bool, *warning, *fatal) {
333
306
// The exception is for pods that are orphaned (the referencing
334
307
// management resource - including DaemonSet - is not found).
335
308
// Such pods will be deleted if --force is used.
336
- controllerRef , err := o .getPodController (pod )
337
- if err != nil {
338
- // if we're forcing, remove orphaned pods with a warning
339
- if apierrors .IsNotFound (err ) && o .Force {
340
- return true , & warning {err .Error ()}, nil
341
- }
342
- return false , nil , & fatal {err .Error ()}
343
- }
309
+ controllerRef := o .getPodController (pod )
344
310
if controllerRef == nil || controllerRef .Kind != "DaemonSet" {
345
311
return true , nil , nil
346
312
}
313
+
347
314
if _ , err := o .client .Extensions ().DaemonSets (pod .Namespace ).Get (controllerRef .Name , metav1.GetOptions {}); err != nil {
315
+ // remove orphaned pods with a warning if --force is used
316
+ if apierrors .IsNotFound (err ) && o .Force {
317
+ return true , & warning {err .Error ()}, nil
318
+ }
348
319
return false , nil , & fatal {err .Error ()}
349
320
}
321
+
350
322
if ! o .IgnoreDaemonsets {
351
323
return false , nil , & fatal {kDaemonsetFatal }
352
324
}
325
+
353
326
return false , & warning {kDaemonsetWarning }, nil
354
327
}
355
328
@@ -395,7 +368,13 @@ func (ps podStatuses) Message() string {
395
368
// getPodsForDeletion returns all the pods we're going to delete. If there are
396
369
// any pods preventing us from deleting, we return that list in an error.
397
370
func (o * DrainOptions ) getPodsForDeletion () (pods []api.Pod , err error ) {
371
+ labelSelector , err := labels .Parse (o .PodSelector )
372
+ if err != nil {
373
+ return pods , err
374
+ }
375
+
398
376
podList , err := o .client .Core ().Pods (metav1 .NamespaceAll ).List (metav1.ListOptions {
377
+ LabelSelector : labelSelector .String (),
399
378
FieldSelector : fields .SelectorFromSet (fields.Set {"spec.nodeName" : o .nodeInfo .Name }).String ()})
400
379
if err != nil {
401
380
return pods , err
0 commit comments