Add Kubernetes Gateway Provider
Co-authored-by: Jean-Baptiste Doumenjou <925513+jbdoumenjou@users.noreply.github.com>
This commit is contained in:
parent
ea418aa7d8
commit
c21597c593
56 changed files with 7239 additions and 156 deletions
990
pkg/provider/kubernetes/gateway/kubernetes_test.go
Normal file
990
pkg/provider/kubernetes/gateway/kubernetes_test.go
Normal file
|
@ -0,0 +1,990 @@
|
|||
package gateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/provider"
|
||||
"github.com/traefik/traefik/v2/pkg/tls"
|
||||
"sigs.k8s.io/service-apis/apis/v1alpha1"
|
||||
)
|
||||
|
||||
var _ provider.Provider = (*Provider)(nil)
|
||||
|
||||
func Bool(v bool) *bool { return &v }
|
||||
|
||||
func TestLoadHTTPRoutes(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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Empty because missing entry point",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Empty because no http route defined",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Empty caused by missing GatewayClass",
|
||||
entryPoints: map[string]Entrypoint{"web": {
|
||||
Address: ":80",
|
||||
}},
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Empty caused by unknown GatewayClass controller name",
|
||||
entryPoints: map[string]Entrypoint{"web": {
|
||||
Address: ":80",
|
||||
}},
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Empty caused by multiport service with wrong TargetPort",
|
||||
entryPoints: map[string]Entrypoint{"web": {
|
||||
Address: ":80",
|
||||
}},
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Empty caused by HTTPS without TLS",
|
||||
entryPoints: map[string]Entrypoint{"websecure": {
|
||||
Address: ":443",
|
||||
}},
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, with foo entrypoint",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-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: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute with protocol HTTPS",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-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: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: []*tls.CertAndStores{
|
||||
{
|
||||
Certificate: tls.Certificate{
|
||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, with multiple hosts",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-75dd1ad561e42725558a": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-web-75dd1ad561e42725558a-wrr",
|
||||
Rule: "Host(`foo.com`, `bar.com`) && PathPrefix(`/`)",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-75dd1ad561e42725558a-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: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One HTTPRoute with two different rules",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||
},
|
||||
"default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && Path(`/bir`)",
|
||||
Service: "default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a-wrr",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-http-app-1-my-gateway-web-d737b4933fa88e68ab8a-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami2-8080",
|
||||
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: Bool(true),
|
||||
},
|
||||
},
|
||||
"default-whoami2-8080": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "One HTTPRoute with one rule two targets",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"web"},
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
{
|
||||
Name: "default-whoami2-8080",
|
||||
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: Bool(true),
|
||||
},
|
||||
},
|
||||
"default-whoami2-8080": {
|
||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||
Servers: []dynamic.Server{
|
||||
{
|
||||
URL: "http://10.10.0.3:8080",
|
||||
},
|
||||
{
|
||||
URL: "http://10.10.0.4:8080",
|
||||
},
|
||||
},
|
||||
PassHostHeader: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Two Gateways and one HTTPRoute",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
},
|
||||
"default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
Service: "default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-http-web-1c0cf64bde37d9d0df06-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-http-app-1-my-gateway-https-websecure-1c0cf64bde37d9d0df06-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: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: []*tls.CertAndStores{
|
||||
{
|
||||
Certificate: tls.Certificate{
|
||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Gateway with two listeners and one HTTPRoute",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
},
|
||||
"default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06": {
|
||||
EntryPoints: []string{"websecure"},
|
||||
Service: "default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`)",
|
||||
TLS: &dynamic.RouterTLSConfig{},
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-1c0cf64bde37d9d0df06-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-http-app-1-my-gateway-websecure-1c0cf64bde37d9d0df06-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: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: []*tls.CertAndStores{
|
||||
{
|
||||
Certificate: tls.Certificate{
|
||||
CertFile: tls.FileOrContent("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----"),
|
||||
KeyFile: tls.FileOrContent("-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Simple HTTPRoute, with several rules",
|
||||
paths: []string{"services.yml", "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{},
|
||||
Services: map[string]*dynamic.TCPService{},
|
||||
},
|
||||
HTTP: &dynamic.HTTPConfiguration{
|
||||
Routers: map[string]*dynamic.Router{
|
||||
"default-http-app-1-my-gateway-web-6211a6376ce8f78494a8": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-web-6211a6376ce8f78494a8-wrr",
|
||||
Rule: "Host(`foo.com`) && PathPrefix(`/bar`) && Headers(`my-header2`,`bar`) && Headers(`my-header`,`foo`)",
|
||||
},
|
||||
"default-http-app-1-my-gateway-web-fe80e69a38713941ea22": {
|
||||
EntryPoints: []string{"web"},
|
||||
Service: "default-http-app-1-my-gateway-web-fe80e69a38713941ea22-wrr",
|
||||
Rule: "Host(`foo.com`) && Path(`/bar`) && Headers(`my-header`,`bar`)",
|
||||
},
|
||||
},
|
||||
Middlewares: map[string]*dynamic.Middleware{},
|
||||
Services: map[string]*dynamic.Service{
|
||||
"default-http-app-1-my-gateway-web-6211a6376ce8f78494a8-wrr": {
|
||||
Weighted: &dynamic.WeightedRoundRobin{
|
||||
Services: []dynamic.WRRService{
|
||||
{
|
||||
Name: "default-whoami-80",
|
||||
Weight: func(i int) *int { return &i }(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"default-http-app-1-my-gateway-web-fe80e69a38713941ea22-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: Bool(true),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TLS: &dynamic.TLSConfiguration{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if test.expected == nil {
|
||||
return
|
||||
}
|
||||
|
||||
p := Provider{EntryPoints: test.entryPoints}
|
||||
conf := p.loadConfigurationFromGateway(context.Background(), newClientMock(test.paths...))
|
||||
assert.Equal(t, test.expected, conf)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostRule(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
routeSpec v1alpha1.HTTPRouteSpec
|
||||
expectedRule string
|
||||
}{
|
||||
{
|
||||
desc: "Empty rule and matches",
|
||||
expectedRule: "",
|
||||
},
|
||||
{
|
||||
desc: "One Host",
|
||||
routeSpec: v1alpha1.HTTPRouteSpec{
|
||||
Hostnames: []v1alpha1.Hostname{
|
||||
"Foo",
|
||||
},
|
||||
},
|
||||
expectedRule: "Host(`Foo`)",
|
||||
},
|
||||
{
|
||||
desc: "Multiple Hosts",
|
||||
routeSpec: v1alpha1.HTTPRouteSpec{
|
||||
Hostnames: []v1alpha1.Hostname{
|
||||
"Foo",
|
||||
"Bar",
|
||||
"Bir",
|
||||
},
|
||||
},
|
||||
expectedRule: "Host(`Foo`, `Bar`, `Bir`)",
|
||||
},
|
||||
{
|
||||
desc: "Multiple Hosts with empty one",
|
||||
routeSpec: v1alpha1.HTTPRouteSpec{
|
||||
Hostnames: []v1alpha1.Hostname{
|
||||
"Foo",
|
||||
"",
|
||||
"Bir",
|
||||
},
|
||||
},
|
||||
expectedRule: "Host(`Foo`, `Bir`)",
|
||||
},
|
||||
{
|
||||
desc: "Multiple empty hosts",
|
||||
routeSpec: v1alpha1.HTTPRouteSpec{
|
||||
Hostnames: []v1alpha1.Hostname{
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
},
|
||||
expectedRule: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, test.expectedRule, hostRule(test.routeSpec))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractRule(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
routeRule v1alpha1.HTTPRouteRule
|
||||
hostRule string
|
||||
expectedRule string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
desc: "Empty rule and matches",
|
||||
expectedRule: "PathPrefix(`/`)",
|
||||
},
|
||||
{
|
||||
desc: "One Host rule without matches",
|
||||
hostRule: "Host(`foo.com`)",
|
||||
expectedRule: "Host(`foo.com`) && PathPrefix(`/`)",
|
||||
},
|
||||
{
|
||||
desc: "One Path in matches",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedRule: "Path(`/foo/`)",
|
||||
},
|
||||
{
|
||||
desc: "One Path in matches and another unknown",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: "unknown",
|
||||
Value: "/foo/",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
desc: "One Path in matches and another empty",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
},
|
||||
{},
|
||||
},
|
||||
},
|
||||
expectedRule: "Path(`/foo/`)",
|
||||
},
|
||||
{
|
||||
desc: "Path OR Header rules",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
},
|
||||
{
|
||||
Headers: &v1alpha1.HTTPHeaderMatch{
|
||||
Type: v1alpha1.HeaderMatchExact,
|
||||
Values: map[string]string{
|
||||
"my-header": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedRule: "Path(`/foo/`) || Headers(`my-header`,`foo`)",
|
||||
},
|
||||
{
|
||||
desc: "Path && Header rules",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
Headers: &v1alpha1.HTTPHeaderMatch{
|
||||
Type: v1alpha1.HeaderMatchExact,
|
||||
Values: map[string]string{
|
||||
"my-header": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedRule: "Path(`/foo/`) && Headers(`my-header`,`foo`)",
|
||||
},
|
||||
{
|
||||
desc: "Host && Path && Header rules",
|
||||
hostRule: "Host(`foo.com`)",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
Headers: &v1alpha1.HTTPHeaderMatch{
|
||||
Type: v1alpha1.HeaderMatchExact,
|
||||
Values: map[string]string{
|
||||
"my-header": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedRule: "Host(`foo.com`) && Path(`/foo/`) && Headers(`my-header`,`foo`)",
|
||||
},
|
||||
{
|
||||
desc: "Host && (Path || Header) rules",
|
||||
hostRule: "Host(`foo.com`)",
|
||||
routeRule: v1alpha1.HTTPRouteRule{
|
||||
Matches: []v1alpha1.HTTPRouteMatch{
|
||||
{
|
||||
Path: v1alpha1.HTTPPathMatch{
|
||||
Type: v1alpha1.PathMatchExact,
|
||||
Value: "/foo/",
|
||||
},
|
||||
},
|
||||
{
|
||||
Headers: &v1alpha1.HTTPHeaderMatch{
|
||||
Type: v1alpha1.HeaderMatchExact,
|
||||
Values: map[string]string{
|
||||
"my-header": "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedRule: "Host(`foo.com`) && (Path(`/foo/`) || Headers(`my-header`,`foo`))",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rule, err := extractRule(test.routeRule, test.hostRule)
|
||||
if test.expectedError {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.expectedRule, rule)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue