github.com/mponton/terratest@v0.44.0/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/mponton/terratest/modules/logger" 13 "github.com/mponton/terratest/modules/retry" 14 "github.com/mponton/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 } 151 152 // GetPodLogsE returns the logs of a Pod at the time when the function was called. Pass container name if there are more containers in the Pod or set to "" if there is only one. 153 // If the Pod is not running an Error is returned. 154 // If the provided containerName is not the name of a container in the Pod an Error is returned. 155 func GetPodLogsE(t testing.TestingT, options *KubectlOptions, pod *corev1.Pod, containerName string) (string, error) { 156 var output string 157 var err error 158 if containerName == "" { 159 output, err = RunKubectlAndGetOutputE(t, options, "logs", pod.Name) 160 } else { 161 output, err = RunKubectlAndGetOutputE(t, options, "logs", pod.Name, fmt.Sprintf("-c%s", containerName)) 162 } 163 164 if err != nil { 165 return "", err 166 } 167 return output, nil 168 } 169 170 // GetPodLogsE returns the logs of a Pod at the time when the function was called. Pass container name if there are more containers in the Pod or set to "" if there is only one. 171 func GetPodLogs(t testing.TestingT, options *KubectlOptions, pod *corev1.Pod, containerName string) string { 172 logs, err := GetPodLogsE(t, options, pod, containerName) 173 require.NoError(t, err) 174 return logs 175 }