Change:
treats any error returned by the condition as terminal, but silently ignores any errors that aren't returned along with . We should change WaitForPodCondition to behave like . /sig testing /area e2e-test-framework
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules: After 90d of inactivity, is applied After 30d of inactivity since was applied, is applied After 30d of inactivity since was applied, the issue is closed You can: Mark this issue or PR as fresh with Mark this issue or PR as rotten with Close this issue or PR with Offer to help out with [Issue Triage][1] Please send feedback to sig-contributor-experience at . /lifecycle stale [1]:
/remove-lifecycle stale
Was there any reason why you instead of doing this right away? I fully agree with this issue, we should abort early. I just found the TODO because I have a failing test that ran longer than expected after a final pod failure and that made me check out why it didn't abort quicker :grin:

Discussion:
import ( "context" <ins> "errors" </ins> "fmt" "os" "path/filepath"

// errPodCompleted is returned by PodRunning or PodContainerRunning to indicate that // the pod has already reached completed state. <del> var errPodCompleted = fmt.Errorf("pod ran to completion") </del> <ins> var errPodCompleted = FinalError(errors.New("pod ran to completion successfully")) // errPodFailed is returned by PodRunning or PodContainerRunning to indicate that // the pod has already reached a permanent failue state. var errPodFailed = FinalError(errors.New("pod failed permanently")) </ins> // LabelLogOnPodFailure can be used to mark which Pods will have their logs logged in the case of // a test failure. By default, if there are no Pods with this label, only the first 5 Pods will

} } <ins> // FinalError constructs an error that indicates to a poll function that // polling can be stopped immediately because some permanent error has been // encountered that is not going to go away. // // TODO (@pohly): move this into framework once the refactoring from // https://github.com/kubernetes/kubernetes/pull/112043 allows it. Right now it // leads to circular dependencies. func FinalError(err error) error { return &FinalErr{Err: err} } type FinalErr struct { Err error } func (err *FinalErr) Error() string { if err.Err != nil { return fmt.Sprintf("final error: %s", err.Err.Error()) } return "final error, exact problem unknown" } func (err *FinalErr) Unwrap() error { return err.Err } // IsFinal checks whether the error was marked as final by wrapping some error // with FinalError. func IsFinal(err error) bool { var finalErr *FinalErr return errors.As(err, &finalErr) } </ins> // maybeTimeoutError returns a TimeoutError if err is a timeout. Otherwise, wrap err. // taskFormat and taskArgs should be the task being performed when the error occurred, // e.g. "waiting for pod to be running".

} // WaitForPodCondition waits a pods to be matched to the given condition. <ins> // If the condition callback returns an error that matches FinalErr (checked with IsFinal), // then polling aborts early. </ins> func WaitForPodCondition(c clientset.Interface, ns, podName, conditionDesc string, timeout time.Duration, condition podCondition) error { e2elog.Logf("Waiting up to %v for pod %q in namespace %q to be %q", timeout, podName, ns, conditionDesc) var (

} return true, err } else if err != nil { <del> // TODO(#109732): stop polling and return the error in this case. </del> e2elog.Logf("Error evaluating pod condition %s: %v", conditionDesc, err) <ins> if IsFinal(err) { return false, err } </ins> } return false, nil })

switch pod.Status.Phase { case v1.PodRunning: return true, nil <del> case v1.PodFailed, v1.PodSucceeded: </del> <ins> case v1.PodFailed: return false, errPodFailed case v1.PodSucceeded: </ins> return false, errPodCompleted } return false, nil

func WaitTimeoutForPodReadyInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error { return WaitForPodCondition(c, namespace, podName, "running and ready", timeout, func(pod *v1.Pod) (bool, error) { switch pod.Status.Phase { <del> case v1.PodFailed, v1.PodSucceeded: </del> <ins> case v1.PodFailed: e2elog.Logf("The phase of Pod %s is %s which is unexpected, pod status: %#v", pod.Name, pod.Status.Phase, pod.Status) return false, errPodFailed case v1.PodSucceeded: </ins> e2elog.Logf("The phase of Pod %s is %s which is unexpected, pod status: %#v", pod.Name, pod.Status.Phase, pod.Status) return false, errPodCompleted case v1.PodRunning: