cmd/k8s-operator: use dynamic resource names in e2e ingress tests (#19536)

Replace hardcoded resource names with dynamically generated names in
k8s-operator-e2e ingress tests to avoid collisions with stale resources.

Updates #tailscale/corp#40612

Signed-off-by: Becky Pauley <becky@tailscale.com>
This commit is contained in:
BeckyPauley
2026-04-27 13:40:46 +01:00
committed by GitHub
parent 3a05c450ce
commit 7477a6ee47
2 changed files with 54 additions and 50 deletions
+52 -48
View File
@@ -33,12 +33,12 @@ func TestL3Ingress(t *testing.T) {
} }
// Apply nginx // Apply nginx
createAndCleanup(t, kubeClient, nginxDeployment(ns, "nginx")) nginx := nginxDeployment(ns)
createAndCleanup(t, kubeClient, nginx)
// Apply service to expose it as ingress // Apply service to expose it as ingress
name := generateName("test-ingress")
svc := &corev1.Service{ svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: generateName("test-ingress"),
Namespace: ns, Namespace: ns,
Annotations: map[string]string{ Annotations: map[string]string{
"tailscale.com/expose": "true", "tailscale.com/expose": "true",
@@ -46,7 +46,7 @@ func TestL3Ingress(t *testing.T) {
}, },
Spec: corev1.ServiceSpec{ Spec: corev1.ServiceSpec{
Selector: map[string]string{ Selector: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": nginx.Name,
}, },
Ports: []corev1.ServicePort{ Ports: []corev1.ServicePort{
{ {
@@ -60,7 +60,7 @@ func TestL3Ingress(t *testing.T) {
createAndCleanup(t, kubeClient, svc) createAndCleanup(t, kubeClient, svc)
if err := tstest.WaitFor(time.Minute, func() error { if err := tstest.WaitFor(time.Minute, func() error {
maybeReadySvc := &corev1.Service{ObjectMeta: objectMeta(ns, name)} maybeReadySvc := &corev1.Service{ObjectMeta: objectMeta(ns, svc.Name)}
if err := get(t.Context(), kubeClient, maybeReadySvc); err != nil { if err := get(t.Context(), kubeClient, maybeReadySvc); err != nil {
return err return err
} }
@@ -81,7 +81,7 @@ func TestL3Ingress(t *testing.T) {
if err := kubeClient.List(t.Context(), &secrets, if err := kubeClient.List(t.Context(), &secrets,
client.InNamespace("tailscale"), client.InNamespace("tailscale"),
client.MatchingLabels{ client.MatchingLabels{
"tailscale.com/parent-resource": name, "tailscale.com/parent-resource": svc.Name,
"tailscale.com/parent-resource-ns": ns, "tailscale.com/parent-resource-ns": ns,
}, },
); err != nil { ); err != nil {
@@ -111,33 +111,34 @@ func TestL3HAIngress(t *testing.T) {
} }
// Apply nginx. // Apply nginx.
createAndCleanup(t, kubeClient, nginxDeployment(ns, "nginx")) nginx := nginxDeployment(ns)
createAndCleanup(t, kubeClient, nginx)
// Create an ingress ProxyGroup. // Create an ingress ProxyGroup.
createAndCleanup(t, kubeClient, &tsapi.ProxyGroup{ pg := &tsapi.ProxyGroup{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "ingress", Name: generateName("ingress"),
}, },
Spec: tsapi.ProxyGroupSpec{ Spec: tsapi.ProxyGroupSpec{
Type: tsapi.ProxyGroupTypeIngress, Type: tsapi.ProxyGroupTypeIngress,
}, },
}) }
createAndCleanup(t, kubeClient, pg)
// Apply a Service to expose nginx via the ProxyGroup. // Apply a Service to expose nginx via the ProxyGroup.
name := generateName("test-ingress")
svc := &corev1.Service{ svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: generateName("test-ingress"),
Namespace: ns, Namespace: ns,
Annotations: map[string]string{ Annotations: map[string]string{
"tailscale.com/proxy-group": "ingress", "tailscale.com/proxy-group": pg.Name,
}, },
}, },
Spec: corev1.ServiceSpec{ Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer, Type: corev1.ServiceTypeLoadBalancer,
LoadBalancerClass: new("tailscale"), LoadBalancerClass: new("tailscale"),
Selector: map[string]string{ Selector: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": nginx.Name,
}, },
Ports: []corev1.ServicePort{ Ports: []corev1.ServicePort{
{ {
@@ -152,12 +153,12 @@ func TestL3HAIngress(t *testing.T) {
var svcIPv4 string var svcIPv4 string
forceReconcile := triggerReconcile(t, forceReconcile := triggerReconcile(t,
client.ObjectKey{Namespace: ns, Name: name}, client.ObjectKey{Namespace: ns, Name: svc.Name},
&corev1.Service{}, 30*time.Second) &corev1.Service{}, 30*time.Second)
// Wait for Service to be ready // Wait for Service to be ready
if err := tstest.WaitFor(5*time.Minute, func() error { if err := tstest.WaitFor(5*time.Minute, func() error {
maybeReadySvc := &corev1.Service{ObjectMeta: objectMeta(ns, name)} maybeReadySvc := &corev1.Service{ObjectMeta: objectMeta(ns, svc.Name)}
forceReconcile() forceReconcile()
if err := get(t.Context(), kubeClient, maybeReadySvc); err != nil { if err := get(t.Context(), kubeClient, maybeReadySvc); err != nil {
return err return err
@@ -188,15 +189,16 @@ func TestL7Ingress(t *testing.T) {
} }
// Apply nginx Deployment and Service. // Apply nginx Deployment and Service.
createAndCleanup(t, kubeClient, nginxDeployment(ns, "nginx")) nginx := nginxDeployment(ns)
createAndCleanup(t, kubeClient, nginx)
createAndCleanup(t, kubeClient, &corev1.Service{ createAndCleanup(t, kubeClient, &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "nginx", Name: nginx.Name,
Namespace: ns, Namespace: ns,
}, },
Spec: corev1.ServiceSpec{ Spec: corev1.ServiceSpec{
Selector: map[string]string{ Selector: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": nginx.Name,
}, },
Ports: []corev1.ServicePort{ Ports: []corev1.ServicePort{
{ {
@@ -208,13 +210,12 @@ func TestL7Ingress(t *testing.T) {
}) })
// Apply Ingress to expose nginx. // Apply Ingress to expose nginx.
name := generateName("test-ingress") ingress := l7Ingress(ns, nginx.Name, map[string]string{})
ingress := l7Ingress(ns, name, map[string]string{})
createAndCleanup(t, kubeClient, ingress) createAndCleanup(t, kubeClient, ingress)
t.Log("Waiting for the Ingress to be ready...") t.Log("Waiting for the Ingress to be ready...")
hostname, err := waitForIngressHostname(t, ns, name) hostname, err := waitForIngressHostname(t, ns, ingress.Name)
if err != nil { if err != nil {
t.Fatalf("error waiting for Ingress hostname: %v", err) t.Fatalf("error waiting for Ingress hostname: %v", err)
} }
@@ -230,15 +231,16 @@ func TestL7HAIngress(t *testing.T) {
} }
// Apply nginx Deployment and Service. // Apply nginx Deployment and Service.
createAndCleanup(t, kubeClient, nginxDeployment(ns, "nginx")) nginx := nginxDeployment(ns)
createAndCleanup(t, kubeClient, nginx)
createAndCleanup(t, kubeClient, &corev1.Service{ createAndCleanup(t, kubeClient, &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "nginx", Name: nginx.Name,
Namespace: ns, Namespace: ns,
}, },
Spec: corev1.ServiceSpec{ Spec: corev1.ServiceSpec{
Selector: map[string]string{ Selector: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": nginx.Name,
}, },
Ports: []corev1.ServicePort{ Ports: []corev1.ServicePort{
{ {
@@ -250,23 +252,23 @@ func TestL7HAIngress(t *testing.T) {
}) })
// Create ProxyGroup that the Ingress will reference. // Create ProxyGroup that the Ingress will reference.
createAndCleanup(t, kubeClient, &tsapi.ProxyGroup{ pg := &tsapi.ProxyGroup{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "ingress", Name: generateName("ingress"),
}, },
Spec: tsapi.ProxyGroupSpec{ Spec: tsapi.ProxyGroupSpec{
Type: tsapi.ProxyGroupTypeIngress, Type: tsapi.ProxyGroupTypeIngress,
}, },
}) }
createAndCleanup(t, kubeClient, pg)
// Apply Ingress to expose nginx. // Apply Ingress to expose nginx.
name := generateName("test-ingress") ingress := l7Ingress(ns, nginx.Name, map[string]string{"tailscale.com/proxy-group": pg.Name})
ingress := l7Ingress(ns, name, map[string]string{"tailscale.com/proxy-group": "ingress"})
createAndCleanup(t, kubeClient, ingress) createAndCleanup(t, kubeClient, ingress)
t.Log("Waiting for the Ingress to be ready...") t.Log("Waiting for the Ingress to be ready...")
hostname, err := waitForIngressHostname(t, ns, name) hostname, err := waitForIngressHostname(t, ns, ingress.Name)
if err != nil { if err != nil {
t.Fatalf("error waiting for Ingress hostname: %v", err) t.Fatalf("error waiting for Ingress hostname: %v", err)
} }
@@ -278,19 +280,20 @@ func TestL7HAIngress(t *testing.T) {
func TestL7HAIngressMultiTailnet(t *testing.T) { func TestL7HAIngressMultiTailnet(t *testing.T) {
if tnClient == nil || secondTNClient == nil { if tnClient == nil || secondTNClient == nil {
t.Skip("TestL7HAMultiTailnet requires a working tailnet client for a first and second tailnet") t.Skip("TestL7HAIngressMultiTailnet requires a working tailnet client for a first and second tailnet")
} }
// Apply nginx Deployment and Service. // Apply nginx Deployment and Service.
createAndCleanup(t, kubeClient, nginxDeployment(ns, "nginx")) nginx := nginxDeployment(ns)
createAndCleanup(t, kubeClient, nginx)
createAndCleanup(t, kubeClient, &corev1.Service{ createAndCleanup(t, kubeClient, &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "nginx", Name: nginx.Name,
Namespace: ns, Namespace: ns,
}, },
Spec: corev1.ServiceSpec{ Spec: corev1.ServiceSpec{
Selector: map[string]string{ Selector: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": nginx.Name,
}, },
Ports: []corev1.ServicePort{ Ports: []corev1.ServicePort{
{ {
@@ -304,7 +307,7 @@ func TestL7HAIngressMultiTailnet(t *testing.T) {
// Create Ingress ProxyGroup for each Tailnet. // Create Ingress ProxyGroup for each Tailnet.
firstTailnetPG := &tsapi.ProxyGroup{ firstTailnetPG := &tsapi.ProxyGroup{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "first-tailnet", Name: generateName("first-tailnet"),
}, },
Spec: tsapi.ProxyGroupSpec{ Spec: tsapi.ProxyGroupSpec{
Type: tsapi.ProxyGroupTypeIngress, Type: tsapi.ProxyGroupTypeIngress,
@@ -313,7 +316,7 @@ func TestL7HAIngressMultiTailnet(t *testing.T) {
createAndCleanup(t, kubeClient, firstTailnetPG) createAndCleanup(t, kubeClient, firstTailnetPG)
secondTailnetPG := &tsapi.ProxyGroup{ secondTailnetPG := &tsapi.ProxyGroup{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "second-tailnet", Name: generateName("second-tailnet"),
}, },
Spec: tsapi.ProxyGroupSpec{ Spec: tsapi.ProxyGroupSpec{
Type: tsapi.ProxyGroupTypeIngress, Type: tsapi.ProxyGroupTypeIngress,
@@ -330,14 +333,13 @@ func TestL7HAIngressMultiTailnet(t *testing.T) {
} }
// Apply Ingress to expose nginx. // Apply Ingress to expose nginx.
name := generateName("test-ingress") ingress := l7Ingress(ns, nginx.Name, map[string]string{
ingress := l7Ingress(ns, name, map[string]string{ "tailscale.com/proxy-group": secondTailnetPG.Name,
"tailscale.com/proxy-group": "second-tailnet",
}) })
createAndCleanup(t, kubeClient, ingress) createAndCleanup(t, kubeClient, ingress)
// Check that the tailscale (VIP) Service has been created in the expected Tailnet. // Check that the tailscale (VIP) Service has been created in the expected Tailnet.
svcName := "svc:" + name svcName := "svc:" + ingress.Name
if err := tstest.WaitFor(3*time.Minute, func() error { if err := tstest.WaitFor(3*time.Minute, func() error {
_, err := secondTSClient.VIPServices().Get(t.Context(), svcName) _, err := secondTSClient.VIPServices().Get(t.Context(), svcName)
if tailscale.IsNotFound(err) { if tailscale.IsNotFound(err) {
@@ -347,7 +349,7 @@ func TestL7HAIngressMultiTailnet(t *testing.T) {
}); err != nil { }); err != nil {
t.Fatalf("Tailscale service %q never appeared in expected tailnet: %v", svcName, err) t.Fatalf("Tailscale service %q never appeared in expected tailnet: %v", svcName, err)
} }
hostname, err := waitForIngressHostname(t, ns, name) hostname, err := waitForIngressHostname(t, ns, ingress.Name)
if err != nil { if err != nil {
t.Fatalf("error waiting for Ingress hostname: %v", err) t.Fatalf("error waiting for Ingress hostname: %v", err)
} }
@@ -356,7 +358,8 @@ func TestL7HAIngressMultiTailnet(t *testing.T) {
} }
} }
func l7Ingress(namespace, name string, annotations map[string]string) *networkingv1.Ingress { func l7Ingress(namespace, svc string, annotations map[string]string) *networkingv1.Ingress {
name := generateName("test-ingress")
ingress := &networkingv1.Ingress{ ingress := &networkingv1.Ingress{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
@@ -378,7 +381,7 @@ func l7Ingress(namespace, name string, annotations map[string]string) *networkin
PathType: new(networkingv1.PathTypePrefix), PathType: new(networkingv1.PathTypePrefix),
Backend: networkingv1.IngressBackend{ Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{ Service: &networkingv1.IngressServiceBackend{
Name: "nginx", Name: svc,
Port: networkingv1.ServiceBackendPort{ Port: networkingv1.ServiceBackendPort{
Number: 80, Number: 80,
}, },
@@ -395,26 +398,27 @@ func l7Ingress(namespace, name string, annotations map[string]string) *networkin
return ingress return ingress
} }
func nginxDeployment(namespace, name string) *appsv1.Deployment { func nginxDeployment(namespace string) *appsv1.Deployment {
name := generateName("nginx")
return &appsv1.Deployment{ return &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: namespace,
Labels: map[string]string{ Labels: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": name,
}, },
}, },
Spec: appsv1.DeploymentSpec{ Spec: appsv1.DeploymentSpec{
Replicas: new(int32(1)), Replicas: new(int32(1)),
Selector: &metav1.LabelSelector{ Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{ MatchLabels: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": name,
}, },
}, },
Template: corev1.PodTemplateSpec{ Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{ Labels: map[string]string{
"app.kubernetes.io/name": "nginx", "app.kubernetes.io/name": name,
}, },
}, },
Spec: corev1.PodSpec{ Spec: corev1.PodSpec{
+2 -2
View File
@@ -54,7 +54,7 @@ func createAndCleanup(t *testing.T, cl client.Client, obj client.Object) {
t.Cleanup(func() { t.Cleanup(func() {
// Use context.Background() for cleanup, as t.Context() is cancelled // Use context.Background() for cleanup, as t.Context() is cancelled
// just before cleanup functions are called. // just before cleanup functions are called.
if err = cl.Delete(context.Background(), obj); err != nil { if err := cl.Delete(context.Background(), obj); err != nil {
t.Errorf("error cleaning up %s %s/%s: %s", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName(), err) t.Errorf("error cleaning up %s %s/%s: %s", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName(), err)
} }
}) })
@@ -69,7 +69,7 @@ func createAndCleanupErr(t *testing.T, cl client.Client, obj client.Object) erro
} }
t.Cleanup(func() { t.Cleanup(func() {
if err = cl.Delete(context.Background(), obj); err != nil { if err := cl.Delete(context.Background(), obj); err != nil {
t.Errorf("error cleaning up %s %s/%s: %s", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName(), err) t.Errorf("error cleaning up %s %s/%s: %s", obj.GetObjectKind().GroupVersionKind(), obj.GetNamespace(), obj.GetName(), err)
} }
}) })