refactor: simplify template and use typed function.

This commit is contained in:
Fernandez Ludovic 2018-01-05 17:31:24 +01:00 committed by Traefiker
parent 750878d668
commit b1ea36793b
4 changed files with 790 additions and 170 deletions

View file

@ -890,91 +890,88 @@ func templatesKubernetesTmpl() (*asset, error) {
}
var _templatesKvTmpl = []byte(`[backends]
{{range $backend := List .Prefix "/backends/"}}
{{$backendName := Last $backend}}
{{range $backend := List .Prefix "/backends/" }}
{{ $backendName := Last $backend }}
{{$circuitBreaker := Get "" $backend "/circuitbreaker/expression"}}
{{with $circuitBreaker}}
[backends."{{$backendName}}".circuitBreaker]
expression = "{{$circuitBreaker}}"
{{ $circuitBreaker := getCircuitBreaker $backend }}
{{if $circuitBreaker }}
[backends."{{ $backendName }}".circuitBreaker]
expression = "{{ $circuitBreaker.Expression }}"
{{end}}
{{$loadBalancer := Get "" $backend "/loadbalancer/method"}}
{{with $loadBalancer}}
[backends."{{$backendName}}".loadBalancer]
method = "{{$loadBalancer}}"
sticky = {{ getSticky $backend }}
{{if hasStickinessLabel $backend}}
[backends."{{$backendName}}".loadBalancer.stickiness]
cookieName = "{{getStickinessCookieName $backend}}"
{{end}}
{{ $loadBalancer := getLoadBalancer $backend }}
{{if $loadBalancer }}
[backends."{{ $backendName }}".loadBalancer]
method = "{{ $loadBalancer.Method }}"
sticky = {{ $loadBalancer.Sticky }}
{{if $loadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
{{end}}
{{end}}
{{$maxConnAmt := Get "" $backend "/maxconn/amount"}}
{{$maxConnExtractorFunc := Get "" $backend "/maxconn/extractorfunc"}}
{{with $maxConnAmt}}
{{with $maxConnExtractorFunc}}
[backends."{{$backendName}}".maxConn]
amount = {{$maxConnAmt}}
extractorFunc = "{{$maxConnExtractorFunc}}"
{{end}}
{{ $maxConn := getMaxConn $backend }}
{{if $maxConn }}
[backends."{{ $backendName }}".maxConn]
extractorFunc = "{{ $maxConn.ExtractorFunc }}"
amount = {{ $maxConn.Amount }}
{{end}}
{{$healthCheck := Get "" $backend "/healthcheck/path"}}
{{with $healthCheck}}
[backends."{{$backendName}}".healthCheck]
path = "{{$healthCheck}}"
port = {{ Get "0" $backend "/healthcheck/port" }}
interval = "{{ Get "30s" $backend "/healthcheck/interval" }}"
{{ $healthCheck := getHealthCheck $backend }}
{{if $healthCheck }}
[backends.{{ $backendName }}.healthCheck]
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
{{end}}
{{range $server := ListServers $backend}}
[backends."{{$backendName}}".servers."{{Last $server}}"]
url = "{{Get "" $server "/url"}}"
weight = {{Get "0" $server "/weight"}}
{{range $serverName, $server := getServers $backend}}
[backends."{{ $backendName }}".servers."{{ $serverName }}"]
url = "{{ $server.URL }}"
weight = {{ $server.Weight }}
{{end}}
{{end}}
[frontends]
{{range $frontend := List .Prefix "/frontends/" }}
{{$frontendName := Last $frontend}}
{{ $frontendName := Last $frontend }}
[frontends."{{$frontendName}}"]
backend = "{{Get "" $frontend "/backend"}}"
priority = {{Get "0" $frontend "/priority"}}
passHostHeader = {{Get "true" $frontend "/passHostHeader"}}
passTLSCert = {{Get "false" $frontend "/passtlscert"}}
[frontends."{{ $frontendName }}"]
backend = "{{ getBackendName $frontend }}"
priority = {{ getPriority $frontend }}
passHostHeader = {{ getPassHostHeader $frontend }}
passTLSCert = {{ getPassTLSCert $frontend }}
{{$entryPoints := SplitGet $frontend "/entrypoints"}}
entryPoints = [{{range $entryPoints}}
entryPoints = [{{range getEntryPoints $frontend }}
"{{.}}",
{{end}}]
{{$whitelistSourceRange := SplitGet $frontend "/whitelistsourcerange"}}
whitelistSourceRange = [{{range $whitelistSourceRange}}
{{ $whitelistSourceRange := getWhitelistSourceRange $frontend }}
{{if $whitelistSourceRange }}
whitelistSourceRange = [{{range $whitelistSourceRange }}
"{{.}}",
{{end}}]
{{end}}
basicAuth = [{{range getBasicAuth $frontend }}
"{{.}}",
{{end}}]
{{$basicAuth := SplitGet $frontend "/basicauth"}}
basicAuth = [{{range $basicAuth}}
"{{.}}",
{{end}}]
{{$redirect := getRedirect $frontend }}
{{ if $redirect }}
[frontends."{{$frontendName}}".redirect]
{{ $redirect := getRedirect $frontend }}
{{if $redirect }}
[frontends."{{ $frontendName }}".redirect]
entryPoint = "{{ $redirect.EntryPoint }}"
regex = "{{ $redirect.Regex }}"
replacement = "{{ $redirect.Replacement }}"
{{end}}
{{ $errorPages := getErrorPages $frontend }}
{{ if $errorPages }}
[frontends."{{$frontendName}}".errors]
{{ range $pageName, $page := $errorPages }}
{{if $errorPages }}
[frontends."{{ $frontendName }}".errors]
{{range $pageName, $page := $errorPages }}
[frontends."{{$frontendName}}".errors.{{ $pageName }}]
status = [{{range $page.Status}}
status = [{{range $page.Status }}
"{{.}}",
{{end}}]
backend = "{{$page.Backend}}"
@ -983,12 +980,12 @@ var _templatesKvTmpl = []byte(`[backends]
{{end}}
{{ $rateLimit := getRateLimit $frontend }}
{{ if $rateLimit }}
[frontends."{{$frontendName}}".rateLimit]
{{if $rateLimit }}
[frontends."{{ $frontendName }}".rateLimit]
extractorFunc = "{{ $rateLimit.ExtractorFunc }}"
[frontends."{{$frontendName}}".rateLimit.rateSet]
{{ range $limitName, $rateLimit := $rateLimit.RateSet }}
[frontends."{{$frontendName}}".rateLimit.rateSet.{{ $limitName }}]
[frontends."{{ $frontendName }}".rateLimit.rateSet]
{{range $limitName, $rateLimit := $rateLimit.RateSet }}
[frontends."{{ $frontendName }}".rateLimit.rateSet.{{ $limitName }}]
period = "{{ $rateLimit.Period }}"
average = {{ $rateLimit.Average }}
burst = {{ $rateLimit.Burst }}
@ -996,7 +993,7 @@ var _templatesKvTmpl = []byte(`[backends]
{{end}}
{{ $headers := getHeaders $frontend }}
{{ if $headers }}
{{if $headers }}
[frontends."{{ $frontendName }}".headers]
SSLRedirect = {{ $headers.SSLRedirect }}
SSLTemporaryRedirect = {{ $headers.SSLTemporaryRedirect }}
@ -1014,33 +1011,33 @@ var _templatesKvTmpl = []byte(`[backends]
ReferrerPolicy = "{{ $headers.ReferrerPolicy }}"
IsDevelopment = {{ $headers.IsDevelopment }}
{{ if $headers.AllowedHosts }}
AllowedHosts = [{{ range $headers.AllowedHosts }}
{{if $headers.AllowedHosts }}
AllowedHosts = [{{range $headers.AllowedHosts }}
"{{.}}",
{{end}}]
{{end}}
{{ if $headers.HostsProxyHeaders }}
HostsProxyHeaders = [{{ range $headers.HostsProxyHeaders }}
{{if $headers.HostsProxyHeaders }}
HostsProxyHeaders = [{{range $headers.HostsProxyHeaders }}
"{{.}}",
{{end}}]
{{end}}
{{ if $headers.CustomRequestHeaders }}
{{if $headers.CustomRequestHeaders }}
[frontends."{{ $frontendName }}".headers.customRequestHeaders]
{{ range $k, $v := $headers.CustomRequestHeaders }}
{{range $k, $v := $headers.CustomRequestHeaders }}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{ if $headers.CustomResponseHeaders }}
{{if $headers.CustomResponseHeaders }}
[frontends."{{ $frontendName }}".headers.customResponseHeaders]
{{ range $k, $v := $headers.CustomResponseHeaders }}
{{range $k, $v := $headers.CustomResponseHeaders }}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{ if $headers.SSLProxyHeaders }}
{{if $headers.SSLProxyHeaders }}
[frontends."{{ $frontendName }}".headers.SSLProxyHeaders]
{{range $k, $v := $headers.SSLProxyHeaders}}
{{$k}} = "{{$v}}"
@ -1048,25 +1045,23 @@ var _templatesKvTmpl = []byte(`[backends]
{{end}}
{{end}}
{{range $route := List $frontend "/routes/"}}
[frontends."{{$frontendName}}".routes."{{Last $route}}"]
rule = "{{Get "" $route "/rule"}}"
{{range $routeName, $route := getRoutes $frontend }}
[frontends."{{ $frontendName }}".routes."{{ $routeName }}"]
rule = "{{ $route.Rule }}"
{{end}}
{{end}}
{{range $tlsConfiguration := List .Prefix "/tlsconfiguration/"}}
{{range $tlsConfiguration := getTLSConfigurations .Prefix }}
[[tlsConfiguration]]
{{$entryPoints := SplitGet $tlsConfiguration "/entrypoints"}}
entryPoints = [{{range $entryPoints}}
entryPoints = [{{range $tlsConfiguration.EntryPoints }}
"{{.}}",
{{end}}]
[tlsConfiguration.certificate]
certFile = """{{Get "" $tlsConfiguration "/certificate/certfile"}}"""
keyFile = """{{Get "" $tlsConfiguration "/certificate/keyfile"}}"""
certFile = """{{ $tlsConfiguration.Certificate.CertFile }}"""
keyFile = """{{ $tlsConfiguration.Certificate.KeyFile }}"""
{{end}}
`)

View file

@ -2,6 +2,7 @@ package kv
import (
"fmt"
"math"
"net/http"
"sort"
"strconv"
@ -12,6 +13,7 @@ import (
"github.com/containous/flaeg"
"github.com/containous/traefik/log"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/tls"
"github.com/containous/traefik/types"
"github.com/docker/libkv/store"
)
@ -35,16 +37,31 @@ func (p *Provider) buildConfiguration() *types.Configuration {
"Last": p.last,
"Has": p.has,
"getTLSConfigurations": p.getTLSConfigurations,
// Frontend functions
"getRedirect": p.getRedirect,
"getErrorPages": p.getErrorPages,
"getRateLimit": p.getRateLimit,
"getHeaders": p.getHeaders,
"getBackendName": p.getFuncString(pathFrontendBackend, ""),
"getPriority": p.getFuncInt(pathFrontendPriority, 0),
"getPassHostHeader": p.getFuncBool(pathFrontendPassHostHeader, true),
"getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert),
"getEntryPoints": p.getFuncSlice(pathFrontendEntryPoints),
"getWhitelistSourceRange": p.getFuncSlice(pathFrontendWhiteListSourceRange),
"getBasicAuth": p.getFuncSlice(pathFrontendBasicAuth),
"getRoutes": p.getRoutes,
"getRedirect": p.getRedirect,
"getErrorPages": p.getErrorPages,
"getRateLimit": p.getRateLimit,
"getHeaders": p.getHeaders,
// Backend functions
"getSticky": p.getSticky,
"hasStickinessLabel": p.hasStickinessLabel,
"getStickinessCookieName": p.getStickinessCookieName,
"getServers": p.getServers,
"getCircuitBreaker": p.getCircuitBreaker,
"getLoadBalancer": p.getLoadBalancer,
"getMaxConn": p.getMaxConn,
"getHealthCheck": p.getHealthCheck,
"getSticky": p.getSticky, // Deprecated [breaking]
"hasStickinessLabel": p.hasStickinessLabel, // Deprecated [breaking]
"getStickinessCookieName": p.getStickinessCookieName, // Deprecated [breaking]
}
configuration, err := p.GetConfiguration("templates/kv.tmpl", KvFuncMap, templateObjects)
@ -61,6 +78,7 @@ func (p *Provider) buildConfiguration() *types.Configuration {
return configuration
}
// Deprecated
func (p *Provider) getSticky(rootPath string) bool {
stickyValue := p.get("", rootPath, pathBackendLoadBalancerSticky)
if len(stickyValue) > 0 {
@ -77,10 +95,12 @@ func (p *Provider) getSticky(rootPath string) bool {
return sticky
}
// Deprecated
func (p *Provider) hasStickinessLabel(rootPath string) bool {
return p.getBool(false, rootPath, pathBackendLoadBalancerStickiness)
}
// Deprecated
func (p *Provider) getStickinessCookieName(rootPath string) string {
return p.get("", rootPath, pathBackendLoadBalancerStickinessCookieName)
}
@ -193,6 +213,145 @@ func (p *Provider) getHeaders(rootPath string) *types.Headers {
return headers
}
func (p *Provider) getLoadBalancer(rootPath string) *types.LoadBalancer {
lb := &types.LoadBalancer{
Method: p.get(label.DefaultBackendLoadBalancerMethod, rootPath, pathBackendLoadBalancerMethod),
Sticky: p.getSticky(rootPath),
}
if p.getBool(false, rootPath, pathBackendLoadBalancerStickiness) {
lb.Stickiness = &types.Stickiness{
CookieName: p.get("", rootPath, pathBackendLoadBalancerStickinessCookieName),
}
}
return lb
}
func (p *Provider) getCircuitBreaker(rootPath string) *types.CircuitBreaker {
if !p.has(rootPath, pathBackendCircuitBreakerExpression) {
return nil
}
circuitBreaker := p.get(label.DefaultCircuitBreakerExpression, rootPath, pathBackendCircuitBreakerExpression)
if len(circuitBreaker) == 0 {
return nil
}
return &types.CircuitBreaker{Expression: circuitBreaker}
}
func (p *Provider) getMaxConn(rootPath string) *types.MaxConn {
amount := p.getInt64(math.MinInt64, rootPath, pathBackendMaxConnAmount)
extractorFunc := p.get(label.DefaultBackendMaxconnExtractorFunc, rootPath, pathBackendMaxConnExtractorFunc)
if amount == math.MinInt64 || len(extractorFunc) == 0 {
return nil
}
return &types.MaxConn{
Amount: amount,
ExtractorFunc: extractorFunc,
}
}
func (p *Provider) getHealthCheck(rootPath string) *types.HealthCheck {
path := p.get("", rootPath, pathBackendHealthCheckPath)
if len(path) == 0 {
return nil
}
port := p.getInt(label.DefaultBackendHealthCheckPort, rootPath, pathBackendHealthCheckPort)
interval := p.get("30s", rootPath, pathBackendHealthCheckInterval)
return &types.HealthCheck{
Path: path,
Port: port,
Interval: interval,
}
}
func (p *Provider) getTLSConfigurations(prefix string) []*tls.Configuration {
var tlsConfiguration []*tls.Configuration
for _, tlsConfPath := range p.list(prefix, pathTLSConfiguration) {
certFile := p.get("", tlsConfPath, pathTLSConfigurationCertFile)
keyFile := p.get("", tlsConfPath, pathTLSConfigurationKeyFile)
if len(certFile) == 0 && len(keyFile) == 0 {
log.Warnf("Invalid TLS configuration (no cert and no key): %s", tlsConfPath)
continue
}
entryPoints := p.splitGet(tlsConfPath, pathTLSConfigurationEntryPoints)
if len(entryPoints) == 0 {
log.Warnf("Invalid TLS configuration (no entry points): %s", tlsConfPath)
continue
}
tlsConf := &tls.Configuration{
EntryPoints: entryPoints,
Certificate: &tls.Certificate{
CertFile: tls.FileOrContent(certFile),
KeyFile: tls.FileOrContent(keyFile),
},
}
tlsConfiguration = append(tlsConfiguration, tlsConf)
}
return tlsConfiguration
}
func (p *Provider) getRoutes(rootPath string) map[string]types.Route {
var routes map[string]types.Route
rts := p.list(rootPath, pathFrontendRoutes)
for _, rt := range rts {
rule := p.get("", rt, pathFrontendRule)
if len(rule) == 0 {
continue
}
if routes == nil {
routes = make(map[string]types.Route)
}
routeName := p.last(rt)
routes[routeName] = types.Route{
Rule: rule,
}
}
return routes
}
func (p *Provider) getServers(rootPath string) map[string]types.Server {
var servers map[string]types.Server
serverKeys := p.listServers(rootPath)
for _, serverKey := range serverKeys {
serverURL := p.get("", serverKey, pathBackendServerURL)
if len(serverURL) == 0 {
continue
}
if servers == nil {
servers = make(map[string]types.Server)
}
serverName := p.last(serverKey)
servers[serverName] = types.Server{
URL: serverURL,
Weight: p.getInt(0, serverKey, pathBackendServerWeight),
}
}
return servers
}
func (p *Provider) listServers(backend string) []string {
serverNames := p.list(backend, pathBackendServers)
return fun.Filter(p.serverFilter, serverNames).([]string)
@ -229,6 +388,30 @@ func (p *Provider) checkConstraints(keys ...string) bool {
return true
}
func (p *Provider) getFuncString(key string, defaultValue string) func(rootPath string) string {
return func(rootPath string) string {
return p.get(defaultValue, rootPath, key)
}
}
func (p *Provider) getFuncBool(key string, defaultValue bool) func(rootPath string) bool {
return func(rootPath string) bool {
return p.getBool(defaultValue, rootPath, key)
}
}
func (p *Provider) getFuncInt(key string, defaultValue int) func(rootPath string) int {
return func(rootPath string) int {
return p.getInt(defaultValue, rootPath, key)
}
}
func (p *Provider) getFuncSlice(key string) func(rootPath string) []string {
return func(rootPath string) []string {
return p.splitGet(rootPath, key)
}
}
func (p *Provider) get(defaultValue string, keyParts ...string) string {
key := strings.Join(keyParts, "")

View file

@ -38,6 +38,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
expected: &types.Configuration{
Backends: map[string]*types.Backend{
"backend.with.dot.too": {
LoadBalancer: &types.LoadBalancer{Method: label.DefaultBackendLoadBalancerMethod},
Servers: map[string]types.Server{
"server.with.dot": {
URL: "http://172.17.0.2:80",
@ -48,11 +49,10 @@ func TestProviderBuildConfiguration(t *testing.T) {
},
Frontends: map[string]*types.Frontend{
"frontend.with.dot": {
Backend: "backend.with.dot.too",
PassHostHeader: true,
EntryPoints: []string{},
WhitelistSourceRange: []string{},
BasicAuth: []string{},
Backend: "backend.with.dot.too",
PassHostHeader: true,
EntryPoints: []string{},
BasicAuth: []string{},
Routes: map[string]types.Route{
"route.with.dot": {
Rule: "Host:test.localhost",
@ -1292,3 +1292,450 @@ func TestProviderGetHeaders(t *testing.T) {
})
}
}
func TestProviderGetLoadBalancer(t *testing.T) {
testCases := []struct {
desc string
rootPath string
kvPairs []*store.KVPair
expected *types.LoadBalancer
}{
{
desc: "when all keys",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendLoadBalancerMethod, "drr"),
withPair(pathBackendLoadBalancerSticky, "true"),
withPair(pathBackendLoadBalancerStickiness, "true"),
withPair(pathBackendLoadBalancerStickinessCookieName, "aubergine"))),
expected: &types.LoadBalancer{
Method: "drr",
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "aubergine",
},
},
},
{
desc: "when no specific configuration",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik", backend("foo")),
expected: &types.LoadBalancer{
Method: "wrr",
},
},
{
desc: "when method is set",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendLoadBalancerMethod, "drr"))),
expected: &types.LoadBalancer{
Method: "drr",
},
},
{
desc: "when sticky is set",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendLoadBalancerSticky, "true"))),
expected: &types.LoadBalancer{
Method: "wrr",
Sticky: true,
},
},
{
desc: "when stickiness is set",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendLoadBalancerStickiness, "true"))),
expected: &types.LoadBalancer{
Method: "wrr",
Stickiness: &types.Stickiness{},
},
},
{
desc: "when stickiness cookie name is set",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendLoadBalancerStickiness, "true"),
withPair(pathBackendLoadBalancerStickinessCookieName, "aubergine"))),
expected: &types.LoadBalancer{
Method: "wrr",
Stickiness: &types.Stickiness{
CookieName: "aubergine",
},
},
},
{
desc: "when stickiness cookie name is set but not stickiness",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendLoadBalancerStickinessCookieName, "aubergine"))),
expected: &types.LoadBalancer{
Method: "wrr",
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getLoadBalancer(test.rootPath)
assert.Equal(t, test.expected, result)
})
}
}
func TestProviderGetCircuitBreaker(t *testing.T) {
testCases := []struct {
desc string
rootPath string
kvPairs []*store.KVPair
expected *types.CircuitBreaker
}{
{
desc: "when cb expression defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendCircuitBreakerExpression, label.DefaultCircuitBreakerExpression))),
expected: &types.CircuitBreaker{
Expression: label.DefaultCircuitBreakerExpression,
},
},
{
desc: "when no cb expression",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik", backend("foo")),
expected: nil,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getCircuitBreaker(test.rootPath)
assert.Equal(t, test.expected, result)
})
}
}
func TestProviderGetMaxConn(t *testing.T) {
testCases := []struct {
desc string
rootPath string
kvPairs []*store.KVPair
expected *types.MaxConn
}{
{
desc: "when max conn keys are defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendMaxConnAmount, "5"),
withPair(pathBackendMaxConnExtractorFunc, "client.ip"))),
expected: &types.MaxConn{
Amount: 5,
ExtractorFunc: "client.ip",
},
},
{
desc: "should return nil when only extractor func is defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendMaxConnExtractorFunc, "client.ip"))),
expected: nil,
},
{
desc: "when only amount is defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendMaxConnAmount, "5"))),
expected: &types.MaxConn{
Amount: 5,
ExtractorFunc: "request.host",
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getMaxConn(test.rootPath)
assert.Equal(t, test.expected, result)
})
}
}
func TestProviderGetHealthCheck(t *testing.T) {
testCases := []struct {
desc string
rootPath string
kvPairs []*store.KVPair
expected *types.HealthCheck
}{
{
desc: "when all configuration keys defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendHealthCheckPath, "/health"),
withPair(pathBackendHealthCheckPort, "80"),
withPair(pathBackendHealthCheckInterval, "10s"))),
expected: &types.HealthCheck{
Interval: "10s",
Path: "/health",
Port: 80,
},
},
{
desc: "when only path defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendHealthCheckPath, "/health"))),
expected: &types.HealthCheck{
Interval: "30s",
Path: "/health",
Port: 0,
},
},
{
desc: "should return nil when no path",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendHealthCheckPort, "80"),
withPair(pathBackendHealthCheckInterval, "30s"))),
expected: nil,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getHealthCheck(test.rootPath)
assert.Equal(t, test.expected, result)
})
}
}
func TestProviderGetTLSConfigurations(t *testing.T) {
testCases := []struct {
desc string
kvPairs []*store.KVPair
expected []*tls.Configuration
}{
{
desc: "when several TLS configuration defined",
kvPairs: filler("traefik",
entry("tlsconfiguration/foo",
withPair("entrypoints", "http,https"),
withPair("certificate/certfile", "certfile1"),
withPair("certificate/keyfile", "keyfile1")),
entry("tlsconfiguration/bar",
withPair("entrypoints", "http,https"),
withPair("certificate/certfile", "certfile2"),
withPair("certificate/keyfile", "keyfile2"))),
expected: []*tls.Configuration{
{
EntryPoints: []string{"http", "https"},
Certificate: &tls.Certificate{
CertFile: "certfile2",
KeyFile: "keyfile2",
},
},
{
EntryPoints: []string{"http", "https"},
Certificate: &tls.Certificate{
CertFile: "certfile1",
KeyFile: "keyfile1",
},
},
},
},
{
desc: "should return nil when no TLS configuration",
kvPairs: filler("traefik", entry("tlsconfiguration/foo")),
expected: nil,
},
{
desc: "should return nil when no entry points",
kvPairs: filler("traefik",
entry("tlsconfiguration/foo",
withPair("certificate/certfile", "certfile2"),
withPair("certificate/keyfile", "keyfile2"))),
expected: nil,
},
{
desc: "should return nil when no cert file and no key file",
kvPairs: filler("traefik",
entry("tlsconfiguration/foo",
withPair("entrypoints", "http,https"))),
expected: nil,
},
}
prefix := "traefik"
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getTLSConfigurations(prefix)
assert.Equal(t, test.expected, result)
})
}
}
func TestProviderGetRoutes(t *testing.T) {
testCases := []struct {
desc string
rootPath string
kvPairs []*store.KVPair
expected map[string]types.Route
}{
{
desc: "should return nil when no data",
expected: nil,
},
{
desc: "should return nil when route key exists but without rule key",
rootPath: "traefik/frontends/foo",
kvPairs: filler("traefik",
frontend("foo",
withPair(pathFrontendRoutes+"bar", "test1"),
withPair(pathFrontendRoutes+"bir", "test2"))),
expected: nil,
},
{
desc: "should return a map when configuration keys are defined",
rootPath: "traefik/frontends/foo",
kvPairs: filler("traefik",
frontend("foo",
withPair(pathFrontendRoutes+"bar"+pathFrontendRule, "test1"),
withPair(pathFrontendRoutes+"bir"+pathFrontendRule, "test2"))),
expected: map[string]types.Route{
"bar": {
Rule: "test1",
},
"bir": {
Rule: "test2",
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getRoutes(test.rootPath)
assert.Equal(t, test.expected, result)
})
}
}
func TestProviderGetServers(t *testing.T) {
testCases := []struct {
desc string
rootPath string
kvPairs []*store.KVPair
expected map[string]types.Server
}{
{
desc: "should return nil when no data",
expected: nil,
},
{
desc: "should return nil when server has no URL",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendServers+"server1/weight", "7"),
withPair(pathBackendServers+"server2/weight", "6"))),
expected: nil,
},
{
desc: "should use default weight when invalid weight value",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendServers+"server1/url", "http://172.17.0.2:80"),
withPair(pathBackendServers+"server1/weight", "kls"))),
expected: map[string]types.Server{
"server1": {
URL: "http://172.17.0.2:80",
Weight: 0,
},
},
},
{
desc: "should return a map when configuration keys are defined",
rootPath: "traefik/backends/foo",
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendServers+"server1/url", "http://172.17.0.2:80"),
withPair(pathBackendServers+"server2/url", "http://172.17.0.3:80"),
withPair(pathBackendServers+"server2/weight", "6"))),
expected: map[string]types.Server{
"server1": {
URL: "http://172.17.0.2:80",
Weight: 0,
},
"server2": {
URL: "http://172.17.0.3:80",
Weight: 6,
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
p := newProviderMock(test.kvPairs)
result := p.getServers(test.rootPath)
assert.Equal(t, test.expected, result)
})
}
}

