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  }