diff --git a/modules/k8s/configmap.go b/modules/k8s/configmap.go new file mode 100644 index 000000000..86d623645 --- /dev/null +++ b/modules/k8s/configmap.go @@ -0,0 +1,54 @@ +package k8s + +import ( + "context" + "fmt" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/gruntwork-io/terratest/modules/logger" + "github.com/gruntwork-io/terratest/modules/retry" + "github.com/gruntwork-io/terratest/modules/testing" + "github.com/stretchr/testify/require" +) + +// GetConfigMap returns a Kubernetes configmap resource in the provided namespace with the given name. The namespace used +// is the one provided in the KubectlOptions. This will fail the test if there is an error. +func GetConfigMap(t testing.TestingT, options *KubectlOptions, configMapName string) *corev1.ConfigMap { + configMap, err := GetConfigMapE(t, options, configMapName) + require.NoError(t, err) + return configMap +} + +// GetConfigMapE returns a Kubernetes configmap resource in the provided namespace with the given name. The namespace used +// is the one provided in the KubectlOptions. +func GetConfigMapE(t testing.TestingT, options *KubectlOptions, configMapName string) (*corev1.ConfigMap, error) { + clientset, err := GetKubernetesClientFromOptionsE(t, options) + if err != nil { + return nil, err + } + return clientset.CoreV1().ConfigMaps(options.Namespace).Get(context.Background(), configMapName, metav1.GetOptions{}) +} + +// WaitUntilConfigMapAvailable waits until the configmap is present on the cluster in cases where it is not immediately +// available (for example, when using ClusterIssuer to request a certificate). +func WaitUntilConfigMapAvailable(t testing.TestingT, options *KubectlOptions, configMapName string, retries int, sleepBetweenRetries time.Duration) { + statusMsg := fmt.Sprintf("Wait for configmap %s to be provisioned.", configMapName) + message := retry.DoWithRetry( + t, + statusMsg, + retries, + sleepBetweenRetries, + func() (string, error) { + _, err := GetConfigMapE(t, options, configMapName) + if err != nil { + return "", err + } + + return "configmap is now available", nil + }, + ) + logger.Logf(t, message) +} diff --git a/modules/k8s/configmap_test.go b/modules/k8s/configmap_test.go new file mode 100644 index 000000000..798ba8f7f --- /dev/null +++ b/modules/k8s/configmap_test.go @@ -0,0 +1,68 @@ +//go:build kubeall || kubernetes +// +build kubeall kubernetes + +// NOTE: we have build tags to differentiate kubernetes tests from non-kubernetes tests. This is done because minikube +// is heavy and can interfere with docker related tests in terratest. Specifically, many of the tests start to fail with +// `connection refused` errors from `minikube`. To avoid overloading the system, we run the kubernetes tests and helm +// tests separately from the others. This may not be necessary if you have a sufficiently powerful machine. We +// recommend at least 4 cores and 16GB of RAM if you want to run all the tests together. + +package k8s + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/gruntwork-io/terratest/modules/random" +) + +func TestGetConfigMapEReturnsErrorForNonExistantConfigMap(t *testing.T) { + t.Parallel() + + options := NewKubectlOptions("", "", "default") + _, err := GetConfigMapE(t, options, "test-config-map") + require.Error(t, err) +} + +func TestGetConfigMapEReturnsCorrectConfigMapInCorrectNamespace(t *testing.T) { + t.Parallel() + + uniqueID := strings.ToLower(random.UniqueId()) + options := NewKubectlOptions("", "", uniqueID) + configData := fmt.Sprintf(EXAMPLE_CONFIGMAP_YAML_TEMPLATE, uniqueID, uniqueID) + defer KubectlDeleteFromString(t, options, configData) + KubectlApplyFromString(t, options, configData) + + configMap := GetConfigMap(t, options, "test-config-map") + require.Equal(t, configMap.Name, "test-config-map") + require.Equal(t, configMap.Namespace, uniqueID) +} + +func TestWaitUntilConfigMapAvailableReturnsSuccessfully(t *testing.T) { + t.Parallel() + + uniqueID := strings.ToLower(random.UniqueId()) + options := NewKubectlOptions("", "", uniqueID) + configData := fmt.Sprintf(EXAMPLE_CONFIGMAP_YAML_TEMPLATE, uniqueID, uniqueID) + defer KubectlDeleteFromString(t, options, configData) + + KubectlApplyFromString(t, options, configData) + WaitUntilConfigMapAvailable(t, options, "test-config-map", 10, 1*time.Second) +} + +const EXAMPLE_CONFIGMAP_YAML_TEMPLATE = `--- +apiVersion: v1 +kind: Namespace +metadata: + name: %s +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: test-config-map + namespace: %s +`