feat(rancher): add rate limit and error pages labels.

This commit is contained in:
Fernandez Ludovic 2017-12-20 16:33:26 +01:00 committed by Traefiker
parent d0a6689413
commit 22405a1259
3 changed files with 186 additions and 18 deletions

View file

@ -15,17 +15,12 @@ import (
func (p *Provider) buildConfiguration(services []rancherData) *types.Configuration {
var RancherFuncMap = template.FuncMap{
"getDomain": getFuncString(label.TraefikDomain, p.Domain), // FIXME dead ?
// Backend functions
"getPort": getFuncString(label.TraefikPort, ""),
"getBackend": getBackend,
"getWeight": getFuncString(label.TraefikWeight, label.DefaultWeight),
"getDomain": getFuncString(label.TraefikDomain, p.Domain),
"getProtocol": getFuncString(label.TraefikProtocol, label.DefaultProtocol),
"getPassHostHeader": getFuncString(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
"getPassTLSCert": getFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
"getPriority": getFuncString(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
"getEntryPoints": getFuncSliceString(label.TraefikFrontendEntryPoints),
"getBasicAuth": getFuncSliceString(label.TraefikFrontendAuthBasic),
"getFrontendRule": p.getFrontendRule,
"getWeight": getFuncString(label.TraefikWeight, label.DefaultWeight),
"hasCircuitBreakerLabel": hasFunc(label.TraefikBackendCircuitBreakerExpression),
"getCircuitBreakerExpression": getFuncString(label.TraefikBackendCircuitBreakerExpression, label.DefaultCircuitBreakerExpression),
"hasLoadBalancerLabel": hasLoadBalancerLabel,
@ -33,19 +28,33 @@ func (p *Provider) buildConfiguration(services []rancherData) *types.Configurati
"hasMaxConnLabels": hasMaxConnLabels,
"getMaxConnAmount": getFuncInt64(label.TraefikBackendMaxConnAmount, math.MaxInt64),
"getMaxConnExtractorFunc": getFuncString(label.TraefikBackendMaxConnExtractorFunc, label.DefaultBackendMaxconnExtractorFunc),
"getSticky": getSticky, // deprecated
"getSticky": getSticky,
"hasStickinessLabel": hasFunc(label.TraefikBackendLoadBalancerStickiness),
"getStickinessCookieName": getFuncString(label.TraefikBackendLoadBalancerStickinessCookieName, label.DefaultBackendLoadbalancerStickinessCookieName),
"hasRedirect": hasRedirect,
"getRedirectEntryPoint": getFuncString(label.TraefikFrontendRedirectEntryPoint, label.DefaultFrontendRedirectEntryPoint),
"getRedirectRegex": getFuncString(label.TraefikFrontendRedirectRegex, ""),
"getRedirectReplacement": getFuncString(label.TraefikFrontendRedirectReplacement, ""),
"getWhitelistSourceRange": getFuncSliceString(label.TraefikFrontendWhitelistSourceRange),
"hasHealthCheckLabels": hasFunc(label.TraefikBackendHealthCheckPath),
"getHealthCheckPath": getFuncString(label.TraefikBackendHealthCheckPath, ""),
"getHealthCheckPort": getFuncInt(label.TraefikBackendHealthCheckPort, label.DefaultBackendHealthCheckPort),
"getHealthCheckInterval": getFuncString(label.TraefikBackendHealthCheckInterval, ""),
// Frontend functions
"getBackend": getBackend,
"getPriority": getFuncString(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
"getPassHostHeader": getFuncString(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
"getPassTLSCert": getFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
"getEntryPoints": getFuncSliceString(label.TraefikFrontendEntryPoints),
"getBasicAuth": getFuncSliceString(label.TraefikFrontendAuthBasic),
"getWhitelistSourceRange": getFuncSliceString(label.TraefikFrontendWhitelistSourceRange),
"getFrontendRule": p.getFrontendRule,
"hasRedirect": hasRedirect,
"getRedirectEntryPoint": getFuncString(label.TraefikFrontendRedirectEntryPoint, label.DefaultFrontendRedirectEntryPoint),
"getRedirectRegex": getFuncString(label.TraefikFrontendRedirectRegex, ""),
"getRedirectReplacement": getFuncString(label.TraefikFrontendRedirectReplacement, ""),
"hasErrorPages": hasPrefixFunc(label.Prefix + label.BaseFrontendErrorPage),
"getErrorPages": getErrorPages,
"hasRateLimits": hasFunc(label.TraefikFrontendRateLimitExtractorFunc),
"getRateLimitsExtractorFunc": getFuncString(label.TraefikFrontendRateLimitExtractorFunc, ""),
"getRateLimits": getRateLimits,
// Headers
"hasRequestHeaders": hasFunc(label.TraefikFrontendRequestHeaders),
"getRequestHeaders": getFuncMap(label.TraefikFrontendRequestHeaders),
"hasResponseHeaders": hasFunc(label.TraefikFrontendResponseHeaders),
@ -195,8 +204,21 @@ func getBackend(service rancherData) string {
}
func hasRedirect(service rancherData) bool {
return label.Has(service.Labels, label.TraefikFrontendRedirectEntryPoint) ||
label.Has(service.Labels, label.TraefikFrontendRedirectRegex) && label.Has(service.Labels, label.TraefikFrontendRedirectReplacement)
frep := label.Has(service.Labels, label.TraefikFrontendRedirectEntryPoint)
frrg := label.Has(service.Labels, label.TraefikFrontendRedirectRegex)
frrp := label.Has(service.Labels, label.TraefikFrontendRedirectReplacement)
return frep || frrg && frrp
}
func getErrorPages(service rancherData) map[string]*types.ErrorPage {
prefix := label.Prefix + label.BaseFrontendErrorPage
return label.ParseErrorPages(service.Labels, prefix, label.RegexpFrontendErrorPage)
}
func getRateLimits(service rancherData) map[string]*types.Rate {
prefix := label.Prefix + label.BaseFrontendRateLimit
return label.ParseRateSets(service.Labels, prefix, label.RegexpFrontendRateLimit)
}
// Label functions
@ -242,3 +264,9 @@ func hasFunc(labelName string) func(service rancherData) bool {
return label.Has(service.Labels, labelName)
}
}
func hasPrefixFunc(prefix string) func(service rancherData) bool {
return func(service rancherData) bool {
return label.HasPrefix(service.Labels, prefix)
}
}

View file

@ -2,7 +2,9 @@ package rancher
import (
"testing"
"time"
"github.com/containous/flaeg"
"github.com/containous/traefik/provider/label"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert"
@ -70,6 +72,118 @@ func TestProviderBuildConfiguration(t *testing.T) {
},
},
},
{
desc: "with Error Pages",
services: []rancherData{
{
Name: "test/service",
Labels: map[string]string{
label.TraefikPort: "80",
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: "404",
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: "foobar",
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: "foo_query",
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: "500,600",
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: "foobar",
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: "bar_query",
},
Health: "healthy",
Containers: []string{"127.0.0.1"},
},
},
expectedBackends: map[string]*types.Backend{
"backend-test-service": {
Servers: map[string]types.Server{
"server-0": {
URL: "http://127.0.0.1:80",
Weight: 0,
},
},
},
},
expectedFrontends: map[string]*types.Frontend{
"frontend-Host-test-service-rancher-localhost": {
EntryPoints: []string{},
BasicAuth: []string{},
Backend: "backend-test-service",
Routes: map[string]types.Route{
"route-frontend-Host-test-service-rancher-localhost": {
Rule: "Host:test.service.rancher.localhost",
},
},
PassHostHeader: true,
Errors: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
Query: "foo_query",
Backend: "foobar",
},
"bar": {
Status: []string{"500", "600"},
Query: "bar_query",
Backend: "foobar",
},
},
},
},
},
{
desc: "with rate Limits",
services: []rancherData{
{
Name: "test/service",
Labels: map[string]string{
label.TraefikPort: "80",
label.TraefikFrontendRateLimitExtractorFunc: "client.ip",
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitPeriod: "6",
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitAverage: "12",
label.Prefix + label.BaseFrontendRateLimit + "foo." + label.SuffixRateLimitBurst: "18",
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitPeriod: "3",
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitAverage: "6",
label.Prefix + label.BaseFrontendRateLimit + "bar." + label.SuffixRateLimitBurst: "9",
},
Health: "healthy",
Containers: []string{"127.0.0.1"},
},
},
expectedBackends: map[string]*types.Backend{
"backend-test-service": {
Servers: map[string]types.Server{
"server-0": {
URL: "http://127.0.0.1:80",
Weight: 0,
},
},
},
},
expectedFrontends: map[string]*types.Frontend{
"frontend-Host-test-service-rancher-localhost": {
EntryPoints: []string{},
BasicAuth: []string{},
Backend: "backend-test-service",
Routes: map[string]types.Route{
"route-frontend-Host-test-service-rancher-localhost": {
Rule: "Host:test.service.rancher.localhost",
},
},
PassHostHeader: true,
RateLimit: &types.RateLimit{
ExtractorFunc: "client.ip",
RateSet: map[string]*types.Rate{
"foo": {
Period: flaeg.Duration(6 * time.Second),
Average: 12,
Burst: 18,
},
"bar": {
Period: flaeg.Duration(3 * time.Second),
Average: 6,
Burst: 9,
},
},
},
},
},
},
}
for _, test := range testCases {

View file

@ -2,6 +2,8 @@
[backends]
{{range $backendName, $backend := .Backends}}
[backends.backend-{{$backendName}}]
{{if hasCircuitBreakerLabel $backend}}
[backends.backend-{{$backendName}}.circuitBreaker]
expression = "{{getCircuitBreakerExpression $backend}}"
@ -68,7 +70,31 @@
replacement = "{{getRedirectReplacement $service}}"
{{end}}
[frontends."frontend-{{$frontendName}}".headers]
{{ if hasErrorPages $service }}
[frontends."frontend-{{$frontendName}}".errors]
{{ range $pageName, $page := getErrorPages $service }}
[frontends."frontend-{{$frontendName}}".errors.{{ $pageName }}]
status = [{{range $page.Status}}
"{{.}}",
{{end}}]
backend = "{{$page.Backend}}"
query = "{{$page.Query}}"
{{end}}
{{end}}
{{ if hasRateLimits $service }}
[frontends."frontend-{{$frontendName}}".rateLimit]
extractorFunc = "{{ getRateLimitsExtractorFunc $service }}"
[frontends."frontend-{{$frontendName}}".rateLimit.rateSet]
{{ range $limitName, $rateLimit := getRateLimits $service }}
[frontends."frontend-{{$frontendName}}".rateLimit.rateSet.{{ $limitName }}]
period = "{{ $rateLimit.Period }}"
average = {{ $rateLimit.Average }}
burst = {{ $rateLimit.Burst }}
{{end}}
{{end}}
[frontends."frontend-{{$frontendName}}".headers]
{{if hasSSLRedirectHeaders $service}}
SSLRedirect = {{getSSLRedirectHeaders $service}}
{{end}}