diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd.yml index 4c841827b..67967d898 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd.yml +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd.yml @@ -222,6 +222,7 @@ spec: - match: HostSNI(`bar.com`) services: - name: whoamitcp + namespace: default port: 8080 tls: secretName: foosecret diff --git a/integration/fixtures/k8s/05-ingressroutetcp.yml b/integration/fixtures/k8s/05-ingressroutetcp.yml index 8c9fbf7d1..32bf76864 100644 --- a/integration/fixtures/k8s/05-ingressroutetcp.yml +++ b/integration/fixtures/k8s/05-ingressroutetcp.yml @@ -11,6 +11,7 @@ spec: - match: HostSNI(`*`) services: - name: whoamitcp + namespace: default port: 8080 tls: options: diff --git a/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml b/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml index 5f6615f2d..aa38c760b 100644 --- a/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml +++ b/pkg/provider/kubernetes/crd/fixtures/tcp/services.yml @@ -86,3 +86,48 @@ subsets: ports: - name: web-secure port: 443 + +--- +apiVersion: v1 +kind: Service +metadata: + name: whoamitcp3 + namespace: ns3 + +spec: + ports: + - name: myapp3 + port: 8083 + selector: + app: containous + task: whoamitcp3 + +--- +kind: Endpoints +apiVersion: v1 +metadata: + name: whoamitcp3 + namespace: ns3 + +subsets: + - addresses: + - ip: 10.10.0.7 + - ip: 10.10.0.8 + ports: + - name: myapp3 + port: 8083 + +--- +kind: Endpoints +apiVersion: v1 +metadata: + name: whoamitcp3 + namespace: ns4 + +subsets: + - addresses: + - ip: 10.10.0.9 + - ip: 10.10.0.10 + ports: + - name: myapp4 + port: 8084 diff --git a/pkg/provider/kubernetes/crd/fixtures/tcp/with_different_services_ns.yml b/pkg/provider/kubernetes/crd/fixtures/tcp/with_different_services_ns.yml new file mode 100644 index 000000000..4d89d1184 --- /dev/null +++ b/pkg/provider/kubernetes/crd/fixtures/tcp/with_different_services_ns.yml @@ -0,0 +1,31 @@ +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRouteTCP +metadata: + name: test.route + namespace: default + +spec: + entryPoints: + - foo + + routes: + - match: HostSNI(`foo.com`) + services: + # without namespace + - name: whoamitcp + port: 8000 + weight: 2 + # with default namespace + - name: whoamitcp2 + namespace: default + port: 8080 + weight: 3 + # with custom namespace + - name: whoamitcp3 + namespace: ns3 + port: 8083 + weight: 4 + # with unknown namespace + - name: whoamitcp + namespace: unknwonns + port: 8080 diff --git a/pkg/provider/kubernetes/crd/kubernetes_tcp.go b/pkg/provider/kubernetes/crd/kubernetes_tcp.go index 1a27885d4..95e6fb9e7 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_tcp.go +++ b/pkg/provider/kubernetes/crd/kubernetes_tcp.go @@ -129,7 +129,12 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client } func createLoadBalancerServerTCP(client Client, namespace string, service v1alpha1.ServiceTCP) (*dynamic.TCPService, error) { - servers, err := loadTCPServers(client, namespace, service) + ns := namespace + if len(service.Namespace) > 0 { + ns = service.Namespace + } + + servers, err := loadTCPServers(client, ns, service) if err != nil { return nil, err } diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index 7444dd353..cfee54b7c 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -191,6 +191,83 @@ func TestLoadIngressRouteTCPs(t *testing.T) { TLS: &dynamic.TLSConfiguration{}, }, }, + { + desc: "One ingress Route with different services namespaces", + paths: []string{"tcp/services.yml", "tcp/with_different_services_ns.yml"}, + expected: &dynamic.Configuration{ + TCP: &dynamic.TCPConfiguration{ + Routers: map[string]*dynamic.TCPRouter{ + "default-test.route-fdd3e9338e47a45efefc": { + EntryPoints: []string{"foo"}, + Service: "default-test.route-fdd3e9338e47a45efefc", + Rule: "HostSNI(`foo.com`)", + }, + }, + Services: map[string]*dynamic.TCPService{ + "default-test.route-fdd3e9338e47a45efefc": { + Weighted: &dynamic.TCPWeightedRoundRobin{ + Services: []dynamic.TCPWRRService{ + { + Name: "default-test.route-fdd3e9338e47a45efefc-whoamitcp-8000", + Weight: func(i int) *int { return &i }(2), + }, + { + Name: "default-test.route-fdd3e9338e47a45efefc-whoamitcp2-8080", + Weight: func(i int) *int { return &i }(3), + }, + { + Name: "default-test.route-fdd3e9338e47a45efefc-whoamitcp3-8083", + Weight: func(i int) *int { return &i }(4), + }, + }, + }, + }, + "default-test.route-fdd3e9338e47a45efefc-whoamitcp-8000": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{ + { + Address: "10.10.0.1:8000", + }, + { + Address: "10.10.0.2:8000", + }, + }, + }, + }, + "default-test.route-fdd3e9338e47a45efefc-whoamitcp2-8080": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{ + { + Address: "10.10.0.3:8080", + }, + { + Address: "10.10.0.4:8080", + }, + }, + }, + }, + "default-test.route-fdd3e9338e47a45efefc-whoamitcp3-8083": { + LoadBalancer: &dynamic.TCPServersLoadBalancer{ + Servers: []dynamic.TCPServer{ + { + Address: "10.10.0.7:8083", + }, + { + Address: "10.10.0.8:8083", + }, + }, + }, + }, + }, + }, + HTTP: &dynamic.HTTPConfiguration{ + Routers: map[string]*dynamic.Router{}, + Middlewares: map[string]*dynamic.Middleware{}, + Services: map[string]*dynamic.Service{}, + }, + TLS: &dynamic.TLSConfiguration{}, + }, + }, { desc: "Ingress class does not match", paths: []string{"tcp/services.yml", "tcp/simple.yml"}, diff --git a/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroutetcp.go b/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroutetcp.go index 50dc7a49e..b6b47b22f 100644 --- a/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroutetcp.go +++ b/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroutetcp.go @@ -46,6 +46,7 @@ type TLSOptionTCPRef struct { // ServiceTCP defines an upstream to proxy traffic. type ServiceTCP struct { Name string `json:"name"` + Namespace string `json:"namespace"` Port int32 `json:"port"` Weight *int `json:"weight,omitempty"` TerminationDelay *int `json:"terminationDelay,omitempty"`