Merge branch v2.3 into master

This commit is contained in:
kevinpollet 2020-12-11 10:58:00 +01:00
commit eebbe64b36
No known key found for this signature in database
GPG key ID: 0C9A5DDD1B292453
46 changed files with 1949 additions and 148 deletions

View file

@ -2,15 +2,23 @@ package crd
import (
"context"
"io/ioutil"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/provider"
crdfake "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/generated/clientset/versioned/fake"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/k8s"
"github.com/traefik/traefik/v2/pkg/tls"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
kubefake "k8s.io/client-go/kubernetes/fake"
)
var _ provider.Provider = (*Provider)(nil)
@ -1010,6 +1018,129 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Ingress Route with IPv6 backends",
paths: []string{
"services.yml", "with_ipv6.yml",
"tcp/services.yml", "tcp/with_ipv6.yml",
"udp/services.yml", "udp/with_ipv6.yml",
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"default-test.route-0": {
EntryPoints: []string{"foo"},
Service: "default-test.route-0",
},
},
Services: map[string]*dynamic.UDPService{
"default-test.route-0": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{
Address: "[fd00:10:244:0:1::3]:8080",
},
},
},
},
},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-673acf455cb2dab0b43a": {
EntryPoints: []string{"foo"},
Service: "default-test.route-673acf455cb2dab0b43a",
Rule: "HostSNI(`*`)",
},
},
Services: map[string]*dynamic.TCPService{
"default-test.route-673acf455cb2dab0b43a": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-test.route-673acf455cb2dab0b43a-whoamitcp-ipv6-8080",
Weight: func(i int) *int { return &i }(1),
},
{
Name: "default-test.route-673acf455cb2dab0b43a-external.service.with.ipv6-8080",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-test.route-673acf455cb2dab0b43a-whoamitcp-ipv6-8080": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "[fd00:10:244:0:1::3]:8080",
},
{
Address: "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8080",
},
},
},
},
"default-test.route-673acf455cb2dab0b43a-external.service.with.ipv6-8080": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "[fe80::200:5aee:feaa:20a2]:8080",
},
},
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{
"default-test-route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-whoami-ipv6-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8080",
},
},
PassHostHeader: func(i bool) *bool { return &i }(true),
},
},
"default-external-svc-with-ipv6-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://[2001:db8:85a3:8d3:1319:8a2e:370:7347]:8080",
},
},
PassHostHeader: func(i bool) *bool { return &i }(true),
},
},
"default-test-route-6b204d94623b3df4370c": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-ipv6-8080",
Weight: func(i int) *int { return &i }(1),
},
{
Name: "default-external-svc-with-ipv6-8080",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
@ -1023,7 +1154,10 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
}
p := Provider{IngressClass: test.ingressClass}
conf := p.loadConfigurationFromCRD(context.Background(), newClientMock(test.paths...))
p.SetDefaults()
clientMock := newClientMock(test.paths...)
conf := p.loadConfigurationFromCRD(context.Background(), clientMock)
assert.Equal(t, test.expected, conf)
})
}
@ -3205,7 +3339,10 @@ func TestLoadIngressRoutes(t *testing.T) {
}
p := Provider{IngressClass: test.ingressClass}
conf := p.loadConfigurationFromCRD(context.Background(), newClientMock(test.paths...))
p.SetDefaults()
clientMock := newClientMock(test.paths...)
conf := p.loadConfigurationFromCRD(context.Background(), clientMock)
assert.Equal(t, test.expected, conf)
})
}
@ -3519,7 +3656,10 @@ func TestLoadIngressRouteUDPs(t *testing.T) {
}
p := Provider{IngressClass: test.ingressClass}
conf := p.loadConfigurationFromCRD(context.Background(), newClientMock(test.paths...))
p.SetDefaults()
clientMock := newClientMock(test.paths...)
conf := p.loadConfigurationFromCRD(context.Background(), clientMock)
assert.Equal(t, test.expected, conf)
})
}
@ -3738,3 +3878,572 @@ func TestGetServicePort(t *testing.T) {
})
}
}
func TestCrossNamespace(t *testing.T) {
testCases := []struct {
desc string
allowCrossNamespace bool
ingressClass string
paths []string
expected *dynamic.Configuration
}{
{
desc: "Empty",
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTP middleware cross namespace disallowed",
paths: []string{"services.yml", "with_middleware_cross_namespace.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{
"default-test-crossnamespace-route-9313b71dbe6a649d5049": {
EntryPoints: []string{"foo"},
Service: "default-test-crossnamespace-route-9313b71dbe6a649d5049",
Rule: "Host(`foo.com`) && PathPrefix(`/bir`)",
Priority: 12,
Middlewares: []string{"default-test-errorpage"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"cross-ns-stripprefix": {
StripPrefix: &dynamic.StripPrefix{
Prefixes: []string{"/stripit"},
ForceSlash: false,
},
},
},
Services: map[string]*dynamic.Service{
"default-test-crossnamespace-route-9313b71dbe6a649d5049": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTP middleware cross namespace allowed",
paths: []string{"services.yml", "with_middleware_cross_namespace.yml"},
allowCrossNamespace: true,
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{
"default-test-crossnamespace-route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-test-crossnamespace-route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12,
Middlewares: []string{
"cross-ns-stripprefix",
},
},
"default-test-crossnamespace-route-9313b71dbe6a649d5049": {
EntryPoints: []string{"foo"},
Service: "default-test-crossnamespace-route-9313b71dbe6a649d5049",
Rule: "Host(`foo.com`) && PathPrefix(`/bir`)",
Priority: 12,
Middlewares: []string{"default-test-errorpage"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"cross-ns-stripprefix": {
StripPrefix: &dynamic.StripPrefix{
Prefixes: []string{"/stripit"},
ForceSlash: false,
},
},
"default-test-errorpage": {
Errors: &dynamic.ErrorPage{
Status: []string{"500-599"},
Service: "default-test-errorpage-errorpage-service",
Query: "/{status}.html",
},
},
},
Services: map[string]*dynamic.Service{
"default-test-crossnamespace-route-6b204d94623b3df4370c": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
"default-test-crossnamespace-route-9313b71dbe6a649d5049": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
"default-test-errorpage-errorpage-service": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTP cross namespace allowed",
paths: []string{"services.yml", "with_cross_namespace.yml"},
allowCrossNamespace: true,
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{
"default-cross-ns-route-6b204d94623b3df4370c": {
EntryPoints: []string{"foo"},
Service: "default-cross-ns-route-6b204d94623b3df4370c",
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-cross-ns-route-6b204d94623b3df4370c": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "cross-ns-whoami-svc-80",
Weight: func(i int) *int { return &i }(1),
},
{
Name: "default-tr-svc-wrr1",
Weight: func(i int) *int { return &i }(1),
},
{
Name: "cross-ns-tr-svc-wrr2",
Weight: func(i int) *int { return &i }(1),
},
{
Name: "default-tr-svc-mirror1",
Weight: func(i int) *int { return &i }(1),
},
{
Name: "cross-ns-tr-svc-mirror2",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"cross-ns-whoami-svc-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
"default-tr-svc-wrr1": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "cross-ns-whoami-svc-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"cross-ns-tr-svc-wrr2": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "cross-ns-whoami-svc-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-tr-svc-mirror1": {
Mirroring: &dynamic.Mirroring{
Service: "default-whoami-80",
Mirrors: []dynamic.MirrorService{
{
Name: "cross-ns-whoami-svc-80",
Percent: 20,
},
},
},
},
"cross-ns-tr-svc-mirror2": {
Mirroring: &dynamic.Mirroring{
Service: "cross-ns-whoami-svc-80",
Mirrors: []dynamic.MirrorService{
{
Name: "cross-ns-whoami-svc-80",
Percent: 20,
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTP cross namespace disallowed",
paths: []string{"services.yml", "with_cross_namespace.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"cross-ns-tr-svc-wrr2": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "cross-ns-whoami-svc-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"cross-ns-whoami-svc-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
"cross-ns-tr-svc-mirror2": {
Mirroring: &dynamic.Mirroring{
Service: "cross-ns-whoami-svc-80",
Mirrors: []dynamic.MirrorService{
{
Name: "cross-ns-whoami-svc-80",
Percent: 20,
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TCP cross namespace allowed",
paths: []string{"tcp/services.yml", "tcp/with_cross_namespace.yml"},
allowCrossNamespace: true,
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
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": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.1:8000",
Port: "",
},
{
Address: "10.10.0.2:8000",
Port: "",
},
},
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TCP cross namespace disallowed",
paths: []string{"tcp/services.yml", "tcp/with_cross_namespace.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
// The router that references the invalid service will be discarded.
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{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "UDP cross namespace allowed",
paths: []string{"udp/services.yml", "udp/with_cross_namespace.yml"},
allowCrossNamespace: true,
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"default-test.route-0": {
EntryPoints: []string{"foo"},
Service: "default-test.route-0",
},
},
Services: map[string]*dynamic.UDPService{
"default-test.route-0": {
LoadBalancer: &dynamic.UDPServersLoadBalancer{
Servers: []dynamic.UDPServer{
{
Address: "10.10.0.1:8000",
Port: "",
},
{
Address: "10.10.0.2:8000",
Port: "",
},
},
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "UDP cross namespace disallowed",
paths: []string{"udp/services.yml", "udp/with_cross_namespace.yml"},
expected: &dynamic.Configuration{
// The router that references the invalid service will be discarded.
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{
"default-test.route-0": {
EntryPoints: []string{"foo"},
Service: "default-test.route-0",
},
},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
ServersTransports: map[string]*dynamic.ServersTransport{},
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
var k8sObjects []runtime.Object
var crdObjects []runtime.Object
for _, path := range test.paths {
yamlContent, err := ioutil.ReadFile(filepath.FromSlash("./fixtures/" + path))
if err != nil {
panic(err)
}
objects := k8s.MustParseYaml(yamlContent)
for _, obj := range objects {
switch o := obj.(type) {
case *corev1.Service, *corev1.Endpoints, *corev1.Secret:
k8sObjects = append(k8sObjects, o)
case *v1alpha1.IngressRoute:
crdObjects = append(crdObjects, o)
case *v1alpha1.IngressRouteTCP:
crdObjects = append(crdObjects, o)
case *v1alpha1.IngressRouteUDP:
crdObjects = append(crdObjects, o)
case *v1alpha1.Middleware:
crdObjects = append(crdObjects, o)
case *v1alpha1.TraefikService:
crdObjects = append(crdObjects, o)
case *v1alpha1.TLSOption:
crdObjects = append(crdObjects, o)
case *v1alpha1.TLSStore:
crdObjects = append(crdObjects, o)
default:
}
}
}
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
crdClient := crdfake.NewSimpleClientset(crdObjects...)
client := newClientImpl(kubeClient, crdClient)
stopCh := make(chan struct{})
eventCh, err := client.WatchAll([]string{"default", "cross-ns"}, stopCh)
require.NoError(t, err)
if k8sObjects != nil || crdObjects != nil {
// just wait for the first event
<-eventCh
}
p := Provider{}
p.SetDefaults()
p.AllowCrossNamespace = func(b bool) *bool { return &b }(test.allowCrossNamespace)
conf := p.loadConfigurationFromCRD(context.Background(), client)
assert.Equal(t, test.expected, conf)
})
}
}