diff --git a/test/e2e/framework/pods.go b/test/e2e/framework/pods.go index fb9e8a57572..03c38192e2b 100644 --- a/test/e2e/framework/pods.go +++ b/test/e2e/framework/pods.go @@ -78,6 +78,32 @@ func (c *PodClient) Create(pod *v1.Pod) *v1.Pod { return p } +// CreateEventually retries pod creation for a while before failing +// the test with the most recent error. This mimicks the behavior +// of a controller (like the one for DaemonSet) and is necessary +// because pod creation can fail while its service account is still +// getting provisioned +// (https://github.com/kubernetes/kubernetes/issues/68776). +// +// Both the timeout and polling interval are configurable as optional +// arguments: +// - The first optional argument is the timeout. +// - The second optional argument is the polling interval. +// +// Both intervals can either be specified as time.Duration, parsable +// duration strings or as floats/integers. In the last case they are +// interpreted as seconds. +func (c *PodClient) CreateEventually(pod *v1.Pod, opts ...interface{}) *v1.Pod { + c.mungeSpec(pod) + var ret *v1.Pod + Eventually(func() error { + p, err := c.PodInterface.Create(pod) + ret = p + return err + }, opts...).ShouldNot(HaveOccurred(), "Failed to create %q pod", pod.GetName()) + return ret +} + // CreateSync creates a new pod according to the framework specifications in the given namespace, and waits for it to start. func (c *PodClient) CreateSyncInNamespace(pod *v1.Pod, namespace string) *v1.Pod { p := c.Create(pod) diff --git a/test/e2e/storage/csi_objects.go b/test/e2e/storage/csi_objects.go index 8e9fb4eb12b..df5d1d43e29 100644 --- a/test/e2e/storage/csi_objects.go +++ b/test/e2e/storage/csi_objects.go @@ -293,8 +293,6 @@ func csiHostPathPod( f *framework.Framework, sa *v1.ServiceAccount, ) *v1.Pod { - podClient := client.CoreV1().Pods(config.Namespace) - priv := true mountPropagation := v1.MountPropagationBidirectional hostPathType := v1.HostPathDirectoryOrCreate @@ -466,10 +464,15 @@ func csiHostPathPod( return nil } - ret, err := podClient.Create(pod) - if err != nil { - framework.ExpectNoError(err, "Failed to create %q pod: %v", pod.GetName(), err) - } + // Creating the pod can fail initially while the service + // account's secret isn't provisioned yet ('No API token found + // for service account "csi-service-account", retry after the + // token is automatically created and added to the service + // account', see https://github.com/kubernetes/kubernetes/issues/68776). + // We could use a DaemonSet, but then the name of the csi-pod changes + // during each test run. It's simpler to just try for a while here. + podClient := f.PodClient() + ret := podClient.CreateEventually(pod) // Wait for pod to come up framework.ExpectNoError(framework.WaitForPodRunningInNamespace(client, ret))