Change:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . --Is this a BUG REPORT or FEATURE REQUEST?: /kind bug What happened: See One /sig storage
/assign
[Slow] test suite was run. Glusterfs io stream test failed due to ns not being deleted, which was due to 1 pod remaining. The glusterfs-server pod was deleted. It appears that the glusterfs-client pod was not deleted even though returned no error. In cases where this test succeeds (which is most of the time) returns which is seen in the log as INFO: Ignore "not found" error above. Pod "gluster-io-client" successfully deleted. Sometimes when the plugin io streaming tests pass you'll see logged for the client pod. However, sometimes a client pod is deleted but the above log entry is not triggered. Eg in you'll see the nfs-client pod is deleted (the ns was able to be deleted) yet the above log msg stating to ignore the "not found" error was not generated. (scroll down to the line "I0724 20:27:20.364] Jul 24 20:27:00.559: INFO: Waiting for pod nfs-io-client in namespace 'e2e-tests-volume-io-pmdks' status to be 'terminated due to deadline exceeded'(found phase: "Running", readiness: true) (29.883170178s elapsed) I0724 20:27:20.365] [AfterEach] [sig-storage] NFS"). My guess is that in this case the plugin's client pod did not terminate in 30s -- WHY NOT THE FULL 5m? -- but did terminate in time for the ns to be deleted. And sometimes the client pod cannot be deleted in 30s (again WHY NOT THE FULL 5m?) and is still present when the ns is deleted. Note: if we cannot detect that the client pod was not actually deleted and then we delete the server pod, there is no chance that the ns can be deleted. Once the server pod is gone the client pod will not delete.
It looks like the client pod failed to terminate:
30s may not always be enough time for the gluster client pod to terminate?
also, why is it so common to see ~29 seconds for the client pods (nfs, gluster) to supposedly terminate. The wait should be for up to 5m yet I never see = 30s wait times... yet, we know that sometimes the gluster client pod is not terminated. Seems like maybe a bug in this area?
can you take a look? My findings so far are this test fails about 20% of the time. The gluster client pod's Status is set to Failed and therefore the pod won't be deleted. There is e2e code that waits for the pod to be deleted but escapes if the pod has "Failed" and if the passed-in reason matches the pod's Status.Reason. In the gluster pod test failures the pod's Status.Reason == "". This causes the test to incorrectly assume that the pod was deleted when it wasn't. This problem manifests itself when the namespace is deleted and that step fails. It seems like the Failed pod's Status.Reason should not be blank. cc
It looks like gluster unmount failed:
But in the log I looked at today (https://k8s-) I see the pod's Status=Running. Then the pod is deleted and the status remains Running for ~30s then changes to Failed. Even though the pod is Failed its Reason remains "". So 1) I wonder why the pod is marked as Running if its mount failed, and 2) once the pod is Failed why is Reason still blank?
It was the unmount that failed, not the mount.
ah, ok thanks, I missed that. Still need to know why Pod.Status.Reason is blank...
Below are some records from a related to the glusterfs-client pod, gluster-io-cliente2e-tests-volume-io-6h140(-778e-11e7-afad-)_ and the "e2e-tests-volume-io-6h140" ns:
I think the issue is that the test is deleting the gluster endpoints before deleting the pod.
Nm, the test does seem to be cleaning up in the correct order: client pod, then server pod and endpoints. So the issue seems to be that during Pod termination, it goes to Failed state. Before, I thought it was because the unmount failed, but based on the timestamps of the logs, it seems like it fails before we start unmounting.
Just spoke to and he said that it's normal for a Pod to go to Failed state during the termination sequence. In between Failed state and Pod object deletion is when we unmount the volumes. So I think the issue here is that the WaitForPodTerminated function needs to wait only for the Pod object to be deleted, and not return early if Pod state is Failed.
do you have time to look at this? The test is still flaking
yes I can take a look. Do you know if there has been a pr started to address this issue? BTW, I will be gone most of tomorrow but will start tomorrow night.

Discussion:
return waitForPodTerminatedInNamespace(f.ClientSet, podName, reason, f.Namespace.Name) } <ins> // WaitForPodNotFound waits for the pod to be completely terminated (not "Get-able"). func (f *Framework) WaitForPodNotFound(podName string, timeout time.Duration) error { return waitForPodNotFoundInNamespace(f.ClientSet, podName, f.Namespace.Name, timeout) } </ins> // WaitForPodRunning waits for the pod to run in the namespace. func (f *Framework) WaitForPodRunning(podName string) error { return WaitForPodNameRunningInNamespace(f.ClientSet, podName, f.Namespace.Name)

