diff --git a/modules/k8s/networkpolicy.go b/modules/k8s/networkpolicy.go new file mode 100644 index 000000000..124028e6e --- /dev/null +++ b/modules/k8s/networkpolicy.go @@ -0,0 +1,53 @@ +package k8s + +import ( + "context" + "fmt" + "time" + + "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" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// GetNetworkPolicy returns a Kubernetes networkpolicy 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 GetNetworkPolicy(t testing.TestingT, options *KubectlOptions, networkPolicyName string) *networkingv1.NetworkPolicy { + networkPolicy, err := GetNetworkPolicyE(t, options, networkPolicyName) + require.NoError(t, err) + return networkPolicy +} + +// GetNetworkPolicyE returns a Kubernetes networkpolicy resource in the provided namespace with the given name. The namespace used +// is the one provided in the KubectlOptions. +func GetNetworkPolicyE(t testing.TestingT, options *KubectlOptions, networkPolicyName string) (*networkingv1.NetworkPolicy, error) { + clientset, err := GetKubernetesClientFromOptionsE(t, options) + if err != nil { + return nil, err + } + return clientset.NetworkingV1().NetworkPolicies(options.Namespace).Get(context.Background(), networkPolicyName, metav1.GetOptions{}) +} + +// WaitUntilNetworkPolicyAvailable waits until the networkpolicy is present on the cluster in cases where it is not immediately +// available (for example, when using ClusterIssuer to request a certificate). +func WaitUntilNetworkPolicyAvailable(t testing.TestingT, options *KubectlOptions, networkPolicyName string, retries int, sleepBetweenRetries time.Duration) { + statusMsg := fmt.Sprintf("Wait for networkpolicy %s to be provisioned.", networkPolicyName) + message := retry.DoWithRetry( + t, + statusMsg, + retries, + sleepBetweenRetries, + func() (string, error) { + _, err := GetNetworkPolicyE(t, options, networkPolicyName) + if err != nil { + return "", err + } + + return "networkpolicy is now available", nil + }, + ) + logger.Logf(t, message) +} diff --git a/modules/k8s/networkpolicy_test.go b/modules/k8s/networkpolicy_test.go new file mode 100644 index 000000000..9e06933e5 --- /dev/null +++ b/modules/k8s/networkpolicy_test.go @@ -0,0 +1,72 @@ +//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 TestGetNetworkPolicyEReturnsErrorForNonExistantNetworkPolicy(t *testing.T) { + t.Parallel() + + options := NewKubectlOptions("", "", "default") + _, err := GetNetworkPolicyE(t, options, "test-network-policy") + require.Error(t, err) +} + +func TestGetNetworkPolicyEReturnsCorrectNetworkPolicyInCorrectNamespace(t *testing.T) { + t.Parallel() + + uniqueID := strings.ToLower(random.UniqueId()) + options := NewKubectlOptions("", "", uniqueID) + configData := fmt.Sprintf(EXAMPLE_NETWORK_POLICY_YAML_TEMPLATE, uniqueID, uniqueID) + defer KubectlDeleteFromString(t, options, configData) + KubectlApplyFromString(t, options, configData) + + networkPolicy := GetNetworkPolicy(t, options, "test-network-policy") + require.Equal(t, networkPolicy.Name, "test-network-policy") + require.Equal(t, networkPolicy.Namespace, uniqueID) +} + +func TestWaitUntilNetworkPolicyAvailableReturnsSuccessfully(t *testing.T) { + t.Parallel() + + uniqueID := strings.ToLower(random.UniqueId()) + options := NewKubectlOptions("", "", uniqueID) + configData := fmt.Sprintf(EXAMPLE_NETWORK_POLICY_YAML_TEMPLATE, uniqueID, uniqueID) + defer KubectlDeleteFromString(t, options, configData) + + KubectlApplyFromString(t, options, configData) + WaitUntilNetworkPolicyAvailable(t, options, "test-network-policy", 10, 1*time.Second) +} + +const EXAMPLE_NETWORK_POLICY_YAML_TEMPLATE = `--- +apiVersion: v1 +kind: Namespace +metadata: + name: %s +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: test-network-policy + namespace: %s +spec: + podSelector: {} + policyTypes: + - Ingress +`