View file

@ -1,89 +1,86 @@
[backends]
{{range $backend := List .Prefix "/backends/"}}
{{$backendName := Last $backend}}
{{range $backend := List .Prefix "/backends/" }}
{{ $backendName := Last $backend }}
{{$circuitBreaker := Get "" $backend "/circuitbreaker/expression"}}
{{with $circuitBreaker}}
[backends."{{$backendName}}".circuitBreaker]
expression = "{{$circuitBreaker}}"
{{ $circuitBreaker := getCircuitBreaker $backend }}
{{if $circuitBreaker }}
[backends."{{ $backendName }}".circuitBreaker]
expression = "{{ $circuitBreaker.Expression }}"
{{end}}
{{$loadBalancer := Get "" $backend "/loadbalancer/method"}}
{{with $loadBalancer}}
[backends."{{$backendName}}".loadBalancer]
method = "{{$loadBalancer}}"
sticky = {{ getSticky $backend }}
{{if hasStickinessLabel $backend}}
[backends."{{$backendName}}".loadBalancer.stickiness]
cookieName = "{{getStickinessCookieName $backend}}"
{{end}}
{{ $loadBalancer := getLoadBalancer $backend }}
{{if $loadBalancer }}
[backends."{{ $backendName }}".loadBalancer]
method = "{{ $loadBalancer.Method }}"
sticky = {{ $loadBalancer.Sticky }}
{{if $loadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
{{end}}
{{end}}
{{$maxConnAmt := Get "" $backend "/maxconn/amount"}}
{{$maxConnExtractorFunc := Get "" $backend "/maxconn/extractorfunc"}}
{{with $maxConnAmt}}
{{with $maxConnExtractorFunc}}
[backends."{{$backendName}}".maxConn]
amount = {{$maxConnAmt}}
extractorFunc = "{{$maxConnExtractorFunc}}"
{{end}}
{{ $maxConn := getMaxConn $backend }}
{{if $maxConn }}
[backends."{{ $backendName }}".maxConn]
extractorFunc = "{{ $maxConn.ExtractorFunc }}"
amount = {{ $maxConn.Amount }}
{{end}}
{{$healthCheck := Get "" $backend "/healthcheck/path"}}
{{with $healthCheck}}
[backends."{{$backendName}}".healthCheck]
path = "{{$healthCheck}}"
port = {{ Get "0" $backend "/healthcheck/port" }}
interval = "{{ Get "30s" $backend "/healthcheck/interval" }}"
{{ $healthCheck := getHealthCheck $backend }}
{{if $healthCheck }}
[backends.{{ $backendName }}.healthCheck]
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
{{end}}
{{range $server := ListServers $backend}}
[backends."{{$backendName}}".servers."{{Last $server}}"]
url = "{{Get "" $server "/url"}}"
weight = {{Get "0" $server "/weight"}}
{{range $serverName, $server := getServers $backend}}
[backends."{{ $backendName }}".servers."{{ $serverName }}"]
url = "{{ $server.URL }}"
weight = {{ $server.Weight }}
{{end}}
{{end}}
[frontends]
{{range $frontend := List .Prefix "/frontends/" }}
{{$frontendName := Last $frontend}}
{{ $frontendName := Last $frontend }}
[frontends."{{$frontendName}}"]
backend = "{{Get "" $frontend "/backend"}}"
priority = {{Get "0" $frontend "/priority"}}
passHostHeader = {{Get "true" $frontend "/passHostHeader"}}
passTLSCert = {{Get "false" $frontend "/passtlscert"}}
[frontends."{{ $frontendName }}"]
backend = "{{ getBackendName $frontend }}"
priority = {{ getPriority $frontend }}
passHostHeader = {{ getPassHostHeader $frontend }}
passTLSCert = {{ getPassTLSCert $frontend }}
{{$entryPoints := SplitGet $frontend "/entrypoints"}}
entryPoints = [{{range $entryPoints}}
entryPoints = [{{range getEntryPoints $frontend }}
"{{.}}",
{{end}}]
{{$whitelistSourceRange := SplitGet $frontend "/whitelistsourcerange"}}
whitelistSourceRange = [{{range $whitelistSourceRange}}
{{ $whitelistSourceRange := getWhitelistSourceRange $frontend }}
{{if $whitelistSourceRange }}
whitelistSourceRange = [{{range $whitelistSourceRange }}
"{{.}}",
{{end}}]
{{end}}
basicAuth = [{{range getBasicAuth $frontend }}
"{{.}}",
{{end}}]
{{$basicAuth := SplitGet $frontend "/basicauth"}}
basicAuth = [{{range $basicAuth}}
"{{.}}",
{{end}}]
{{$redirect := getRedirect $frontend }}
{{ if $redirect }}
[frontends."{{$frontendName}}".redirect]
{{ $redirect := getRedirect $frontend }}
{{if $redirect }}
[frontends."{{ $frontendName }}".redirect]
entryPoint = "{{ $redirect.EntryPoint }}"
regex = "{{ $redirect.Regex }}"
replacement = "{{ $redirect.Replacement }}"
{{end}}
{{ $errorPages := getErrorPages $frontend }}
{{ if $errorPages }}
[frontends."{{$frontendName}}".errors]
{{ range $pageName, $page := $errorPages }}
{{if $errorPages }}
[frontends."{{ $frontendName }}".errors]
{{range $pageName, $page := $errorPages }}
[frontends."{{$frontendName}}".errors.{{ $pageName }}]
status = [{{range $page.Status}}
status = [{{range $page.Status }}
"{{.}}",
{{end}}]
backend = "{{$page.Backend}}"
@ -92,12 +89,12 @@
{{end}}
{{ $rateLimit := getRateLimit $frontend }}
{{ if $rateLimit }}
[frontends."{{$frontendName}}".rateLimit]
{{if $rateLimit }}
[frontends."{{ $frontendName }}".rateLimit]
extractorFunc = "{{ $rateLimit.ExtractorFunc }}"
[frontends."{{$frontendName}}".rateLimit.rateSet]
{{ range $limitName, $rateLimit := $rateLimit.RateSet }}
[frontends."{{$frontendName}}".rateLimit.rateSet.{{ $limitName }}]
[frontends."{{ $frontendName }}".rateLimit.rateSet]
{{range $limitName, $rateLimit := $rateLimit.RateSet }}
[frontends."{{ $frontendName }}".rateLimit.rateSet.{{ $limitName }}]
period = "{{ $rateLimit.Period }}"
average = {{ $rateLimit.Average }}
burst = {{ $rateLimit.Burst }}
@ -105,7 +102,7 @@
{{end}}
{{ $headers := getHeaders $frontend }}
{{ if $headers }}
{{if $headers }}
[frontends."{{ $frontendName }}".headers]
SSLRedirect = {{ $headers.SSLRedirect }}
SSLTemporaryRedirect = {{ $headers.SSLTemporaryRedirect }}
@ -123,33 +120,33 @@
ReferrerPolicy = "{{ $headers.ReferrerPolicy }}"
IsDevelopment = {{ $headers.IsDevelopment }}
{{ if $headers.AllowedHosts }}
AllowedHosts = [{{ range $headers.AllowedHosts }}
{{if $headers.AllowedHosts }}
AllowedHosts = [{{range $headers.AllowedHosts }}
"{{.}}",
{{end}}]
{{end}}
{{ if $headers.HostsProxyHeaders }}
HostsProxyHeaders = [{{ range $headers.HostsProxyHeaders }}
{{if $headers.HostsProxyHeaders }}
HostsProxyHeaders = [{{range $headers.HostsProxyHeaders }}
"{{.}}",
{{end}}]
{{end}}
{{ if $headers.CustomRequestHeaders }}
{{if $headers.CustomRequestHeaders }}
[frontends."{{ $frontendName }}".headers.customRequestHeaders]
{{ range $k, $v := $headers.CustomRequestHeaders }}
{{range $k, $v := $headers.CustomRequestHeaders }}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{ if $headers.CustomResponseHeaders }}
{{if $headers.CustomResponseHeaders }}
[frontends."{{ $frontendName }}".headers.customResponseHeaders]
{{ range $k, $v := $headers.CustomResponseHeaders }}
{{range $k, $v := $headers.CustomResponseHeaders }}
{{$k}} = "{{$v}}"
{{end}}
{{end}}
{{ if $headers.SSLProxyHeaders }}
{{if $headers.SSLProxyHeaders }}
[frontends."{{ $frontendName }}".headers.SSLProxyHeaders]
{{range $k, $v := $headers.SSLProxyHeaders}}
{{$k}} = "{{$v}}"
@ -157,24 +154,22 @@
{{end}}
{{end}}
{{range $route := List $frontend "/routes/"}}
[frontends."{{$frontendName}}".routes."{{Last $route}}"]
rule = "{{Get "" $route "/rule"}}"
{{range $routeName, $route := getRoutes $frontend }}
[frontends."{{ $frontendName }}".routes."{{ $routeName }}"]
rule = "{{ $route.Rule }}"
{{end}}
{{end}}
{{range $tlsConfiguration := List .Prefix "/tlsconfiguration/"}}
{{range $tlsConfiguration := getTLSConfigurations .Prefix }}
[[tlsConfiguration]]
{{$entryPoints := SplitGet $tlsConfiguration "/entrypoints"}}
entryPoints = [{{range $entryPoints}}
entryPoints = [{{range $tlsConfiguration.EntryPoints }}
"{{.}}",
{{end}}]
[tlsConfiguration.certificate]
certFile = """{{Get "" $tlsConfiguration "/certificate/certfile"}}"""
keyFile = """{{Get "" $tlsConfiguration "/certificate/keyfile"}}"""
certFile = """{{ $tlsConfiguration.Certificate.CertFile }}"""
keyFile = """{{ $tlsConfiguration.Certificate.KeyFile }}"""
{{end}}