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  }