From 08a092830dbb35ef789eb8f9e2e7d28d3065272c Mon Sep 17 00:00:00 2001 From: juanvallejo Date: Mon, 18 Dec 2017 17:01:23 -0500 Subject: [PATCH 1/2] UPSTREAM: 56864: pick pod-selector changes from #56864: pick of origin #17616 --- .../kubernetes/pkg/kubectl/cmd/drain.go | 81 +++++++------------ 1 file changed, 30 insertions(+), 51 deletions(-) diff --git a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go index 5a7c9db38ba9..4e59f91ec8bc 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go +++ b/vendor/k8s.io/kubernetes/pkg/kubectl/cmd/drain.go @@ -33,6 +33,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/strategicpatch" @@ -59,6 +60,7 @@ type DrainOptions struct { Timeout time.Duration backOff clockwork.Clock DeleteLocalData bool + PodSelector string mapper meta.RESTMapper nodeInfo *resource.Info Out io.Writer @@ -190,6 +192,7 @@ func NewCmdDrain(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { 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).") 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.") cmd.Flags().DurationVar(&options.Timeout, "timeout", 0, "The length of time to wait before giving up, zero means infinite") + cmd.Flags().StringVarP(&options.PodSelector, "pod-selector", "", options.PodSelector, "Label selector to filter pods on the node") return cmd } @@ -201,6 +204,12 @@ func (o *DrainOptions) SetupDrain(cmd *cobra.Command, args []string) error { return cmdutil.UsageErrorf(cmd, "USAGE: %s [flags]", cmd.Use) } + if len(o.PodSelector) > 0 { + if _, err := labels.Parse(o.PodSelector); err != nil { + return errors.New("--pod-selector= must be a valid label selector") + } + } + if o.client, err = o.Factory.ClientSet(); err != nil { return err } @@ -268,38 +277,8 @@ func (o *DrainOptions) deleteOrEvictPodsSimple() error { return err } -func (o *DrainOptions) getController(namespace string, controllerRef *metav1.OwnerReference) (interface{}, error) { - switch controllerRef.Kind { - case "ReplicationController": - return o.client.Core().ReplicationControllers(namespace).Get(controllerRef.Name, metav1.GetOptions{}) - case "DaemonSet": - return o.client.Extensions().DaemonSets(namespace).Get(controllerRef.Name, metav1.GetOptions{}) - case "Job": - return o.client.Batch().Jobs(namespace).Get(controllerRef.Name, metav1.GetOptions{}) - case "ReplicaSet": - return o.client.Extensions().ReplicaSets(namespace).Get(controllerRef.Name, metav1.GetOptions{}) - case "StatefulSet": - return o.client.Apps().StatefulSets(namespace).Get(controllerRef.Name, metav1.GetOptions{}) - } - return nil, fmt.Errorf("Unknown controller kind %q", controllerRef.Kind) -} - -func (o *DrainOptions) getPodController(pod api.Pod) (*metav1.OwnerReference, error) { - controllerRef := metav1.GetControllerOf(&pod) - if controllerRef == nil { - return nil, nil - } - - // We assume the only reason for an error is because the controller is - // gone/missing, not for any other cause. - // TODO(mml): something more sophisticated than this - // TODO(juntee): determine if it's safe to remove getController(), - // so that drain can work for controller types that we don't know about - _, err := o.getController(pod.Namespace, controllerRef) - if err != nil { - return nil, err - } - return controllerRef, nil +func (o *DrainOptions) getPodController(pod api.Pod) *metav1.OwnerReference { + return metav1.GetControllerOf(&pod) } func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal) { @@ -308,21 +287,15 @@ func (o *DrainOptions) unreplicatedFilter(pod api.Pod) (bool, *warning, *fatal) return true, nil, nil } - controllerRef, err := o.getPodController(pod) - if err != nil { - // if we're forcing, remove orphaned pods with a warning - if apierrors.IsNotFound(err) && o.Force { - return true, &warning{err.Error()}, nil - } - return false, nil, &fatal{err.Error()} - } + controllerRef := o.getPodController(pod) if controllerRef != nil { return true, nil, nil } - if !o.Force { - return false, nil, &fatal{kUnmanagedFatal} + if o.Force { + return true, &warning{kUnmanagedWarning}, nil } - return true, &warning{kUnmanagedWarning}, nil + + return false, nil, &fatal{kUnmanagedFatal} } func (o *DrainOptions) daemonsetFilter(pod api.Pod) (bool, *warning, *fatal) { @@ -333,23 +306,23 @@ func (o *DrainOptions) daemonsetFilter(pod api.Pod) (bool, *warning, *fatal) { // The exception is for pods that are orphaned (the referencing // management resource - including DaemonSet - is not found). // Such pods will be deleted if --force is used. - controllerRef, err := o.getPodController(pod) - if err != nil { - // if we're forcing, remove orphaned pods with a warning - if apierrors.IsNotFound(err) && o.Force { - return true, &warning{err.Error()}, nil - } - return false, nil, &fatal{err.Error()} - } + controllerRef := o.getPodController(pod) if controllerRef == nil || controllerRef.Kind != "DaemonSet" { return true, nil, nil } + if _, err := o.client.Extensions().DaemonSets(pod.Namespace).Get(controllerRef.Name, metav1.GetOptions{}); err != nil { + // remove orphaned pods with a warning if --force is used + if apierrors.IsNotFound(err) && o.Force { + return true, &warning{err.Error()}, nil + } return false, nil, &fatal{err.Error()} } + if !o.IgnoreDaemonsets { return false, nil, &fatal{kDaemonsetFatal} } + return false, &warning{kDaemonsetWarning}, nil } @@ -395,7 +368,13 @@ func (ps podStatuses) Message() string { // getPodsForDeletion returns all the pods we're going to delete. If there are // any pods preventing us from deleting, we return that list in an error. func (o *DrainOptions) getPodsForDeletion() (pods []api.Pod, err error) { + labelSelector, err := labels.Parse(o.PodSelector) + if err != nil { + return pods, err + } + podList, err := o.client.Core().Pods(metav1.NamespaceAll).List(metav1.ListOptions{ + LabelSelector: labelSelector.String(), FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": o.nodeInfo.Name}).String()}) if err != nil { return pods, err From 67ed27a809def1e9f70192354e1126bf12295014 Mon Sep 17 00:00:00 2001 From: juanvallejo Date: Mon, 18 Dec 2017 17:01:29 -0500 Subject: [PATCH 2/2] update completions --- contrib/completions/bash/oc | 2 ++ contrib/completions/zsh/oc | 2 ++ 2 files changed, 4 insertions(+) diff --git a/contrib/completions/bash/oc b/contrib/completions/bash/oc index e0f5d2856d9c..0f996d525476 100644 --- a/contrib/completions/bash/oc +++ b/contrib/completions/bash/oc @@ -2447,6 +2447,8 @@ _oc_adm_drain() local_nonpersistent_flags+=("--grace-period=") flags+=("--ignore-daemonsets") local_nonpersistent_flags+=("--ignore-daemonsets") + flags+=("--pod-selector=") + local_nonpersistent_flags+=("--pod-selector=") flags+=("--timeout=") local_nonpersistent_flags+=("--timeout=") flags+=("--as=") diff --git a/contrib/completions/zsh/oc b/contrib/completions/zsh/oc index 4aadc20be239..20f81acfaf75 100644 --- a/contrib/completions/zsh/oc +++ b/contrib/completions/zsh/oc @@ -2589,6 +2589,8 @@ _oc_adm_drain() local_nonpersistent_flags+=("--grace-period=") flags+=("--ignore-daemonsets") local_nonpersistent_flags+=("--ignore-daemonsets") + flags+=("--pod-selector=") + local_nonpersistent_flags+=("--pod-selector=") flags+=("--timeout=") local_nonpersistent_flags+=("--timeout=") flags+=("--as=")