// Deletes the passed-in pod and waits for the pod to be terminated. Resilient to the pod // not existing. func DeletePodWithWait(f *Framework, c clientset.Interface, pod *v1.Pod) error { <ins> const maxWait = 5 * time.Minute </ins> if pod == nil { return nil } <del> Logf("Deleting pod %v", pod.Name) </del> <ins> Logf("Deleting pod %q in namespace %q", pod.Name, pod.Namespace) </ins> err := c.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil) if err != nil { if apierrs.IsNotFound(err) { <del> return nil // assume pod was deleted already </del> <ins> return nil // assume pod was already deleted </ins> } <del> return fmt.Errorf("pod Get API error: %v", err) </del> <ins> return fmt.Errorf("pod Delete API error: %v", err) </ins> } <del> // wait for pod to terminate err = f.WaitForPodTerminated(pod.Name, "") if err != nil && !apierrs.IsNotFound(err) { return fmt.Errorf("error deleting pod %q: %v", pod.Name, err) } if apierrs.IsNotFound(err) { Logf("Ignore "not found" error above. Pod %q successfully deleted", pod.Name) </del> <ins> Logf("Wait up to %v for pod %q to be fully deleted", maxWait, pod.Name) err = f.WaitForPodNotFound(pod.Name, maxWait) if err != nil { return fmt.Errorf("pod %q was not deleted: %v", pod.Name, err) </ins> } return nil }

}) } <ins> // waitForPodNotFoundInNamespace returns an error if it takes too long for the pod to fully terminate. // Unlike `waitForPodTerminatedInNamespace`, the pod's Phase and Reason are ignored. If the pod Get // api returns IsNotFound then the wait stops and nil is returned. If the Get api returns an error other // than "not found" then that error is returned and the wait stops. func waitForPodNotFoundInNamespace(c clientset.Interface, podName, ns string, timeout time.Duration) error { return wait.PollImmediate(Poll, timeout, func() (bool, error) { _, err := c.CoreV1().Pods(ns).Get(podName, metav1.GetOptions{}) if apierrs.IsNotFound(err) { return true, nil // done } if err != nil { return true, err // stop wait with error } return false, nil }) } </ins> // waitForPodSuccessInNamespaceTimeout returns nil if the pod reached state success, or an error if it reached failure or ran too long. func waitForPodSuccessInNamespaceTimeout(c clientset.Interface, podName string, namespace string, timeout time.Duration) error { return WaitForPodCondition(c, namespace, podName, "success or failure", timeout, func(pod *v1.Pod) (bool, error) {

}) AfterEach(func() { <del> framework.ExpectNoError(framework.DeletePodWithWait(f, c, pod), "AfterEach: Failed to delete pod ", pod.Name) framework.ExpectNoError(framework.DeletePodWithWait(f, c, nfsServerPod), "AfterEach: Failed to delete pod ", nfsServerPod.Name) </del> <ins> err := framework.DeletePodWithWait(f, c, pod) Expect(err).NotTo(HaveOccurred(), "AfterEach: Failed to delete client pod ", pod.Name) err = framework.DeletePodWithWait(f, c, nfsServerPod) Expect(err).NotTo(HaveOccurred(), "AfterEach: Failed to delete server pod ", nfsServerPod.Name) </ins> }) // execute It blocks from above table of tests

By("Stop the NFS server") stopNfsServer(nfsServerPod) <del> By("Delete the pod mounted to the NFS volume") framework.ExpectNoError(framework.DeletePodWithWait(f, c, pod), "Failed to delete pod ", pod.Name) </del> <ins> By("Delete the pod mounted to the NFS volume -- expect failure") err := framework.DeletePodWithWait(f, c, pod) Expect(err).To(HaveOccurred()) </ins> // pod object is now stale, but is intentionally not nil By("Check if pod's host has been cleaned up -- expect not")

By("Restart the nfs server") restartNfsServer(nfsServerPod) <del> By("Verify host running the deleted pod is now cleaned up") </del> <ins> By("Verify that the deleted client pod is now cleaned up") </ins> checkPodCleanup(c, pod, true) }) }