diff --git a/cmd/k8s-operator/egress-services.go b/cmd/k8s-operator/egress-services.go index 05be8efed..10994ca1a 100644 --- a/cmd/k8s-operator/egress-services.go +++ b/cmd/k8s-operator/egress-services.go @@ -228,6 +228,11 @@ func (esr *egressSvcsReconciler) provision(ctx context.Context, proxyGroupName s // loop over ClusterIP Service ports, remove any that are not needed. for i := len(clusterIPSvc.Spec.Ports) - 1; i >= 0; i-- { pm := clusterIPSvc.Spec.Ports[i] + // Remove health check port; will be re-added with correct configuration. + if pm.Name == tsHealthCheckPortName { + clusterIPSvc.Spec.Ports = slices.Delete(clusterIPSvc.Spec.Ports, i, i+1) + continue + } found := false for _, wantsPM := range svc.Spec.Ports { if wantsPM.Port == pm.Port && strings.EqualFold(string(wantsPM.Protocol), string(pm.Protocol)) { diff --git a/cmd/k8s-operator/egress-services_test.go b/cmd/k8s-operator/egress-services_test.go index 202804d30..c5ad4fbf4 100644 --- a/cmd/k8s-operator/egress-services_test.go +++ b/cmd/k8s-operator/egress-services_test.go @@ -9,6 +9,7 @@ import ( "context" "encoding/json" "fmt" + "slices" "testing" "github.com/AlekSi/pointer" @@ -116,6 +117,43 @@ func TestTailscaleEgressServices(t *testing.T) { validateReadyService(t, fc, esr, svc, clock, zl, cm) }) + t.Run("user_port_9002_gets_allocated_target_port", func(t *testing.T) { + svc.Spec.Ports = []corev1.ServicePort{ + {Protocol: "TCP", Port: 80, Name: "http"}, + {Protocol: "TCP", Port: 9002, Name: "custom-port"}, + } + mustUpdate(t, fc, "default", "test", func(s *corev1.Service) { + s.Spec.Ports = svc.Spec.Ports + }) + expectReconciled(t, esr, "default", "test") + + name := findGenNameForEgressSvcResources(t, fc, svc) + clusterSvc := mustGetClusterIPSvc(t, fc, name) + + idx := slices.IndexFunc(clusterSvc.Spec.Ports, func(p corev1.ServicePort) bool { + return p.Port == 9002 && p.Name == "custom-port" + }) + if idx == -1 { + t.Fatal("user port 9002 not found") + } + if tp := clusterSvc.Spec.Ports[idx].TargetPort.IntVal; tp < 10000 || tp >= 11000 { + t.Errorf("user port 9002 TargetPort = %d, want [10000-11000)", tp) + } + + idx = slices.IndexFunc(clusterSvc.Spec.Ports, func(p corev1.ServicePort) bool { + return p.Name == "tailscale-health-check" + }) + if idx == -1 { + t.Fatal("health check port not found") + } + if got := clusterSvc.Spec.Ports[idx].Port; got != 9003 { + t.Errorf("health check Port = %d, want 9003", got) + } + if got := clusterSvc.Spec.Ports[idx].TargetPort.IntVal; got != 9002 { + t.Errorf("health check TargetPort = %d, want 9002", got) + } + }) + t.Run("delete_external_name_service", func(t *testing.T) { name := findGenNameForEgressSvcResources(t, fc, svc) if err := fc.Delete(context.Background(), svc); err != nil {