github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/modules/k8s/pod.go (about) 1 package k8s 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/stretchr/testify/require" 9 corev1 "k8s.io/api/core/v1" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 12 "github.com/gruntwork-io/terratest/modules/logger" 13 "github.com/gruntwork-io/terratest/modules/retry" 14 "github.com/gruntwork-io/terratest/modules/testing" 15 ) 16 17 // ListPods will look for pods in the given namespace that match the given filters and return them. This will fail the 18 // test if there is an error. 19 func ListPods(t testing.TestingT, options *KubectlOptions, filters metav1.ListOptions) []corev1.Pod { 20 pods, err := ListPodsE(t, options, filters) 21 require.NoError(t, err) 22 return pods 23 } 24 25 // ListPodsE will look for pods in the given namespace that match the given filters and return them. 26 func ListPodsE(t testing.TestingT, options *KubectlOptions, filters metav1.ListOptions) ([]corev1.Pod, error) { 27 clientset, err := GetKubernetesClientFromOptionsE(t, options) 28 if err != nil { 29 return nil, err 30 } 31 32 resp, err := clientset.CoreV1().Pods(options.Namespace).List(context.Background(), filters) 33 if err != nil { 34 return nil, err 35 } 36 return resp.Items, nil 37 } 38 39 // GetPod returns a Kubernetes pod resource in the provided namespace with the given name. This will 40 // fail the test if there is an error. 41 func GetPod(t testing.TestingT, options *KubectlOptions, podName string) *corev1.Pod { 42 pod, err := GetPodE(t, options, podName) 43 require.NoError(t, err) 44 return pod 45 } 46 47 // GetPodE returns a Kubernetes pod resource in the provided namespace with the given name. 48 func GetPodE(t testing.TestingT, options *KubectlOptions, podName string) (*corev1.Pod, error) { 49 clientset, err := GetKubernetesClientFromOptionsE(t, options) 50 if err != nil { 51 return nil, err 52 } 53 return clientset.CoreV1().Pods(options.Namespace).Get(context.Background(), podName, metav1.GetOptions{}) 54 } 55 56 // WaitUntilNumPodsCreated waits until the desired number of pods are created that match the provided filter. This will 57 // retry the check for the specified amount of times, sleeping for the provided duration between each try. This will 58 // fail the test if the retry times out. 59 func WaitUntilNumPodsCreated( 60 t testing.TestingT, 61 options *KubectlOptions, 62 filters metav1.ListOptions, 63 desiredCount int, 64 retries int, 65 sleepBetweenRetries time.Duration, 66 ) { 67 require.NoError(t, WaitUntilNumPodsCreatedE(t, options, filters, desiredCount, retries, sleepBetweenRetries)) 68 } 69 70 // WaitUntilNumPodsCreatedE waits until the desired number of pods are created that match the provided filter. This will 71 // retry the check for the specified amount of times, sleeping for the provided duration between each try. 72 func WaitUntilNumPodsCreatedE( 73 t testing.TestingT, 74 options *KubectlOptions, 75 filters metav1.ListOptions, 76 desiredCount int, 77 retries int, 78 sleepBetweenRetries time.Duration, 79 ) error { 80 statusMsg := fmt.Sprintf("Wait for num pods created to match desired count %d.", desiredCount) 81 message, err := retry.DoWithRetryE( 82 t, 83 statusMsg, 84 retries, 85 sleepBetweenRetries, 86 func() (string, error) { 87 pods, err := ListPodsE(t, options, filters) 88 if err != nil { 89 return "", err 90 } 91 if len(pods) != desiredCount { 92 return "", DesiredNumberOfPodsNotCreated{Filter: filters, DesiredCount: desiredCount} 93 } 94 return "Desired number of Pods created", nil 95 }, 96 ) 97 if err != nil { 98 logger.Logf(t, "Timedout waiting for the desired number of Pods to be created: %s", err) 99 return err 100 } 101 logger.Logf(t, message) 102 return nil 103 } 104 105 // WaitUntilPodAvailable waits until all of the containers within the pod are ready and started, retrying the check for the specified amount of times, sleeping 106 // for the provided duration between each try. This will fail the test if there is an error or if the check times out. 107 func WaitUntilPodAvailable(t testing.TestingT, options *KubectlOptions, podName string, retries int, sleepBetweenRetries time.Duration) { 108 require.NoError(t, WaitUntilPodAvailableE(t, options, podName, retries, sleepBetweenRetries)) 109 } 110 111 // WaitUntilPodAvailableE waits until all of the containers within the pod are ready and started, retrying the check for the specified amount of times, sleeping 112 // for the provided duration between each try. 113 func WaitUntilPodAvailableE(t testing.TestingT, options *KubectlOptions, podName string, retries int, sleepBetweenRetries time.Duration) error { 114 statusMsg := fmt.Sprintf("Wait for pod %s to be provisioned.", podName) 115 message, err := retry.DoWithRetryE( 116 t, 117 statusMsg, 118 retries, 119 sleepBetweenRetries, 120 func() (string, error) { 121 pod, err := GetPodE(t, options, podName) 122 if err != nil { 123 return "", err 124 } 125 if !IsPodAvailable(pod) { 126 return "", NewPodNotAvailableError(pod) 127 } 128 return "Pod is now available", nil 129 }, 130 ) 131 if err != nil { 132 logger.Logf(t, "Timedout waiting for Pod to be provisioned: %s", err) 133 return err 134 } 135 logger.Logf(t, message) 136 return nil 137 } 138 139 // IsPodAvailable returns true if the all of the containers within the pod are ready and started 140 func IsPodAvailable(pod *corev1.Pod) bool { 141 for _, containerStatus := range pod.Status.ContainerStatuses { 142 isContainerStarted := containerStatus.Started 143 isContainerReady := containerStatus.Ready 144 145 if !isContainerReady || (isContainerStarted != nil && *isContainerStarted == false) { 146 return false 147 } 148 } 149 return pod.Status.Phase == corev1.PodRunning 150 }