traefik/pkg/provider/kubernetes/gateway/kubernetes_test.go
2024-06-13 17:06:04 +02:00

6907 lines
215 KiB
Go

package gateway
import (
"context"
"errors"
"net/http"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/provider"
traefikv1alpha1 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
"github.com/traefik/traefik/v3/pkg/tls"
"github.com/traefik/traefik/v3/pkg/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
kubefake "k8s.io/client-go/kubernetes/fake"
kscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/utils/ptr"
gatev1 "sigs.k8s.io/gateway-api/apis/v1"
gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatev1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
gatefake "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/fake"
)
var _ provider.Provider = (*Provider)(nil)
func init() {
// required by k8s.MustParseYaml
if err := gatev1.AddToScheme(kscheme.Scheme); err != nil {
panic(err)
}
if err := gatev1beta1.AddToScheme(kscheme.Scheme); err != nil {
panic(err)
}
if err := gatev1alpha2.AddToScheme(kscheme.Scheme); err != nil {
panic(err)
}
}
func TestLoadHTTPRoutes(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
experimentalChannel bool
}{
{
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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because missing entry point",
paths: []string{"services.yml", "httproute/simple.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":443",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because no http route defined",
paths: []string{"services.yml", "httproute/without_httproute.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by missing GatewayClass",
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
paths: []string{"services.yml", "httproute/without_gatewayclass.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by unknown GatewayClass controller desc",
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
paths: []string{"services.yml", "httproute/gatewayclass_with_unknown_controller.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by multi ports service with wrong TargetPort",
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
paths: []string{"services.yml", "httproute/with_wrong_service_port.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-9000",
Weight: ptr.To(1),
Status: ptr.To(500),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by HTTPS without TLS",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":443",
}},
paths: []string{"services.yml", "httproute/with_protocol_https_without_tls.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by HTTPS with TLS passthrough",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":443",
}},
paths: []string{"services.yml", "httproute/with_protocol_https_with_tls_passthrough.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by HTTPRoute with protocol TLS",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":443",
}},
paths: []string{"services.yml", "httproute/with_protocol_tls.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by HTTPRoute with protocol TCP",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":443",
}},
paths: []string{"services.yml", "httproute/with_protocol_tcp.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by TCPRoute with protocol HTTP",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":9000",
}},
paths: []string{"services.yml", "tcproute/with_protocol_http.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by TCPRoute with protocol HTTPS",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":9000",
}},
paths: []string{"services.yml", "tcproute/with_protocol_https.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by TLSRoute with protocol TCP",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":9001",
}},
paths: []string{"services.yml", "tlsroute/with_protocol_tcp.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by TLSRoute with protocol HTTP",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":9001",
}},
paths: []string{"services.yml", "tlsroute/with_protocol_http.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by TLSRoute with protocol HTTPS",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":9001",
}},
paths: []string{"services.yml", "tlsroute/with_protocol_https.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused use http entrypoint with tls activated with HTTPRoute",
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":443",
HasHTTPTLSConf: true,
}},
paths: []string{"services.yml", "httproute/simple_with_tls_entrypoint.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because no tcp route defined tls protocol",
paths: []string{"services.yml", "tcproute/without_tcproute_tls_protocol.yml"},
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
experimentalChannel: 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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Empty caused by HTTPRoute with TLS configuration",
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
paths: []string{"services.yml", "httproute/with_tls_configuration.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute",
paths: []string{"services.yml", "httproute/simple.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, with api@internal service",
paths: []string{"services.yml", "httproute/simple_to_api_internal.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "api@internal",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute with protocol HTTPS",
paths: []string{"services.yml", "httproute/with_protocol_https.yml"},
entryPoints: map[string]Entrypoint{"websecure": {
Address: ":443",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-1-my-gateway-websecure-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Simple HTTPRoute, with multiple hosts",
paths: []string{"services.yml", "httproute/with_multiple_host.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-66e726cd8903b49727ae": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "(Host(`foo.com`) || Host(`bar.com`)) && PathPrefix(`/`)",
Priority: 9,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, with two hosts one wildcard",
paths: []string{"services.yml", "with_two_hosts_one_wildcard.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-baa117c0219e3878749f": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.bar\\.com$`)) && PathPrefix(`/`)",
Priority: 11,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, with one host and a wildcard",
paths: []string{"services.yml", "with_two_hosts_wildcard.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-45eba2eaf40ac792e036": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "(Host(`foo.com`) || HostRegexp(`^[a-z0-9-\\.]+\\.foo\\.com$`)) && PathPrefix(`/`)",
Priority: 11,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "One HTTPRoute with two different rules",
paths: []string{"services.yml", "httproute/two_rules.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100009,
RuleSyntax: "v3",
Service: "default-http-app-1-my-gateway-web-0-wrr",
},
"default-http-app-1-my-gateway-web-1-d737b4933fa88e68ab8a": {
EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && Path(`/bir`)",
Priority: 100008,
RuleSyntax: "v3",
Service: "default-http-app-1-my-gateway-web-1-wrr",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-1-my-gateway-web-1-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami2-8080",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"default-whoami2-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.3:8080",
},
{
URL: "http://10.10.0.4:8080",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "One HTTPRoute with one rule two targets",
paths: []string{"services.yml", "httproute/one_rule_two_targets.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
Service: "default-http-app-1-my-gateway-web-0-wrr",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
{
Name: "default-whoami2-8080",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"default-whoami2-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.3:8080",
},
{
URL: "http://10.10.0.4:8080",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Two Gateways and one HTTPRoute",
paths: []string{"services.yml", "httproute/with_two_gateways_one_httproute.yml"},
entryPoints: map[string]Entrypoint{
"web": {
Address: ":80",
},
"websecure": {
Address: ":443",
},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-http-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-http-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
"default-http-app-1-my-gateway-https-websecure-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-1-my-gateway-https-websecure-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-http-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-1-my-gateway-https-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Gateway with two listeners and one HTTPRoute",
paths: []string{"services.yml", "httproute/with_two_listeners_one_httproute.yml"},
entryPoints: map[string]Entrypoint{
"web": {
Address: ":80",
},
"websecure": {
Address: ":443",
},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
"default-http-app-1-my-gateway-websecure-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-1-my-gateway-websecure-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-1-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Simple HTTPRoute, with several rules",
paths: []string{"services.yml", "httproute/with_several_rules.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-6cf37fa71907768d925c": {
EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && (Path(`/bar`) || PathPrefix(`/bar/`)) && Header(`my-header`,`foo`) && Header(`my-header2`,`bar`)",
Priority: 10610,
RuleSyntax: "v3",
Service: "default-http-app-1-my-gateway-web-0-wrr",
},
"default-http-app-1-my-gateway-web-2-d23f7039bc8036fb918c": {
EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && PathRegexp(`^/buzz/[0-9]+$`)",
Priority: 2408,
RuleSyntax: "v3",
Service: "default-http-app-1-my-gateway-web-2-wrr",
},
"default-http-app-1-my-gateway-web-1-aaba0f24fd26e1ca2276": {
EntryPoints: []string{"web"},
Rule: "Host(`foo.com`) && Path(`/bar`) && Header(`my-header`,`bar`)",
Priority: 100109,
RuleSyntax: "v3",
Service: "default-http-app-1-my-gateway-web-1-wrr",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-1-my-gateway-web-2-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-1-my-gateway-web-1-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTPRoute with Same namespace selector",
paths: []string{"services.yml", "httproute/with_namespace_same.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":80"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb": {
EntryPoints: []string{"web"},
Service: "default-http-app-default-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/foo`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-default-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTPRoute with All namespace selector",
paths: []string{"services.yml", "httproute/with_namespace_all.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":80"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-default-my-gateway-web-0-efde1997778109a1f6eb": {
EntryPoints: []string{"web"},
Service: "default-http-app-default-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/foo`)",
Priority: 100008,
RuleSyntax: "v3",
},
"bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597": {
EntryPoints: []string{"web"},
Service: "bar-http-app-bar-my-gateway-web-0-wrr",
Rule: "Host(`bar.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-default-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"bar-http-app-bar-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "bar-whoami-bar-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"bar-whoami-bar-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.11:80",
},
{
URL: "http://10.10.0.12:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTPRoute with namespace selector",
paths: []string{"services.yml", "httproute/with_namespace_selector.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":80"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"bar-http-app-bar-my-gateway-web-0-66f5c78d03d948e36597": {
EntryPoints: []string{"web"},
Service: "bar-http-app-bar-my-gateway-web-0-wrr",
Rule: "Host(`bar.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"bar-http-app-bar-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "bar-whoami-bar-80",
Weight: ptr.To(1),
},
},
},
},
"bar-whoami-bar-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.11:80",
},
{
URL: "http://10.10.0.12:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, request header modifier",
paths: []string{"services.yml", "httproute/filter_request_header_modifier.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`example.org`) && PathPrefix(`/`)",
Priority: 13,
RuleSyntax: "v3",
Middlewares: []string{"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-requestheadermodifier-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-requestheadermodifier-0": {
RequestHeaderModifier: &dynamic.RequestHeaderModifier{
Set: map[string]string{"X-Foo": "Bar"},
Add: map[string]string{"X-Bar": "Foo"},
Remove: []string{"X-Baz"},
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, redirect HTTP to HTTPS",
paths: []string{"services.yml", "httproute/filter_http_to_https.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`example.org`) && PathPrefix(`/`)",
Priority: 13,
RuleSyntax: "v3",
Middlewares: []string{"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-requestredirect-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-requestredirect-0": {
RequestRedirect: &dynamic.RequestRedirect{
Scheme: ptr.To("https"),
Port: ptr.To(""),
StatusCode: http.StatusMovedPermanently,
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, redirect HTTP to HTTPS with hostname",
paths: []string{"services.yml", "httproute/filter_http_to_https_with_hostname_and_port.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`example.org`) && PathPrefix(`/`)",
Priority: 13,
RuleSyntax: "v3",
Middlewares: []string{"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-requestredirect-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-0-364ce6ec04c3d49b19c4-requestredirect-0": {
RequestRedirect: &dynamic.RequestRedirect{
Hostname: ptr.To("example.com"),
Port: ptr.To("443"),
StatusCode: http.StatusFound,
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute URL rewrite FullPath",
paths: []string{"services.yml", "httproute/filter_url_rewrite_fullpath.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`example.com`) && (Path(`/foo`) || PathPrefix(`/foo/`))",
RuleSyntax: "v3",
Priority: 10412,
Middlewares: []string{"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-urlrewrite-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-urlrewrite-0": {
URLRewrite: &dynamic.URLRewrite{
Path: ptr.To("/bar"),
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute URL rewrite Hostname",
paths: []string{"services.yml", "httproute/filter_url_rewrite_hostname.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`example.com`) && (Path(`/foo`) || PathPrefix(`/foo/`))",
RuleSyntax: "v3",
Priority: 10412,
Middlewares: []string{"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-urlrewrite-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-urlrewrite-0": {
URLRewrite: &dynamic.URLRewrite{
Hostname: ptr.To("www.foo.bar"),
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute URL rewrite Combined",
paths: []string{"services.yml", "httproute/filter_url_rewrite_combined.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`example.com`) && (Path(`/foo`) || PathPrefix(`/foo/`))",
RuleSyntax: "v3",
Priority: 10412,
Middlewares: []string{"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-urlrewrite-0"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-http-app-1-my-gateway-web-0-7f90cf546b15efadf2f8-urlrewrite-0": {
URLRewrite: &dynamic.URLRewrite{
Hostname: ptr.To("www.foo.bar"),
Path: ptr.To("/xyz"),
PathPrefix: ptr.To("/foo"),
},
},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: func(i int) *int { return &i }(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
ExperimentalChannel: test.experimentalChannel,
client: client,
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func TestLoadHTTPRoutes_backendExtensionRef(t *testing.T) {
testCases := []struct {
desc string
paths []string
groupKindBackendFuncs map[string]map[string]BuildBackendFunc
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
}{
{
desc: "Simple HTTPRoute with TraefikService",
paths: []string{"services.yml", "httproute/simple_with_TraefikService.yml"},
groupKindBackendFuncs: map[string]map[string]BuildBackendFunc{
traefikv1alpha1.GroupName: {"TraefikService": func(name, namespace string) (string, *dynamic.Service, error) {
return name, nil, nil
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "whoami",
Weight: ptr.To(1),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute with TraefikService with service configuration",
paths: []string{"services.yml", "httproute/simple_with_TraefikService.yml"},
groupKindBackendFuncs: map[string]map[string]BuildBackendFunc{
traefikv1alpha1.GroupName: {"TraefikService": func(name, namespace string) (string, *dynamic.Service, error) {
return name, &dynamic.Service{LoadBalancer: &dynamic.ServersLoadBalancer{Servers: []dynamic.Server{{URL: "foobar"}}}}, nil
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "whoami",
Weight: ptr.To(1),
},
},
},
},
"whoami": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{URL: "foobar"},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute with invalid TraefikService kind",
paths: []string{"services.yml", "httproute/simple_with_TraefikService.yml"},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami",
Weight: ptr.To(1),
Status: ptr.To(500),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute with backendFunc error",
paths: []string{"services.yml", "httproute/simple_with_TraefikService.yml"},
groupKindBackendFuncs: map[string]map[string]BuildBackendFunc{
traefikv1alpha1.GroupName: {"TraefikService": func(name, namespace string) (string, *dynamic.Service, error) {
return "", nil, errors.New("BOOM")
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami",
Weight: ptr.To(1),
Status: ptr.To(500),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple HTTPRoute, with myservice@file service",
paths: []string{"services.yml", "httproute/simple_cross_provider.yml"},
groupKindBackendFuncs: map[string]map[string]BuildBackendFunc{
traefikv1alpha1.GroupName: {"TraefikService": func(name, namespace string) (string, *dynamic.Service, error) {
// func should never be executed in case of cross-provider reference.
return "", nil, errors.New("BOOM")
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "service@file",
Weight: ptr.To(1),
},
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
client: client,
}
for group, kindFuncs := range test.groupKindBackendFuncs {
for kind, backendFunc := range kindFuncs {
p.RegisterBackendFuncs(group, kind, backendFunc)
}
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
testCases := []struct {
desc string
groupKindFilterFuncs map[string]map[string]BuildFilterFunc
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
}{
{
desc: "HTTPRoute with ExtensionRef filter",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return namespace + "-" + name, nil, nil
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
Middlewares: []string{"default-my-middleware"},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "HTTPRoute with ExtensionRef filter and create middleware",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return namespace + "-" + name, &dynamic.Middleware{Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, nil
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
Middlewares: []string{"default-my-middleware"},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-my-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "ExtensionRef filter: Unknown",
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-err-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-err-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "invalid-httproute-filter",
Weight: ptr.To(1),
Status: ptr.To(500),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "ExtensionRef filter with filterFunc error",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return "", nil, errors.New("BOOM")
}},
},
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-err-wrr",
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-err-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "invalid-httproute-filter",
Weight: ptr.To(1),
Status: ptr.To(500),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, []string{"services.yml", "httproute/filter_extension_ref.yml"})
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
client: client,
}
for group, kindFuncs := range test.groupKindFilterFuncs {
for kind, filterFunc := range kindFuncs {
p.RegisterFilterFuncs(group, kind, filterFunc)
}
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func TestLoadTCPRoutes(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
}{
{
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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because missing entry point",
paths: []string{"services.yml", "tcproute/simple.yml"},
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8000",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because no tcp route defined",
paths: []string{"services.yml", "tcproute/without_tcproute.yml"},
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by missing GatewayClass",
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
paths: []string{"services.yml", "tcproute/without_gatewayclass.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by unknown GatewayClass controller desc",
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
paths: []string{"services.yml", "tcproute/gatewayclass_with_unknown_controller.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by HTTPRoute with TLS configuration",
entryPoints: map[string]Entrypoint{"web": {
Address: ":8080",
}},
paths: []string{"services.yml", "tcproute/with_tls_configuration.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by multi ports service with wrong TargetPort",
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
paths: []string{"services.yml", "tcproute/with_wrong_service_port.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TCPRoute",
paths: []string{"services.yml", "tcproute/simple.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-tcp-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-1-my-tcp-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-tcp-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Multiple TCPRoute",
paths: []string{"services.yml", "tcproute/with_multiple_routes.yml"},
entryPoints: map[string]Entrypoint{
"tcp-1": {Address: ":9000"},
"tcp-2": {Address: ":10000"},
"not-tcp": {Address: ":11000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-tcp-gateway-tcp-1": {
EntryPoints: []string{"tcp-1"},
Service: "default-tcp-app-1-my-tcp-gateway-tcp-1-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"default-tcp-app-2-my-tcp-gateway-tcp-2": {
EntryPoints: []string{"tcp-2"},
Service: "default-tcp-app-2-my-tcp-gateway-tcp-2-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-tcp-gateway-tcp-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-2-my-tcp-gateway-tcp-2-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-10000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"default-whoamitcp-10000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:10000",
},
{
Address: "10.10.0.10:10000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TCPRoute with multiple rules",
paths: []string{"services.yml", "tcproute/with_multiple_rules.yml"},
entryPoints: map[string]Entrypoint{
"tcp-1": {Address: ":9000"},
"tcp-2": {Address: ":10000"},
"not-tcp": {Address: ":11000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-my-tcp-gateway-tcp-1": {
EntryPoints: []string{"tcp-1"},
Service: "default-tcp-app-my-tcp-gateway-tcp-1-wrr",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-my-tcp-gateway-tcp-1-wrr": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-tcp-app-my-tcp-gateway-tcp-1-wrr-0",
Weight: ptr.To(1),
},
{
Name: "default-tcp-app-my-tcp-gateway-tcp-1-wrr-1",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-my-tcp-gateway-tcp-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-my-tcp-gateway-tcp-1-wrr-1": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-10000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"default-whoamitcp-10000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:10000",
},
{
Address: "10.10.0.10:10000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TCPRoute, with backendRef",
paths: []string{"services.yml", "tcproute/simple_cross_provider.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-1-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "service@file",
Weight: ptr.To(1),
},
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TCPRoute, with TLS",
paths: []string{"services.yml", "tcproute/with_protocol_tls.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-gateway-tls": {
EntryPoints: []string{"tls"},
Service: "default-tcp-app-1-my-gateway-tls-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-gateway-tls-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
}},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "TCPRoute with Same namespace selector",
paths: []string{"services.yml", "tcproute/with_namespace_same.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-default-my-tcp-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-default-my-tcp-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-default-my-tcp-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TCPRoute with All namespace selector",
paths: []string{"services.yml", "tcproute/with_namespace_all.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-default-my-tcp-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-default-my-tcp-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"bar-tcp-app-bar-my-tcp-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-default-my-tcp-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"bar-whoamitcp-bar-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.13:9000",
},
{
Address: "10.10.0.14:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TCPRoute with namespace selector",
paths: []string{"services.yml", "tcproute/with_namespace_selector.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"bar-tcp-app-bar-my-tcp-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"bar-tcp-app-bar-my-tcp-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-whoamitcp-bar-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.13:9000",
},
{
Address: "10.10.0.14:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
client.experimentalChannel = true
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
ExperimentalChannel: true,
client: client,
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func TestLoadTLSRoutes(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
}{
{
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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because no matching entry point",
paths: []string{"services.yml", "tlsroute/simple_TLS_to_TCPRoute.yml"},
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8000",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because no tls route defined",
paths: []string{"services.yml", "tlsroute/without_tlsroute.yml"},
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by missing GatewayClass",
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
paths: []string{"services.yml", "tlsroute/without_gatewayclass.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by unknown GatewayClass controller desc",
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
paths: []string{"services.yml", "tlsroute/gatewayclass_with_unknown_controller.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by multi ports service with wrong TargetPort",
entryPoints: map[string]Entrypoint{"TCP": {
Address: ":8080",
}},
paths: []string{"services.yml", "tlsroute/with_wrong_service_port.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Empty caused by mixed routes with wrong parent ref",
entryPoints: map[string]Entrypoint{
"tcp": {
Address: ":9000",
},
"tcp-tls": {
Address: ":9443",
},
"http": {
Address: ":80",
},
},
paths: []string{"services.yml", "mixed/with_wrong_routes_selector.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TLS listener to TCPRoute in Terminate mode",
paths: []string{"services.yml", "tlsroute/simple_TLS_to_TCPRoute.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-tls-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-1-my-tls-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-tls-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Simple TLS listener to TCPRoute in Passthrough mode",
paths: []string{"services.yml", "tlsroute/simple_TLS_to_TCPRoute_passthrough.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-tls-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-1-my-tls-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-tls-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TLS listener to TLSRoute",
paths: []string{"services.yml", "tlsroute/simple_TLS_to_TLSRoute.yml"},
entryPoints: map[string]Entrypoint{
"tcp": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270": {
EntryPoints: []string{"tcp"},
Service: "default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270-wrr-0",
Rule: "HostSNI(`foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-1-my-tls-gateway-tcp-f0dd0dd89f82eae1c270-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Multiple TLSRoute",
paths: []string{"services.yml", "tlsroute/with_multiple_routes_kind.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
"tcp": {Address: ":10000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-tls-gateway-tls": {
EntryPoints: []string{"tls"},
Service: "default-tcp-app-1-my-tls-gateway-tls-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
"default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a": {
EntryPoints: []string{"tcp"},
Service: "default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-tls-gateway-tls-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tls-app-1-my-tls-gateway-tcp-673acf455cb2dab0b43a-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-10000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"default-whoamitcp-10000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:10000",
},
{
Address: "10.10.0.10:10000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Simple TLSRoute, with backendRef",
paths: []string{"services.yml", "tlsroute/simple_cross_provider.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tcp-app-1-my-gateway-tls": {
EntryPoints: []string{"tls"},
Service: "default-tcp-app-1-my-gateway-tls-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-gateway-tls-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "service@file",
Weight: ptr.To(1),
},
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Simple TLSRoute, with Passthrough and TLS configuration should raise a warn",
paths: []string{"services.yml", "tlsroute/with_passthrough_tls.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270": {
EntryPoints: []string{"tls"},
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
Rule: "HostSNI(`foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TLSRoute, with Passthrough",
paths: []string{"services.yml", "tlsroute/with_passthrough.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270": {
EntryPoints: []string{"tls"},
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
Rule: "HostSNI(`foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TLSRoute, with single SNI matching",
paths: []string{"services.yml", "tlsroute/with_SNI_matching.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270": {
EntryPoints: []string{"tls"},
Service: "default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0",
Rule: "HostSNI(`foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-1-my-gateway-tls-f0dd0dd89f82eae1c270-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple TLSRoute, with multiple SNI matching",
paths: []string{"services.yml", "tlsroute/with_multiple_SNI_matching.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-1-my-gateway-tls-d5342d75658583f03593": {
EntryPoints: []string{"tls"},
Service: "default-tls-app-1-my-gateway-tls-d5342d75658583f03593-wrr-0",
Rule: "HostSNI(`foo.example.com`) || HostSNI(`bar.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-1-my-gateway-tls-d5342d75658583f03593-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TLSRoute with Same namespace selector",
paths: []string{"services.yml", "tlsroute/with_namespace_same.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5": {
EntryPoints: []string{"tls"},
Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0",
Rule: "HostSNI(`foo.default`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TLSRoute with All namespace selector",
paths: []string{"services.yml", "tlsroute/with_namespace_all.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5": {
EntryPoints: []string{"tls"},
Service: "default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0",
Rule: "HostSNI(`foo.default`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
"bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26": {
EntryPoints: []string{"tls"},
Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0",
Rule: "HostSNI(`foo.bar`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-default-my-gateway-tls-06ae57dcf13ab4c60ee5-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"bar-whoamitcp-bar-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.13:9000",
},
{
Address: "10.10.0.14:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TLSRoute with namespace selector",
paths: []string{"services.yml", "tlsroute/with_namespace_selector.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26": {
EntryPoints: []string{"tls"},
Service: "bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0",
Rule: "HostSNI(`foo.bar`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"bar-tls-app-bar-my-gateway-tls-2279fe75c5156dc5eb26-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-whoamitcp-bar-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.13:9000",
},
{
Address: "10.10.0.14:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "TLSRoute with multiple rules",
paths: []string{"services.yml", "tlsroute/with_multiple_rules.yml"},
entryPoints: map[string]Entrypoint{
"tcp-1": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a": {
EntryPoints: []string{"tcp-1"},
Service: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-0",
Weight: ptr.To(1),
},
{
Name: "default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-1",
Weight: ptr.To(1),
},
},
},
},
"default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tls-app-my-gateway-tcp-1-673acf455cb2dab0b43a-wrr-1": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-10000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"default-whoamitcp-10000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:10000",
},
{
Address: "10.10.0.10:10000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
client.experimentalChannel = true
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
ExperimentalChannel: true,
client: client,
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func TestLoadMixedRoutes(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
experimentalChannel bool
}{
{
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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by unsupported listener.Protocol",
paths: []string{"services.yml", "mixed/with_bad_listener_protocol.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by unsupported listener.Route.Kind",
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
},
paths: []string{"services.yml", "mixed/with_bad_listener_route_kind.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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty caused by listener.Protocol does not support listener.Route.Kind",
paths: []string{"services.yml", "mixed/with_incompatible_protocol_and_route_kind.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Mixed routes",
paths: []string{"services.yml", "mixed/simple.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
"websecure": {Address: ":9443"},
"tcp": {Address: ":9000"},
"tls-1": {Address: ":10000"},
"tls-2": {Address: ":11000"},
},
experimentalChannel: 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{
"default-tcp-app-1-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-1-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"default-tcp-app-1-my-gateway-tls-1": {
EntryPoints: []string{"tls-1"},
Service: "default-tcp-app-1-my-gateway-tls-1-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
"default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1": {
EntryPoints: []string{"tls-2"},
Service: "default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
Rule: "HostSNI(`pass.tls.foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-1-my-gateway-tls-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tls-app-1-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-web-0-a431b128267aabc954fd": {
EntryPoints: []string{"web"},
Service: "default-http-app-1-my-gateway-web-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
},
"default-http-app-1-my-gateway-websecure-0-a431b128267aabc954fd": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-1-my-gateway-websecure-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-1-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Empty caused by mixed routes with multiple listeners using same hostname, port and protocol",
paths: []string{"services.yml", "mixed/with_multiple_listeners_using_same_hostname_port_protocol.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
"tcp": {Address: ":9000"},
"tls": {Address: ":9001"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Mixed routes with Same namespace selector",
paths: []string{"services.yml", "mixed/with_namespace_same.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
"websecure": {Address: ":9443"},
"tcp": {Address: ":9000"},
"tls-1": {Address: ":10000"},
"tls-2": {Address: ":11000"},
},
experimentalChannel: 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{
"default-tcp-app-default-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-default-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"default-tcp-app-default-my-gateway-tls-1": {
EntryPoints: []string{"tls-1"},
Service: "default-tcp-app-default-my-gateway-tls-1-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": {
EntryPoints: []string{"tls-2"},
Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
Rule: "HostSNI(`pass.tls.foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-default-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-default-my-gateway-tls-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-default-my-gateway-web-0-a431b128267aabc954fd": {
EntryPoints: []string{"web"},
Service: "default-http-app-default-my-gateway-web-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
},
"default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-default-my-gateway-websecure-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-default-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-default-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Mixed routes with All namespace selector",
paths: []string{"services.yml", "mixed/with_namespace_all.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
"websecure": {Address: ":9443"},
"tcp": {Address: ":9000"},
"tls-1": {Address: ":10000"},
"tls-2": {Address: ":11000"},
},
experimentalChannel: 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{
"default-tcp-app-default-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-default-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"default-tcp-app-default-my-gateway-tls-1": {
EntryPoints: []string{"tls-1"},
Service: "default-tcp-app-default-my-gateway-tls-1-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1": {
EntryPoints: []string{"tls-2"},
Service: "default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
Rule: "HostSNI(`pass.tls.foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
"bar-tcp-app-bar-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "bar-tcp-app-bar-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"bar-tcp-app-bar-my-gateway-tls-1": {
EntryPoints: []string{"tls-1"},
Service: "bar-tcp-app-bar-my-gateway-tls-1-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-default-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-default-my-gateway-tls-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tls-app-default-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
"bar-whoamitcp-bar-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.13:9000",
},
{
Address: "10.10.0.14:9000",
},
},
},
},
"bar-tcp-app-bar-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-tcp-app-bar-my-gateway-tls-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-default-my-gateway-web-0-a431b128267aabc954fd": {
EntryPoints: []string{"web"},
Service: "default-http-app-default-my-gateway-web-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
},
"default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-default-my-gateway-websecure-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
"bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd": {
EntryPoints: []string{"web"},
Service: "bar-http-app-bar-my-gateway-web-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
},
"bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd": {
EntryPoints: []string{"websecure"},
Service: "bar-http-app-bar-my-gateway-websecure-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-default-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-default-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"bar-whoami-bar-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.11:80",
},
{
URL: "http://10.10.0.12:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"bar-http-app-bar-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "bar-whoami-bar-80",
Weight: ptr.To(1),
},
},
},
},
"bar-http-app-bar-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "bar-whoami-bar-80",
Weight: ptr.To(1),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Mixed routes with Selector Route Binding",
paths: []string{"services.yml", "mixed/with_namespace_selector.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
"websecure": {Address: ":9443"},
"tcp": {Address: ":9000"},
"tls-1": {Address: ":10000"},
"tls-2": {Address: ":11000"},
},
experimentalChannel: 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{
"bar-tcp-app-bar-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "bar-tcp-app-bar-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"bar-tcp-app-bar-my-gateway-tls-1": {
EntryPoints: []string{"tls-1"},
Service: "bar-tcp-app-bar-my-gateway-tls-1-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
"bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1": {
EntryPoints: []string{"tls-2"},
Service: "bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0",
Rule: "HostSNI(`pass.tls.foo.example.com`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{
Passthrough: true,
},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"bar-whoamitcp-bar-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.13:9000",
},
{
Address: "10.10.0.14:9000",
},
},
},
},
"bar-tcp-app-bar-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-tcp-app-bar-my-gateway-tls-1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
"bar-tls-app-bar-my-gateway-tls-2-59130f7db6718b7700c1-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "bar-whoamitcp-bar-9000",
Weight: ptr.To(1),
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"bar-http-app-bar-my-gateway-web-0-a431b128267aabc954fd": {
EntryPoints: []string{"web"},
Service: "bar-http-app-bar-my-gateway-web-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
},
"bar-http-app-bar-my-gateway-websecure-0-a431b128267aabc954fd": {
EntryPoints: []string{"websecure"},
Service: "bar-http-app-bar-my-gateway-websecure-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"bar-whoami-bar-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.11:80",
},
{
URL: "http://10.10.0.12:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"bar-http-app-bar-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "bar-whoami-bar-80",
Weight: ptr.To(1),
},
},
},
},
"bar-http-app-bar-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "bar-whoami-bar-80",
Weight: ptr.To(1),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Mixed routes with core group",
paths: []string{"services.yml", "mixed/with_core_group.yml"},
entryPoints: map[string]Entrypoint{
"web": {Address: ":9080"},
"websecure": {Address: ":9443"},
"tcp": {Address: ":9000"},
"tls": {Address: ":10000"},
},
experimentalChannel: 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{
"default-tcp-app-default-my-gateway-tcp": {
EntryPoints: []string{"tcp"},
Service: "default-tcp-app-default-my-gateway-tcp-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
},
"default-tcp-app-default-my-gateway-tls": {
EntryPoints: []string{"tls"},
Service: "default-tcp-app-default-my-gateway-tls-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-default-my-gateway-tcp-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-tcp-app-default-my-gateway-tls-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{
{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
},
},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-default-my-gateway-web-0-a431b128267aabc954fd": {
EntryPoints: []string{"web"},
Service: "default-http-app-default-my-gateway-web-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
},
"default-http-app-default-my-gateway-websecure-0-a431b128267aabc954fd": {
EntryPoints: []string{"websecure"},
Service: "default-http-app-default-my-gateway-websecure-0-wrr",
Rule: "PathPrefix(`/`)",
Priority: 2,
RuleSyntax: "v3",
TLS: &dynamic.RouterTLSConfig{},
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-default-my-gateway-web-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-http-app-default-my-gateway-websecure-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: ptr.To(1),
},
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: ptr.To(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
client.experimentalChannel = test.experimentalChannel
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
ExperimentalChannel: test.experimentalChannel,
client: client,
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func TestLoadRoutesWithReferenceGrants(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
entryPoints map[string]Entrypoint
experimentalChannel bool
}{
{
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{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because ReferenceGrant for Secret is missing",
paths: []string{"services.yml", "referencegrant/for_secret_missing.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because ReferenceGrant spec.from does not match secret",
paths: []string{"services.yml", "referencegrant/for_secret_not_matching_from.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because ReferenceGrant spec.to does not match secret",
paths: []string{"services.yml", "referencegrant/for_secret_not_matching_to.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "For Secret",
paths: []string{"services.yml", "referencegrant/for_secret.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
experimentalChannel: 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{
"default-tcp-app-1-my-gateway-tls": {
EntryPoints: []string{"tls"},
Service: "default-tcp-app-1-my-gateway-tls-wrr-0",
Rule: "HostSNI(`*`)",
RuleSyntax: "v3",
TLS: &dynamic.RouterTCPTLSConfig{},
},
},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{
"default-tcp-app-1-my-gateway-tls-wrr-0": {
Weighted: &dynamic.TCPWeightedRoundRobin{
Services: []dynamic.TCPWRRService{{
Name: "default-whoamitcp-9000",
Weight: ptr.To(1),
}},
},
},
"default-whoamitcp-9000": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "10.10.0.9:9000",
},
{
Address: "10.10.0.10:9000",
},
},
},
},
},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{
Certificates: []*tls.CertAndStores{
{
Certificate: tls.Certificate{
CertFile: types.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
KeyFile: types.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
},
},
},
},
},
},
{
desc: "Empty because ReferenceGrant for Service is missing",
paths: []string{"services.yml", "referencegrant/for_secret_missing.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because ReferenceGrant spec.from does not match service",
paths: []string{"services.yml", "referencegrant/for_service_not_matching_from.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Empty because ReferenceGrant spec.to does not match service",
paths: []string{"services.yml", "referencegrant/for_service_not_matching_to.yml"},
entryPoints: map[string]Entrypoint{
"tls": {Address: ":9000"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "For Service",
paths: []string{"services.yml", "referencegrant/for_service.yml"},
entryPoints: map[string]Entrypoint{
"http": {Address: ":80"},
},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-http-app-1-my-gateway-http-0-d40286ed9f4652ca2108": {
EntryPoints: []string{"http"},
Rule: "Host(`foo.example.com`) && PathPrefix(`/`)",
Service: "default-http-app-1-my-gateway-http-0-wrr",
RuleSyntax: "v3",
Priority: 17,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-http-0-wrr": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-bar-80",
Weight: ptr.To(1),
Status: ptr.To(500),
},
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
if test.expected == nil {
return
}
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
client.experimentalChannel = test.experimentalChannel
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
EntryPoints: test.entryPoints,
ExperimentalChannel: test.experimentalChannel,
client: client,
}
conf := p.loadConfigurationFromGateways(context.Background())
assert.Equal(t, test.expected, conf)
})
}
}
func Test_matchListener(t *testing.T) {
testCases := []struct {
desc string
gwListener gatewayListener
parentRef gatev1.ParentReference
routeNamespace string
wantMatch bool
}{
{
desc: "Unsupported group",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
parentRef: gatev1.ParentReference{
Group: ptr.To(gatev1.Group("foo")),
},
wantMatch: false,
},
{
desc: "Unsupported kind",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
parentRef: gatev1.ParentReference{
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("foo")),
},
wantMatch: false,
},
{
desc: "Namespace does not match the listener",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
parentRef: gatev1.ParentReference{
Namespace: ptr.To(gatev1.Namespace("foo")),
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("Gateway")),
},
wantMatch: false,
},
{
desc: "Route namespace defaulting does not match the listener",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
routeNamespace: "foo",
parentRef: gatev1.ParentReference{
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("Gateway")),
},
wantMatch: false,
},
{
desc: "Name does not match the listener",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
parentRef: gatev1.ParentReference{
Namespace: ptr.To(gatev1.Namespace("default")),
Name: "foo",
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("Gateway")),
},
wantMatch: false,
},
{
desc: "SectionName does not match a listener",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
parentRef: gatev1.ParentReference{
SectionName: ptr.To(gatev1.SectionName("bar")),
Name: "gateway",
Namespace: ptr.To(gatev1.Namespace("default")),
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("Gateway")),
},
wantMatch: false,
},
{
desc: "Match",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
parentRef: gatev1.ParentReference{
SectionName: ptr.To(gatev1.SectionName("foo")),
Name: "gateway",
Namespace: ptr.To(gatev1.Namespace("default")),
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("Gateway")),
},
wantMatch: true,
},
{
desc: "Match with route namespace defaulting",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
},
routeNamespace: "default",
parentRef: gatev1.ParentReference{
SectionName: ptr.To(gatev1.SectionName("foo")),
Name: "gateway",
Group: ptr.To(gatev1.Group(gatev1.GroupName)),
Kind: ptr.To(gatev1.Kind("Gateway")),
},
wantMatch: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gotMatch := matchListener(test.gwListener, test.routeNamespace, test.parentRef)
assert.Equal(t, test.wantMatch, gotMatch)
})
}
}
func Test_allowRoute(t *testing.T) {
testCases := []struct {
desc string
gwListener gatewayListener
routeNamespace string
routeKind string
wantAllow bool
}{
{
desc: "Not allowed Kind",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
AllowedRouteKinds: []string{
"foo",
"bar",
},
},
routeKind: "baz",
wantAllow: false,
},
{
desc: "Allowed Kind",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
AllowedRouteKinds: []string{
"foo",
"bar",
},
AllowedNamespaces: []string{
corev1.NamespaceAll,
},
},
routeKind: "bar",
wantAllow: true,
},
{
desc: "Not allowed namespace",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
AllowedRouteKinds: []string{
"foo",
},
AllowedNamespaces: []string{
"foo",
"bar",
},
},
routeKind: "foo",
routeNamespace: "baz",
wantAllow: false,
},
{
desc: "Allowed namespace",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
AllowedRouteKinds: []string{
"foo",
},
AllowedNamespaces: []string{
"foo",
"bar",
},
},
routeKind: "foo",
routeNamespace: "foo",
wantAllow: true,
},
{
desc: "Allowed namespace",
gwListener: gatewayListener{
Name: "foo",
GWName: "gateway",
GWNamespace: "default",
AllowedRouteKinds: []string{
"foo",
},
AllowedNamespaces: []string{
corev1.NamespaceAll,
"bar",
},
},
routeKind: "foo",
routeNamespace: "foo",
wantAllow: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
gotAllow := allowRoute(test.gwListener, test.routeNamespace, test.routeKind)
assert.Equal(t, test.wantAllow, gotAllow)
})
}
}
func Test_findMatchingHostnames(t *testing.T) {
testCases := []struct {
desc string
listenerHostname *gatev1.Hostname
routeHostnames []gatev1.Hostname
want []gatev1.Hostname
wantOk bool
}{
{
desc: "Empty",
wantOk: true,
},
{
desc: "Only listener hostname",
listenerHostname: ptr.To(gatev1.Hostname("foo.com")),
want: []gatev1.Hostname{"foo.com"},
wantOk: true,
},
{
desc: "Only Route hostname",
routeHostnames: []gatev1.Hostname{"foo.com"},
want: []gatev1.Hostname{"foo.com"},
wantOk: true,
},
{
desc: "Matching hostname",
listenerHostname: ptr.To(gatev1.Hostname("foo.com")),
routeHostnames: []gatev1.Hostname{"foo.com"},
want: []gatev1.Hostname{"foo.com"},
wantOk: true,
},
{
desc: "Matching hostname with wildcard",
listenerHostname: ptr.To(gatev1.Hostname("*.foo.com")),
routeHostnames: []gatev1.Hostname{"*.foo.com"},
want: []gatev1.Hostname{"*.foo.com"},
wantOk: true,
},
{
desc: "Matching subdomain with listener wildcard",
listenerHostname: ptr.To(gatev1.Hostname("*.foo.com")),
routeHostnames: []gatev1.Hostname{"bar.foo.com"},
want: []gatev1.Hostname{"bar.foo.com"},
wantOk: true,
},
{
desc: "Matching subsubdomain with listener wildcard",
listenerHostname: ptr.To(gatev1.Hostname("*.foo.com")),
routeHostnames: []gatev1.Hostname{"baz.bar.foo.com"},
want: []gatev1.Hostname{"baz.bar.foo.com"},
wantOk: true,
},
{
desc: "Matching subdomain with route hostname wildcard",
listenerHostname: ptr.To(gatev1.Hostname("bar.foo.com")),
routeHostnames: []gatev1.Hostname{"*.foo.com"},
want: []gatev1.Hostname{"bar.foo.com"},
wantOk: true,
},
{
desc: "Matching subsubdomain with route hostname wildcard",
listenerHostname: ptr.To(gatev1.Hostname("baz.bar.foo.com")),
routeHostnames: []gatev1.Hostname{"*.foo.com"},
want: []gatev1.Hostname{"baz.bar.foo.com"},
wantOk: true,
},
{
desc: "Non matching root domain with listener wildcard",
listenerHostname: ptr.To(gatev1.Hostname("*.foo.com")),
routeHostnames: []gatev1.Hostname{"foo.com"},
},
{
desc: "Non matching root domain with route hostname wildcard",
listenerHostname: ptr.To(gatev1.Hostname("foo.com")),
routeHostnames: []gatev1.Hostname{"*.foo.com"},
},
{
desc: "Multiple route hostnames with one matching route hostname",
listenerHostname: ptr.To(gatev1.Hostname("*.foo.com")),
routeHostnames: []gatev1.Hostname{"bar.com", "test.foo.com", "test.buz.com"},
want: []gatev1.Hostname{"test.foo.com"},
wantOk: true,
},
{
desc: "Multiple route hostnames with non matching route hostname",
listenerHostname: ptr.To(gatev1.Hostname("*.fuz.com")),
routeHostnames: []gatev1.Hostname{"bar.com", "test.foo.com", "test.buz.com"},
},
{
desc: "Multiple route hostnames with multiple matching route hostnames",
listenerHostname: ptr.To(gatev1.Hostname("*.foo.com")),
routeHostnames: []gatev1.Hostname{"toto.foo.com", "test.foo.com", "test.buz.com"},
want: []gatev1.Hostname{"toto.foo.com", "test.foo.com"},
wantOk: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got, ok := findMatchingHostnames(test.listenerHostname, test.routeHostnames)
assert.Equal(t, test.wantOk, ok)
assert.Equal(t, test.want, got)
})
}
}
func Test_allowedRouteKinds(t *testing.T) {
testCases := []struct {
desc string
listener gatev1.Listener
supportedRouteKinds []gatev1.RouteGroupKind
wantKinds []gatev1.RouteGroupKind
wantErr bool
}{
{
desc: "Empty",
},
{
desc: "Empty AllowedRoutes",
supportedRouteKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
wantKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
},
{
desc: "AllowedRoutes with unsupported Group",
listener: gatev1.Listener{
AllowedRoutes: &gatev1.AllowedRoutes{
Kinds: []gatev1.RouteGroupKind{{
Kind: kindTLSRoute, Group: ptr.To(gatev1.Group("foo")),
}},
},
},
supportedRouteKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
wantErr: true,
},
{
desc: "AllowedRoutes with nil Group",
listener: gatev1.Listener{
AllowedRoutes: &gatev1.AllowedRoutes{
Kinds: []gatev1.RouteGroupKind{{
Kind: kindTLSRoute, Group: nil,
}},
},
},
supportedRouteKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
wantErr: true,
},
{
desc: "AllowedRoutes with unsupported Kind",
listener: gatev1.Listener{
AllowedRoutes: &gatev1.AllowedRoutes{
Kinds: []gatev1.RouteGroupKind{{
Kind: "foo", Group: ptr.To(gatev1.Group(gatev1.GroupName)),
}},
},
},
supportedRouteKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
wantErr: true,
},
{
desc: "Supported AllowedRoutes",
listener: gatev1.Listener{
AllowedRoutes: &gatev1.AllowedRoutes{
Kinds: []gatev1.RouteGroupKind{{
Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName)),
}},
},
},
supportedRouteKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
wantKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
},
{
desc: "Supported AllowedRoutes with duplicates",
listener: gatev1.Listener{
AllowedRoutes: &gatev1.AllowedRoutes{
Kinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
{Kind: kindTCPRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
{Kind: kindTCPRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
},
},
supportedRouteKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
{Kind: kindTCPRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
wantKinds: []gatev1.RouteGroupKind{
{Kind: kindTLSRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
{Kind: kindTCPRoute, Group: ptr.To(gatev1.Group(gatev1.GroupName))},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got, conditions := allowedRouteKinds(&gatev1.Gateway{}, test.listener, test.supportedRouteKinds)
if test.wantErr {
require.NotEmpty(t, conditions, "no conditions")
return
}
require.Empty(t, conditions)
assert.Equal(t, test.wantKinds, got)
})
}
}
func Test_makeListenerKey(t *testing.T) {
testCases := []struct {
desc string
listener gatev1.Listener
expectedKey string
}{
{
desc: "empty",
expectedKey: "||0",
},
{
desc: "listener with port, protocol and hostname",
listener: gatev1.Listener{
Port: 443,
Protocol: gatev1.HTTPSProtocolType,
Hostname: ptr.To(gatev1.Hostname("www.example.com")),
},
expectedKey: "HTTPS|www.example.com|443",
},
{
desc: "listener with port, protocol and nil hostname",
listener: gatev1.Listener{
Port: 443,
Protocol: gatev1.HTTPSProtocolType,
},
expectedKey: "HTTPS||443",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.expectedKey, makeListenerKey(test.listener))
})
}
}
func Test_referenceGrantMatchesFrom(t *testing.T) {
testCases := []struct {
desc string
referenceGrant gatev1beta1.ReferenceGrant
group string
kind string
namespace string
expectedResult bool
}{
{
desc: "matches",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
From: []gatev1beta1.ReferenceGrantFrom{
{
Group: "correct-group",
Kind: "correct-kind",
Namespace: "correct-namespace",
},
},
},
},
group: "correct-group",
kind: "correct-kind",
namespace: "correct-namespace",
expectedResult: true,
},
{
desc: "empty group matches core",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
From: []gatev1beta1.ReferenceGrantFrom{
{
Group: "",
Kind: "correct-kind",
Namespace: "correct-namespace",
},
},
},
},
group: "core",
kind: "correct-kind",
namespace: "correct-namespace",
expectedResult: true,
},
{
desc: "wrong group",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
From: []gatev1beta1.ReferenceGrantFrom{
{
Group: "wrong-group",
Kind: "correct-kind",
Namespace: "correct-namespace",
},
},
},
},
group: "correct-group",
kind: "correct-kind",
namespace: "correct-namespace",
expectedResult: false,
},
{
desc: "wrong kind",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
From: []gatev1beta1.ReferenceGrantFrom{
{
Group: "correct-group",
Kind: "wrong-kind",
Namespace: "correct-namespace",
},
},
},
},
group: "correct-group",
kind: "correct-kind",
namespace: "correct-namespace",
expectedResult: false,
},
{
desc: "wrong namespace",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
From: []gatev1beta1.ReferenceGrantFrom{
{
Group: "correct-group",
Kind: "correct-kind",
Namespace: "wrong-namespace",
},
},
},
},
group: "correct-group",
kind: "correct-kind",
namespace: "correct-namespace",
expectedResult: false,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.expectedResult, referenceGrantMatchesFrom(&test.referenceGrant, test.group, test.kind, test.namespace))
})
}
}
func Test_referenceGrantMatchesTo(t *testing.T) {
testCases := []struct {
desc string
referenceGrant gatev1beta1.ReferenceGrant
group string
kind string
name string
expectedResult bool
}{
{
desc: "matches",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
To: []gatev1beta1.ReferenceGrantTo{
{
Group: "correct-group",
Kind: "correct-kind",
Name: ptr.To(gatev1.ObjectName("correct-name")),
},
},
},
},
group: "correct-group",
kind: "correct-kind",
name: "correct-name",
expectedResult: true,
},
{
desc: "matches without name",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
To: []gatev1beta1.ReferenceGrantTo{
{
Group: "correct-group",
Kind: "correct-kind",
Name: nil,
},
},
},
},
group: "correct-group",
kind: "correct-kind",
name: "some-name",
expectedResult: true,
},
{
desc: "empty group matches core",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
To: []gatev1beta1.ReferenceGrantTo{
{
Group: "",
Kind: "correct-kind",
Name: ptr.To(gatev1.ObjectName("correct-name")),
},
},
},
},
group: "core",
kind: "correct-kind",
name: "correct-name",
expectedResult: true,
},
{
desc: "wrong group",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
To: []gatev1beta1.ReferenceGrantTo{
{
Group: "wrong-group",
Kind: "correct-kind",
Name: ptr.To(gatev1.ObjectName("correct-name")),
},
},
},
},
group: "correct-group",
kind: "correct-kind",
name: "correct-namespace",
expectedResult: false,
},
{
desc: "wrong kind",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
To: []gatev1beta1.ReferenceGrantTo{
{
Group: "correct-group",
Kind: "wrong-kind",
Name: ptr.To(gatev1.ObjectName("correct-name")),
},
},
},
},
group: "correct-group",
kind: "correct-kind",
name: "correct-name",
expectedResult: false,
},
{
desc: "wrong name",
referenceGrant: gatev1beta1.ReferenceGrant{
Spec: gatev1beta1.ReferenceGrantSpec{
To: []gatev1beta1.ReferenceGrantTo{
{
Group: "correct-group",
Kind: "correct-kind",
Name: ptr.To(gatev1.ObjectName("wrong-name")),
},
},
},
},
group: "correct-group",
kind: "correct-kind",
name: "correct-name",
expectedResult: false,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.expectedResult, referenceGrantMatchesTo(&test.referenceGrant, test.group, test.kind, test.name))
})
}
}
func Test_gatewayAddresses(t *testing.T) {
testCases := []struct {
desc string
statusAddress *StatusAddress
paths []string
wantErr require.ErrorAssertionFunc
want []gatev1.GatewayStatusAddress
}{
{
desc: "nothing",
wantErr: require.NoError,
},
{
desc: "empty configuration",
statusAddress: &StatusAddress{},
wantErr: require.Error,
},
{
desc: "IP address",
statusAddress: &StatusAddress{
IP: "1.2.3.4",
},
wantErr: require.NoError,
want: []gatev1.GatewayStatusAddress{
{
Type: ptr.To(gatev1.IPAddressType),
Value: "1.2.3.4",
},
},
},
{
desc: "hostname address",
statusAddress: &StatusAddress{
Hostname: "foo.bar",
},
wantErr: require.NoError,
want: []gatev1.GatewayStatusAddress{
{
Type: ptr.To(gatev1.HostnameAddressType),
Value: "foo.bar",
},
},
},
{
desc: "service",
statusAddress: &StatusAddress{
Service: ServiceRef{
Name: "status-address",
Namespace: "default",
},
},
paths: []string{"services.yml"},
wantErr: require.NoError,
want: []gatev1.GatewayStatusAddress{
{
Type: ptr.To(gatev1.HostnameAddressType),
Value: "foo.bar",
},
{
Type: ptr.To(gatev1.IPAddressType),
Value: "1.2.3.4",
},
},
},
{
desc: "missing service",
statusAddress: &StatusAddress{
Service: ServiceRef{
Name: "status-address2",
Namespace: "default",
},
},
wantErr: require.Error,
},
{
desc: "service without load-balancer status",
statusAddress: &StatusAddress{
Service: ServiceRef{
Name: "whoamitcp-bar",
Namespace: "bar",
},
},
paths: []string{"services.yml"},
wantErr: require.NoError,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
k8sObjects, gwObjects := readResources(t, test.paths)
kubeClient := kubefake.NewSimpleClientset(k8sObjects...)
gwClient := newGatewaySimpleClientSet(t, gwObjects...)
client := newClientImpl(kubeClient, gwClient)
eventCh, err := client.WatchAll(nil, make(chan struct{}))
require.NoError(t, err)
if len(k8sObjects) > 0 || len(gwObjects) > 0 {
// just wait for the first event
<-eventCh
}
p := Provider{
StatusAddress: test.statusAddress,
client: client,
}
got, err := p.gatewayAddresses()
test.wantErr(t, err)
assert.Equal(t, test.want, got)
})
}
}
func Test_upsertRouteConditionResolvedRefs(t *testing.T) {
testCases := []struct {
desc string
conditions []metav1.Condition
condition metav1.Condition
wantConditions []metav1.Condition
}{
{
desc: "True to False",
conditions: []metav1.Condition{
{
Type: "foo",
Status: "bar",
Reason: "baz",
Message: "foobarbaz",
},
{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionTrue,
Reason: "foo",
Message: "foo",
},
},
condition: metav1.Condition{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "bar",
Message: "bar",
},
wantConditions: []metav1.Condition{
{
Type: "foo",
Status: "bar",
Reason: "baz",
Message: "foobarbaz",
},
{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "bar",
Message: "bar",
},
},
},
{
desc: "False to False",
conditions: []metav1.Condition{
{
Type: "foo",
Status: "bar",
Reason: "baz",
Message: "foobarbaz",
},
{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "foo",
Message: "foo",
},
},
condition: metav1.Condition{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "bar",
Message: "bar",
},
wantConditions: []metav1.Condition{
{
Type: "foo",
Status: "bar",
Reason: "baz",
Message: "foobarbaz",
},
{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "bar",
Message: "bar",
},
},
},
{
desc: "False to True: no upsert",
conditions: []metav1.Condition{
{
Type: "foo",
Status: "bar",
Reason: "baz",
Message: "foobarbaz",
},
{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "foo",
Message: "foo",
},
},
condition: metav1.Condition{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionTrue,
Reason: "bar",
Message: "bar",
},
wantConditions: []metav1.Condition{
{
Type: "foo",
Status: "bar",
Reason: "baz",
Message: "foobarbaz",
},
{
Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: "foo",
Message: "foo",
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := upsertRouteConditionResolvedRefs(test.conditions, test.condition)
assert.Equal(t, test.wantConditions, got)
})
}
}
// We cannot use the gateway-api fake.NewSimpleClientset due to Gateway being pluralized as "gatewaies" instead of "gateways".
func newGatewaySimpleClientSet(t *testing.T, objects ...runtime.Object) *gatefake.Clientset {
t.Helper()
client := gatefake.NewSimpleClientset(objects...)
for _, object := range objects {
gateway, ok := object.(*gatev1.Gateway)
if !ok {
continue
}
_, err := client.GatewayV1().Gateways(gateway.Namespace).Create(context.Background(), gateway, metav1.CreateOptions{})
require.NoError(t, err)
}
return client
}
func readResources(t *testing.T, paths []string) ([]runtime.Object, []runtime.Object) {
t.Helper()
var k8sObjects []runtime.Object
var gwObjects []runtime.Object
for _, path := range paths {
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
if err != nil {
panic(err)
}
objects := k8s.MustParseYaml(yamlContent)
for _, obj := range objects {
switch obj.GetObjectKind().GroupVersionKind().Group {
case "gateway.networking.k8s.io":
gwObjects = append(gwObjects, obj)
default:
k8sObjects = append(k8sObjects, obj)
}
}
}
return k8sObjects, gwObjects
}