wait.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package pod
  14. import (
  15. "bytes"
  16. "context"
  17. "errors"
  18. "fmt"
  19. "sync"
  20. "text/tabwriter"
  21. "time"
  22. "github.com/onsi/ginkgo"
  23. v1 "k8s.io/api/core/v1"
  24. apierrors "k8s.io/apimachinery/pkg/api/errors"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. "k8s.io/apimachinery/pkg/labels"
  27. "k8s.io/apimachinery/pkg/runtime/schema"
  28. "k8s.io/apimachinery/pkg/util/wait"
  29. clientset "k8s.io/client-go/kubernetes"
  30. podutil "k8s.io/kubernetes/pkg/api/v1/pod"
  31. "k8s.io/kubernetes/pkg/kubelet/util/format"
  32. e2elog "k8s.io/kubernetes/test/e2e/framework/log"
  33. e2eresource "k8s.io/kubernetes/test/e2e/framework/resource"
  34. testutils "k8s.io/kubernetes/test/utils"
  35. )
  36. const (
  37. // defaultPodDeletionTimeout is the default timeout for deleting pod.
  38. defaultPodDeletionTimeout = 3 * time.Minute
  39. // podListTimeout is how long to wait for the pod to be listable.
  40. podListTimeout = time.Minute
  41. podRespondingTimeout = 15 * time.Minute
  42. // How long pods have to become scheduled onto nodes
  43. podScheduledBeforeTimeout = podListTimeout + (20 * time.Second)
  44. // podStartTimeout is how long to wait for the pod to be started.
  45. podStartTimeout = 5 * time.Minute
  46. // poll is how often to poll pods, nodes and claims.
  47. poll = 2 * time.Second
  48. // singleCallTimeout is how long to try single API calls (like 'get' or 'list'). Used to prevent
  49. // transient failures from failing tests.
  50. // TODO: client should not apply this timeout to Watch calls. Increased from 30s until that is fixed.
  51. singleCallTimeout = 5 * time.Minute
  52. // Some pods can take much longer to get ready due to volume attach/detach latency.
  53. slowPodStartTimeout = 15 * time.Minute
  54. )
  55. type podCondition func(pod *v1.Pod) (bool, error)
  56. // errorBadPodsStates create error message of basic info of bad pods for debugging.
  57. func errorBadPodsStates(badPods []v1.Pod, desiredPods int, ns, desiredState string, timeout time.Duration) string {
  58. errStr := fmt.Sprintf("%d / %d pods in namespace %q are NOT in %s state in %v\n", len(badPods), desiredPods, ns, desiredState, timeout)
  59. // Print bad pods info only if there are fewer than 10 bad pods
  60. if len(badPods) > 10 {
  61. return errStr + "There are too many bad pods. Please check log for details."
  62. }
  63. buf := bytes.NewBuffer(nil)
  64. w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
  65. fmt.Fprintln(w, "POD\tNODE\tPHASE\tGRACE\tCONDITIONS")
  66. for _, badPod := range badPods {
  67. grace := ""
  68. if badPod.DeletionGracePeriodSeconds != nil {
  69. grace = fmt.Sprintf("%ds", *badPod.DeletionGracePeriodSeconds)
  70. }
  71. podInfo := fmt.Sprintf("%s\t%s\t%s\t%s\t%+v",
  72. badPod.ObjectMeta.Name, badPod.Spec.NodeName, badPod.Status.Phase, grace, badPod.Status.Conditions)
  73. fmt.Fprintln(w, podInfo)
  74. }
  75. w.Flush()
  76. return errStr + buf.String()
  77. }
  78. // WaitForPodsRunningReady waits up to timeout to ensure that all pods in
  79. // namespace ns are either running and ready, or failed but controlled by a
  80. // controller. Also, it ensures that at least minPods are running and
  81. // ready. It has separate behavior from other 'wait for' pods functions in
  82. // that it requests the list of pods on every iteration. This is useful, for
  83. // example, in cluster startup, because the number of pods increases while
  84. // waiting. All pods that are in SUCCESS state are not counted.
  85. //
  86. // If ignoreLabels is not empty, pods matching this selector are ignored.
  87. func WaitForPodsRunningReady(c clientset.Interface, ns string, minPods, allowedNotReadyPods int32, timeout time.Duration, ignoreLabels map[string]string) error {
  88. ignoreSelector := labels.SelectorFromSet(map[string]string{})
  89. start := time.Now()
  90. e2elog.Logf("Waiting up to %v for all pods (need at least %d) in namespace '%s' to be running and ready",
  91. timeout, minPods, ns)
  92. wg := sync.WaitGroup{}
  93. wg.Add(1)
  94. var ignoreNotReady bool
  95. badPods := []v1.Pod{}
  96. desiredPods := 0
  97. notReady := int32(0)
  98. if wait.PollImmediate(poll, timeout, func() (bool, error) {
  99. // We get the new list of pods, replication controllers, and
  100. // replica sets in every iteration because more pods come
  101. // online during startup and we want to ensure they are also
  102. // checked.
  103. replicas, replicaOk := int32(0), int32(0)
  104. rcList, err := c.CoreV1().ReplicationControllers(ns).List(context.TODO(), metav1.ListOptions{})
  105. if err != nil {
  106. e2elog.Logf("Error getting replication controllers in namespace '%s': %v", ns, err)
  107. if testutils.IsRetryableAPIError(err) {
  108. return false, nil
  109. }
  110. return false, err
  111. }
  112. for _, rc := range rcList.Items {
  113. replicas += *rc.Spec.Replicas
  114. replicaOk += rc.Status.ReadyReplicas
  115. }
  116. rsList, err := c.AppsV1().ReplicaSets(ns).List(context.TODO(), metav1.ListOptions{})
  117. if err != nil {
  118. e2elog.Logf("Error getting replication sets in namespace %q: %v", ns, err)
  119. if testutils.IsRetryableAPIError(err) {
  120. return false, nil
  121. }
  122. return false, err
  123. }
  124. for _, rs := range rsList.Items {
  125. replicas += *rs.Spec.Replicas
  126. replicaOk += rs.Status.ReadyReplicas
  127. }
  128. podList, err := c.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{})
  129. if err != nil {
  130. e2elog.Logf("Error getting pods in namespace '%s': %v", ns, err)
  131. if testutils.IsRetryableAPIError(err) {
  132. return false, nil
  133. }
  134. return false, err
  135. }
  136. nOk := int32(0)
  137. notReady = int32(0)
  138. badPods = []v1.Pod{}
  139. desiredPods = len(podList.Items)
  140. for _, pod := range podList.Items {
  141. if len(ignoreLabels) != 0 && ignoreSelector.Matches(labels.Set(pod.Labels)) {
  142. continue
  143. }
  144. res, err := testutils.PodRunningReady(&pod)
  145. switch {
  146. case res && err == nil:
  147. nOk++
  148. case pod.Status.Phase == v1.PodSucceeded:
  149. e2elog.Logf("The status of Pod %s is Succeeded, skipping waiting", pod.ObjectMeta.Name)
  150. // it doesn't make sense to wait for this pod
  151. continue
  152. case pod.Status.Phase != v1.PodFailed:
  153. e2elog.Logf("The status of Pod %s is %s (Ready = false), waiting for it to be either Running (with Ready = true) or Failed", pod.ObjectMeta.Name, pod.Status.Phase)
  154. notReady++
  155. badPods = append(badPods, pod)
  156. default:
  157. if metav1.GetControllerOf(&pod) == nil {
  158. e2elog.Logf("Pod %s is Failed, but it's not controlled by a controller", pod.ObjectMeta.Name)
  159. badPods = append(badPods, pod)
  160. }
  161. //ignore failed pods that are controlled by some controller
  162. }
  163. }
  164. e2elog.Logf("%d / %d pods in namespace '%s' are running and ready (%d seconds elapsed)",
  165. nOk, len(podList.Items), ns, int(time.Since(start).Seconds()))
  166. e2elog.Logf("expected %d pod replicas in namespace '%s', %d are Running and Ready.", replicas, ns, replicaOk)
  167. if replicaOk == replicas && nOk >= minPods && len(badPods) == 0 {
  168. return true, nil
  169. }
  170. ignoreNotReady = (notReady <= allowedNotReadyPods)
  171. LogPodStates(badPods)
  172. return false, nil
  173. }) != nil {
  174. if !ignoreNotReady {
  175. return errors.New(errorBadPodsStates(badPods, desiredPods, ns, "RUNNING and READY", timeout))
  176. }
  177. e2elog.Logf("Number of not-ready pods (%d) is below the allowed threshold (%d).", notReady, allowedNotReadyPods)
  178. }
  179. return nil
  180. }
  181. // WaitForPodCondition waits a pods to be matched to the given condition.
  182. func WaitForPodCondition(c clientset.Interface, ns, podName, desc string, timeout time.Duration, condition podCondition) error {
  183. e2elog.Logf("Waiting up to %v for pod %q in namespace %q to be %q", timeout, podName, ns, desc)
  184. for start := time.Now(); time.Since(start) < timeout; time.Sleep(poll) {
  185. pod, err := c.CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
  186. if err != nil {
  187. if apierrors.IsNotFound(err) {
  188. e2elog.Logf("Pod %q in namespace %q not found. Error: %v", podName, ns, err)
  189. return err
  190. }
  191. e2elog.Logf("Get pod %q in namespace %q failed, ignoring for %v. Error: %v", podName, ns, poll, err)
  192. continue
  193. }
  194. // log now so that current pod info is reported before calling `condition()`
  195. e2elog.Logf("Pod %q: Phase=%q, Reason=%q, readiness=%t. Elapsed: %v",
  196. podName, pod.Status.Phase, pod.Status.Reason, podutil.IsPodReady(pod), time.Since(start))
  197. if done, err := condition(pod); done {
  198. if err == nil {
  199. e2elog.Logf("Pod %q satisfied condition %q", podName, desc)
  200. }
  201. return err
  202. }
  203. }
  204. return fmt.Errorf("Gave up after waiting %v for pod %q to be %q", timeout, podName, desc)
  205. }
  206. // WaitForPodTerminatedInNamespace returns an error if it takes too long for the pod to terminate,
  207. // if the pod Get api returns an error (IsNotFound or other), or if the pod failed (and thus did not
  208. // terminate) with an unexpected reason. Typically called to test that the passed-in pod is fully
  209. // terminated (reason==""), but may be called to detect if a pod did *not* terminate according to
  210. // the supplied reason.
  211. func WaitForPodTerminatedInNamespace(c clientset.Interface, podName, reason, namespace string) error {
  212. return WaitForPodCondition(c, namespace, podName, "terminated due to deadline exceeded", podStartTimeout, func(pod *v1.Pod) (bool, error) {
  213. // Only consider Failed pods. Successful pods will be deleted and detected in
  214. // waitForPodCondition's Get call returning `IsNotFound`
  215. if pod.Status.Phase == v1.PodFailed {
  216. if pod.Status.Reason == reason { // short-circuit waitForPodCondition's loop
  217. return true, nil
  218. }
  219. return true, fmt.Errorf("Expected pod %q in namespace %q to be terminated with reason %q, got reason: %q", podName, namespace, reason, pod.Status.Reason)
  220. }
  221. return false, nil
  222. })
  223. }
  224. // waitForPodSuccessInNamespaceTimeout returns nil if the pod reached state success, or an error if it reached failure or ran too long.
  225. func waitForPodSuccessInNamespaceTimeout(c clientset.Interface, podName, namespace string, timeout time.Duration) error {
  226. return WaitForPodCondition(c, namespace, podName, fmt.Sprintf("%s or %s", v1.PodSucceeded, v1.PodFailed), timeout, func(pod *v1.Pod) (bool, error) {
  227. if pod.Spec.RestartPolicy == v1.RestartPolicyAlways {
  228. return true, fmt.Errorf("pod %q will never terminate with a succeeded state since its restart policy is Always", podName)
  229. }
  230. switch pod.Status.Phase {
  231. case v1.PodSucceeded:
  232. ginkgo.By("Saw pod success")
  233. return true, nil
  234. case v1.PodFailed:
  235. return true, fmt.Errorf("pod %q failed with status: %+v", podName, pod.Status)
  236. default:
  237. return false, nil
  238. }
  239. })
  240. }
  241. // WaitForPodNameUnschedulableInNamespace returns an error if it takes too long for the pod to become Pending
  242. // and have condition Status equal to Unschedulable,
  243. // if the pod Get api returns an error (IsNotFound or other), or if the pod failed with an unexpected reason.
  244. // Typically called to test that the passed-in pod is Pending and Unschedulable.
  245. func WaitForPodNameUnschedulableInNamespace(c clientset.Interface, podName, namespace string) error {
  246. return WaitForPodCondition(c, namespace, podName, v1.PodReasonUnschedulable, podStartTimeout, func(pod *v1.Pod) (bool, error) {
  247. // Only consider Failed pods. Successful pods will be deleted and detected in
  248. // waitForPodCondition's Get call returning `IsNotFound`
  249. if pod.Status.Phase == v1.PodPending {
  250. for _, cond := range pod.Status.Conditions {
  251. if cond.Type == v1.PodScheduled && cond.Status == v1.ConditionFalse && cond.Reason == v1.PodReasonUnschedulable {
  252. return true, nil
  253. }
  254. }
  255. }
  256. if pod.Status.Phase == v1.PodRunning || pod.Status.Phase == v1.PodSucceeded || pod.Status.Phase == v1.PodFailed {
  257. return true, fmt.Errorf("Expected pod %q in namespace %q to be in phase Pending, but got phase: %v", podName, namespace, pod.Status.Phase)
  258. }
  259. return false, nil
  260. })
  261. }
  262. // WaitForMatchPodsCondition finds match pods based on the input ListOptions.
  263. // waits and checks if all match pods are in the given podCondition
  264. func WaitForMatchPodsCondition(c clientset.Interface, opts metav1.ListOptions, desc string, timeout time.Duration, condition podCondition) error {
  265. e2elog.Logf("Waiting up to %v for matching pods' status to be %s", timeout, desc)
  266. for start := time.Now(); time.Since(start) < timeout; time.Sleep(poll) {
  267. pods, err := c.CoreV1().Pods(metav1.NamespaceAll).List(context.TODO(), opts)
  268. if err != nil {
  269. return err
  270. }
  271. conditionNotMatch := []string{}
  272. for _, pod := range pods.Items {
  273. done, err := condition(&pod)
  274. if done && err != nil {
  275. return fmt.Errorf("Unexpected error: %v", err)
  276. }
  277. if !done {
  278. conditionNotMatch = append(conditionNotMatch, format.Pod(&pod))
  279. }
  280. }
  281. if len(conditionNotMatch) <= 0 {
  282. return err
  283. }
  284. e2elog.Logf("%d pods are not %s: %v", len(conditionNotMatch), desc, conditionNotMatch)
  285. }
  286. return fmt.Errorf("gave up waiting for matching pods to be '%s' after %v", desc, timeout)
  287. }
  288. // WaitForPodNameRunningInNamespace waits default amount of time (PodStartTimeout) for the specified pod to become running.
  289. // Returns an error if timeout occurs first, or pod goes in to failed state.
  290. func WaitForPodNameRunningInNamespace(c clientset.Interface, podName, namespace string) error {
  291. return WaitTimeoutForPodRunningInNamespace(c, podName, namespace, podStartTimeout)
  292. }
  293. // WaitForPodRunningInNamespaceSlow waits an extended amount of time (slowPodStartTimeout) for the specified pod to become running.
  294. // The resourceVersion is used when Watching object changes, it tells since when we care
  295. // about changes to the pod. Returns an error if timeout occurs first, or pod goes in to failed state.
  296. func WaitForPodRunningInNamespaceSlow(c clientset.Interface, podName, namespace string) error {
  297. return WaitTimeoutForPodRunningInNamespace(c, podName, namespace, slowPodStartTimeout)
  298. }
  299. // WaitTimeoutForPodRunningInNamespace waits the given timeout duration for the specified pod to become running.
  300. func WaitTimeoutForPodRunningInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error {
  301. return wait.PollImmediate(poll, timeout, podRunning(c, podName, namespace))
  302. }
  303. // WaitForPodRunningInNamespace waits default amount of time (podStartTimeout) for the specified pod to become running.
  304. // Returns an error if timeout occurs first, or pod goes in to failed state.
  305. func WaitForPodRunningInNamespace(c clientset.Interface, pod *v1.Pod) error {
  306. if pod.Status.Phase == v1.PodRunning {
  307. return nil
  308. }
  309. return WaitTimeoutForPodRunningInNamespace(c, pod.Name, pod.Namespace, podStartTimeout)
  310. }
  311. // WaitTimeoutForPodNoLongerRunningInNamespace waits the given timeout duration for the specified pod to stop.
  312. func WaitTimeoutForPodNoLongerRunningInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error {
  313. return wait.PollImmediate(poll, timeout, podCompleted(c, podName, namespace))
  314. }
  315. // WaitForPodNoLongerRunningInNamespace waits default amount of time (defaultPodDeletionTimeout) for the specified pod to stop running.
  316. // Returns an error if timeout occurs first.
  317. func WaitForPodNoLongerRunningInNamespace(c clientset.Interface, podName, namespace string) error {
  318. return WaitTimeoutForPodNoLongerRunningInNamespace(c, podName, namespace, defaultPodDeletionTimeout)
  319. }
  320. // WaitTimeoutForPodReadyInNamespace waits the given timeout diration for the
  321. // specified pod to be ready and running.
  322. func WaitTimeoutForPodReadyInNamespace(c clientset.Interface, podName, namespace string, timeout time.Duration) error {
  323. return wait.PollImmediate(poll, timeout, podRunningAndReady(c, podName, namespace))
  324. }
  325. // WaitForPodNotPending returns an error if it took too long for the pod to go out of pending state.
  326. // The resourceVersion is used when Watching object changes, it tells since when we care
  327. // about changes to the pod.
  328. func WaitForPodNotPending(c clientset.Interface, ns, podName string) error {
  329. return wait.PollImmediate(poll, podStartTimeout, podNotPending(c, podName, ns))
  330. }
  331. // WaitForPodSuccessInNamespace returns nil if the pod reached state success, or an error if it reached failure or until podStartupTimeout.
  332. func WaitForPodSuccessInNamespace(c clientset.Interface, podName string, namespace string) error {
  333. return waitForPodSuccessInNamespaceTimeout(c, podName, namespace, podStartTimeout)
  334. }
  335. // WaitForPodSuccessInNamespaceSlow returns nil if the pod reached state success, or an error if it reached failure or until slowPodStartupTimeout.
  336. func WaitForPodSuccessInNamespaceSlow(c clientset.Interface, podName string, namespace string) error {
  337. return waitForPodSuccessInNamespaceTimeout(c, podName, namespace, slowPodStartTimeout)
  338. }
  339. // WaitForPodNotFoundInNamespace returns an error if it takes too long for the pod to fully terminate.
  340. // Unlike `waitForPodTerminatedInNamespace`, the pod's Phase and Reason are ignored. If the pod Get
  341. // api returns IsNotFound then the wait stops and nil is returned. If the Get api returns an error other
  342. // than "not found" then that error is returned and the wait stops.
  343. func WaitForPodNotFoundInNamespace(c clientset.Interface, podName, ns string, timeout time.Duration) error {
  344. return wait.PollImmediate(poll, timeout, func() (bool, error) {
  345. _, err := c.CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
  346. if apierrors.IsNotFound(err) {
  347. return true, nil // done
  348. }
  349. if err != nil {
  350. return true, err // stop wait with error
  351. }
  352. return false, nil
  353. })
  354. }
  355. // WaitForPodToDisappear waits the given timeout duration for the specified pod to disappear.
  356. func WaitForPodToDisappear(c clientset.Interface, ns, podName string, label labels.Selector, interval, timeout time.Duration) error {
  357. return wait.PollImmediate(interval, timeout, func() (bool, error) {
  358. e2elog.Logf("Waiting for pod %s to disappear", podName)
  359. options := metav1.ListOptions{LabelSelector: label.String()}
  360. pods, err := c.CoreV1().Pods(ns).List(context.TODO(), options)
  361. if err != nil {
  362. if testutils.IsRetryableAPIError(err) {
  363. return false, nil
  364. }
  365. return false, err
  366. }
  367. found := false
  368. for _, pod := range pods.Items {
  369. if pod.Name == podName {
  370. e2elog.Logf("Pod %s still exists", podName)
  371. found = true
  372. break
  373. }
  374. }
  375. if !found {
  376. e2elog.Logf("Pod %s no longer exists", podName)
  377. return true, nil
  378. }
  379. return false, nil
  380. })
  381. }
  382. // PodsResponding waits for the pods to response.
  383. func PodsResponding(c clientset.Interface, ns, name string, wantName bool, pods *v1.PodList) error {
  384. ginkgo.By("trying to dial each unique pod")
  385. label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
  386. return wait.PollImmediate(poll, podRespondingTimeout, NewProxyResponseChecker(c, ns, label, name, wantName, pods).CheckAllResponses)
  387. }
  388. // WaitForControlledPodsRunning waits up to 10 minutes for pods to become Running.
  389. func WaitForControlledPodsRunning(c clientset.Interface, ns, name string, kind schema.GroupKind) error {
  390. rtObject, err := e2eresource.GetRuntimeObjectForKind(c, kind, ns, name)
  391. if err != nil {
  392. return err
  393. }
  394. selector, err := e2eresource.GetSelectorFromRuntimeObject(rtObject)
  395. if err != nil {
  396. return err
  397. }
  398. replicas, err := e2eresource.GetReplicasFromRuntimeObject(rtObject)
  399. if err != nil {
  400. return err
  401. }
  402. err = testutils.WaitForEnoughPodsWithLabelRunning(c, ns, selector, int(replicas))
  403. if err != nil {
  404. return fmt.Errorf("Error while waiting for replication controller %s pods to be running: %v", name, err)
  405. }
  406. return nil
  407. }
  408. // WaitForControlledPods waits up to podListTimeout for getting pods of the specified controller name and return them.
  409. func WaitForControlledPods(c clientset.Interface, ns, name string, kind schema.GroupKind) (pods *v1.PodList, err error) {
  410. rtObject, err := e2eresource.GetRuntimeObjectForKind(c, kind, ns, name)
  411. if err != nil {
  412. return nil, err
  413. }
  414. selector, err := e2eresource.GetSelectorFromRuntimeObject(rtObject)
  415. if err != nil {
  416. return nil, err
  417. }
  418. return WaitForPodsWithLabel(c, ns, selector)
  419. }
  420. // WaitForPodsWithLabelScheduled waits for all matching pods to become scheduled and at least one
  421. // matching pod exists. Return the list of matching pods.
  422. func WaitForPodsWithLabelScheduled(c clientset.Interface, ns string, label labels.Selector) (pods *v1.PodList, err error) {
  423. err = wait.PollImmediate(poll, podScheduledBeforeTimeout,
  424. func() (bool, error) {
  425. pods, err = WaitForPodsWithLabel(c, ns, label)
  426. if err != nil {
  427. return false, err
  428. }
  429. for _, pod := range pods.Items {
  430. if pod.Spec.NodeName == "" {
  431. return false, nil
  432. }
  433. }
  434. return true, nil
  435. })
  436. return pods, err
  437. }
  438. // WaitForPodsWithLabel waits up to podListTimeout for getting pods with certain label
  439. func WaitForPodsWithLabel(c clientset.Interface, ns string, label labels.Selector) (pods *v1.PodList, err error) {
  440. for t := time.Now(); time.Since(t) < podListTimeout; time.Sleep(poll) {
  441. options := metav1.ListOptions{LabelSelector: label.String()}
  442. pods, err = c.CoreV1().Pods(ns).List(context.TODO(), options)
  443. if err != nil {
  444. if testutils.IsRetryableAPIError(err) {
  445. continue
  446. }
  447. return
  448. }
  449. if len(pods.Items) > 0 {
  450. break
  451. }
  452. }
  453. if pods == nil || len(pods.Items) == 0 {
  454. err = fmt.Errorf("Timeout while waiting for pods with label %v", label)
  455. }
  456. return
  457. }
  458. // WaitForPodsWithLabelRunningReady waits for exact amount of matching pods to become running and ready.
  459. // Return the list of matching pods.
  460. func WaitForPodsWithLabelRunningReady(c clientset.Interface, ns string, label labels.Selector, num int, timeout time.Duration) (pods *v1.PodList, err error) {
  461. var current int
  462. err = wait.Poll(poll, timeout,
  463. func() (bool, error) {
  464. pods, err = WaitForPodsWithLabel(c, ns, label)
  465. if err != nil {
  466. e2elog.Logf("Failed to list pods: %v", err)
  467. if testutils.IsRetryableAPIError(err) {
  468. return false, nil
  469. }
  470. return false, err
  471. }
  472. current = 0
  473. for _, pod := range pods.Items {
  474. if flag, err := testutils.PodRunningReady(&pod); err == nil && flag == true {
  475. current++
  476. }
  477. }
  478. if current != num {
  479. e2elog.Logf("Got %v pods running and ready, expect: %v", current, num)
  480. return false, nil
  481. }
  482. return true, nil
  483. })
  484. return pods, err
  485. }
  486. // WaitForPodsReady waits for the pods to become ready.
  487. func WaitForPodsReady(c clientset.Interface, ns, name string, minReadySeconds int) error {
  488. label := labels.SelectorFromSet(labels.Set(map[string]string{"name": name}))
  489. options := metav1.ListOptions{LabelSelector: label.String()}
  490. return wait.Poll(poll, 5*time.Minute, func() (bool, error) {
  491. pods, err := c.CoreV1().Pods(ns).List(context.TODO(), options)
  492. if err != nil {
  493. return false, nil
  494. }
  495. for _, pod := range pods.Items {
  496. if !podutil.IsPodAvailable(&pod, int32(minReadySeconds), metav1.Now()) {
  497. return false, nil
  498. }
  499. }
  500. return true, nil
  501. })
  502. }
  503. // WaitForNRestartablePods tries to list restarting pods using ps until it finds expect of them,
  504. // returning their names if it can do so before timeout.
  505. func WaitForNRestartablePods(ps *testutils.PodStore, expect int, timeout time.Duration) ([]string, error) {
  506. var pods []*v1.Pod
  507. var errLast error
  508. found := wait.Poll(poll, timeout, func() (bool, error) {
  509. allPods := ps.List()
  510. pods = FilterNonRestartablePods(allPods)
  511. if len(pods) != expect {
  512. errLast = fmt.Errorf("expected to find %d pods but found only %d", expect, len(pods))
  513. e2elog.Logf("Error getting pods: %v", errLast)
  514. return false, nil
  515. }
  516. return true, nil
  517. }) == nil
  518. podNames := make([]string, len(pods))
  519. for i, p := range pods {
  520. podNames[i] = p.ObjectMeta.Name
  521. }
  522. if !found {
  523. return podNames, fmt.Errorf("couldn't find %d pods within %v; last error: %v",
  524. expect, timeout, errLast)
  525. }
  526. return podNames, nil
  527. }