wait.go 23 KB

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