From de06b92a126f1505ab7ddf438225158563dde25d Mon Sep 17 00:00:00 2001 From: Ryan Phillips Date: Fri, 20 Mar 2020 14:43:33 -0500 Subject: [PATCH 1/2] drain: eviction creates in a deleting namespace will throw a forbidden error we can safely ignore this error since a deleting namespace will delete all pods Kubernetes-commit: 93f62dad6c58bb41c396c48f54c0a73830779599 --- pkg/drain/drain.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/drain/drain.go b/pkg/drain/drain.go index a6657d1a7..d613c8210 100644 --- a/pkg/drain/drain.go +++ b/pkg/drain/drain.go @@ -277,6 +277,9 @@ func (d *Helper) evictPods(pods []corev1.Pod, policyGroupVersion string, getPodF } else if apierrors.IsTooManyRequests(err) { fmt.Fprintf(d.ErrOut, "error when evicting pods/%q -n %q (will retry after 5s): %v\n", pod.Name, pod.Namespace, err) time.Sleep(5 * time.Second) + } else if apierrors.IsForbidden(err) { + // an eviction request in a deleting namespace will throw a forbidden error + break } else { returnCh <- fmt.Errorf("error when evicting pods/%q -n %q: %v", pod.Name, pod.Namespace, err) return From e5ddedb459b8313fc89fc172560448624e54e1e6 Mon Sep 17 00:00:00 2001 From: Michael Gugino Date: Wed, 12 Aug 2020 16:15:54 -0400 Subject: [PATCH 2/2] Handle eviction of pods in deleted namespace If a pod is already marked deleted, and the eviction api returns an unauthorized response, ignore that error since the pod is marked for deletion already. If the pod is not already marked deleted, retry. Kubernetes-commit: 8d2a2ffe014ed06b5f8971e7f3dc25ec155e44d4 --- pkg/drain/drain.go | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/pkg/drain/drain.go b/pkg/drain/drain.go index d613c8210..30b790a9c 100644 --- a/pkg/drain/drain.go +++ b/pkg/drain/drain.go @@ -254,6 +254,7 @@ func (d *Helper) evictPods(pods []corev1.Pod, policyGroupVersion string, getPodF defer cancel() for _, pod := range pods { go func(pod corev1.Pod, returnCh chan error) { + refreshPod := false for { switch d.DryRunStrategy { case cmdutil.DryRunServer: @@ -268,20 +269,40 @@ func (d *Helper) evictPods(pods []corev1.Pod, policyGroupVersion string, getPodF return default: } - err := d.EvictPod(pod, policyGroupVersion) + + // Create a temporary pod so we don't mutate the pod in the loop. + activePod := pod + if refreshPod { + freshPod, err := getPodFn(pod.Namespace, pod.Name) + // We ignore errors and let eviction sort it out with + // the original pod. + if err == nil { + activePod = *freshPod + } + refreshPod = false + } + + err := d.EvictPod(activePod, policyGroupVersion) if err == nil { break } else if apierrors.IsNotFound(err) { returnCh <- nil return } else if apierrors.IsTooManyRequests(err) { - fmt.Fprintf(d.ErrOut, "error when evicting pods/%q -n %q (will retry after 5s): %v\n", pod.Name, pod.Namespace, err) + fmt.Fprintf(d.ErrOut, "error when evicting pods/%q -n %q (will retry after 5s): %v\n", activePod.Name, activePod.Namespace, err) time.Sleep(5 * time.Second) - } else if apierrors.IsForbidden(err) { - // an eviction request in a deleting namespace will throw a forbidden error + } else if !activePod.ObjectMeta.DeletionTimestamp.IsZero() && apierrors.IsForbidden(err) && apierrors.HasStatusCause(err, corev1.NamespaceTerminatingCause) { + // an eviction request in a deleting namespace will throw a forbidden error, + // if the pod is already marked deleted, we can ignore this error, an eviction + // request will never succeed, but we will waitForDelete for this pod. break + } else if apierrors.IsForbidden(err) && apierrors.HasStatusCause(err, corev1.NamespaceTerminatingCause) { + // an eviction request in a deleting namespace will throw a forbidden error, + // if the pod is not marked deleted, we retry until it is. + fmt.Fprintf(d.ErrOut, "error when evicting pod %q (will retry after 5s): %v\n", activePod.Name, err) + time.Sleep(5 * time.Second) } else { - returnCh <- fmt.Errorf("error when evicting pods/%q -n %q: %v", pod.Name, pod.Namespace, err) + returnCh <- fmt.Errorf("error when evicting pods/%q -n %q: %v", activePod.Name, activePod.Namespace, err) return } }