feat(docker): add error pages labels.

This commit is contained in:
Fernandez Ludovic 2017-12-18 16:26:04 +01:00 committed by Traefiker
parent 50757b5e99
commit c30ebe5f90
9 changed files with 413 additions and 18 deletions

View file

@ -49,6 +49,8 @@ func (p *Provider) buildConfiguration(containersInspected []dockerData) *types.C
"getRedirectEntryPoint": getFuncStringLabel(label.TraefikFrontendRedirectEntryPoint, label.DefaultFrontendRedirectEntryPoint), "getRedirectEntryPoint": getFuncStringLabel(label.TraefikFrontendRedirectEntryPoint, label.DefaultFrontendRedirectEntryPoint),
"getRedirectRegex": getFuncStringLabel(label.TraefikFrontendRedirectRegex, ""), "getRedirectRegex": getFuncStringLabel(label.TraefikFrontendRedirectRegex, ""),
"getRedirectReplacement": getFuncStringLabel(label.TraefikFrontendRedirectReplacement, ""), "getRedirectReplacement": getFuncStringLabel(label.TraefikFrontendRedirectReplacement, ""),
"hasErrorPages": hasErrorPages,
"getErrorPages": getErrorPages,
// Headers // Headers
"hasRequestHeaders": hasFunc(label.TraefikFrontendRequestHeaders), "hasRequestHeaders": hasFunc(label.TraefikFrontendRequestHeaders),
"getRequestHeaders": getFuncMapLabel(label.TraefikFrontendRequestHeaders), "getRequestHeaders": getFuncMapLabel(label.TraefikFrontendRequestHeaders),
@ -114,6 +116,8 @@ func (p *Provider) buildConfiguration(containersInspected []dockerData) *types.C
"getServiceRequestHeaders": getFuncServiceMapLabel(label.SuffixFrontendRequestHeaders), "getServiceRequestHeaders": getFuncServiceMapLabel(label.SuffixFrontendRequestHeaders),
"hasServiceResponseHeaders": hasFuncServiceLabel(label.SuffixFrontendResponseHeaders), "hasServiceResponseHeaders": hasFuncServiceLabel(label.SuffixFrontendResponseHeaders),
"getServiceResponseHeaders": getFuncServiceMapLabel(label.SuffixFrontendResponseHeaders), "getServiceResponseHeaders": getFuncServiceMapLabel(label.SuffixFrontendResponseHeaders),
"hasServiceErrorPages": hasServiceErrorPages,
"getServiceErrorPages": getServiceErrorPages,
} }
// filter containers // filter containers
filteredContainers := fun.Filter(func(container dockerData) bool { filteredContainers := fun.Filter(func(container dockerData) bool {

View file

@ -8,6 +8,7 @@ import (
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/provider" "github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/label" "github.com/containous/traefik/provider/label"
"github.com/containous/traefik/types"
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
) )
@ -172,6 +173,15 @@ func hasRedirect(container dockerData) bool {
label.Has(container.Labels, label.TraefikFrontendRedirectReplacement) && label.Has(container.Labels, label.TraefikFrontendRedirectRegex) label.Has(container.Labels, label.TraefikFrontendRedirectReplacement) && label.Has(container.Labels, label.TraefikFrontendRedirectRegex)
} }
func hasErrorPages(container dockerData) bool {
return label.HasPrefix(container.Labels, label.Prefix+label.BaseFrontendErrorPage)
}
func getErrorPages(container dockerData) map[string]*types.ErrorPage {
prefix := label.Prefix + label.BaseFrontendErrorPage
return label.ParseErrorPages(container.Labels, prefix, label.RegexpFrontendErrorPage)
}
// Label functions // Label functions
func getFuncInt64Label(labelName string, defaultValue int64) func(container dockerData) int64 { func getFuncInt64Label(labelName string, defaultValue int64) func(container dockerData) int64 {

View file

@ -14,7 +14,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestDockerLoadDockerConfig(t *testing.T) { func TestDockerBuildConfiguration(t *testing.T) {
testCases := []struct { testCases := []struct {
containers []docker.ContainerJSON containers []docker.ContainerJSON
expectedFrontends map[string]*types.Frontend expectedFrontends map[string]*types.Frontend
@ -181,6 +181,61 @@ func TestDockerLoadDockerConfig(t *testing.T) {
}, },
}, },
}, },
{
containers: []docker.ContainerJSON{
containerJSON(
name("test1"),
labels(map[string]string{
label.TraefikBackend: "foobar",
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",
}),
ports(nat.PortMap{
"80/tcp": {},
}),
withNetwork("bridge", ipv4("127.0.0.1")),
),
},
expectedFrontends: map[string]*types.Frontend{
"frontend-Host-test1-docker-localhost-0": {
EntryPoints: []string{},
BasicAuth: []string{},
PassHostHeader: true,
Backend: "backend-foobar",
Routes: map[string]types.Route{
"route-frontend-Host-test1-docker-localhost-0": {
Rule: "Host:test1.docker.localhost",
},
},
Errors: map[string]types.ErrorPage{
"foo": {
Status: []string{"404"},
Query: "foo_query",
Backend: "foobar",
},
"bar": {
Status: []string{"500", "600"},
Query: "bar_query",
Backend: "foobar",
},
},
},
},
expectedBackends: map[string]*types.Backend{
"backend-foobar": {
Servers: map[string]types.Server{
"server-test1": {
URL: "http://127.0.0.1:80",
Weight: 0,
},
},
},
},
},
} }
for caseID, test := range testCases { for caseID, test := range testCases {
@ -897,3 +952,59 @@ func TestDockerGetPort(t *testing.T) {
}) })
} }
} }
func TestGetErrorPages(t *testing.T) {
testCases := []struct {
desc string
data dockerData
expected map[string]*types.ErrorPage
}{
{
desc: "2 errors pages",
data: parseContainer(containerJSON(
labels(map[string]string{
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: "404",
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: "foo_backend",
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: "bar_backend",
label.Prefix + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: "bar_query",
}))),
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
Query: "foo_query",
Backend: "foo_backend",
},
"bar": {
Status: []string{"500", "600"},
Query: "bar_query",
Backend: "bar_backend",
},
},
},
{
desc: "only status field",
data: parseContainer(containerJSON(
labels(map[string]string{
label.Prefix + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: "404",
}))),
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pages := getErrorPages(test.data)
assert.EqualValues(t, test.expected, pages)
})
}
}

View file

@ -7,6 +7,7 @@ import (
"github.com/containous/traefik/provider" "github.com/containous/traefik/provider"
"github.com/containous/traefik/provider/label" "github.com/containous/traefik/provider/label"
"github.com/containous/traefik/types"
) )
// Specific functions // Specific functions
@ -50,7 +51,8 @@ func checkServiceLabelPort(container dockerData) error {
} }
// Get only one instance of all service names from service labels // Get only one instance of all service names from service labels
servicesLabelNames := label.ServicesPropertiesRegexp.FindStringSubmatch(lbl) servicesLabelNames := label.ServicesPropertiesRegexp.FindStringSubmatch(lbl)
if len(servicesLabelNames) > 0 {
if len(servicesLabelNames) > 0 && !strings.HasPrefix(lbl, label.TraefikFrontend) {
serviceLabels[strings.Split(servicesLabelNames[0], ".")[1]] = struct{}{} serviceLabels[strings.Split(servicesLabelNames[0], ".")[1]] = struct{}{}
} }
} }
@ -96,6 +98,16 @@ func hasServiceRedirect(container dockerData, serviceName string) bool {
label.Has(serviceLabels, label.SuffixFrontendRedirectRegex) && label.Has(serviceLabels, label.SuffixFrontendRedirectReplacement) label.Has(serviceLabels, label.SuffixFrontendRedirectRegex) && label.Has(serviceLabels, label.SuffixFrontendRedirectReplacement)
} }
func hasServiceErrorPages(container dockerData, serviceName string) bool {
serviceLabels := getServiceLabels(container, serviceName)
return label.HasPrefix(serviceLabels, label.BaseFrontendErrorPage)
}
func getServiceErrorPages(container dockerData, serviceName string) map[string]*types.ErrorPage {
serviceLabels := getServiceLabels(container, serviceName)
return label.ParseErrorPages(serviceLabels, label.BaseFrontendErrorPage, label.RegexpBaseFrontendErrorPage)
}
// Service label functions // Service label functions
func getFuncServiceMapLabel(labelSuffix string) func(container dockerData, serviceName string) map[string]string { func getFuncServiceMapLabel(labelSuffix string) func(container dockerData, serviceName string) map[string]string {

View file

@ -6,6 +6,7 @@ import (
"testing" "testing"
"github.com/containous/traefik/provider/label" "github.com/containous/traefik/provider/label"
"github.com/containous/traefik/types"
docker "github.com/docker/docker/api/types" docker "github.com/docker/docker/api/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -219,3 +220,60 @@ func TestDockerCheckPortLabels(t *testing.T) {
}) })
} }
} }
func TestGetServiceErrorPages(t *testing.T) {
service := "courgette"
testCases := []struct {
desc string
data dockerData
expected map[string]*types.ErrorPage
}{
{
desc: "2 errors pages",
data: parseContainer(containerJSON(
labels(map[string]string{
label.Prefix + service + "." + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageStatus: "404",
label.Prefix + service + "." + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageBackend: "foo_backend",
label.Prefix + service + "." + label.BaseFrontendErrorPage + "foo." + label.SuffixErrorPageQuery: "foo_query",
label.Prefix + service + "." + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageStatus: "500,600",
label.Prefix + service + "." + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageBackend: "bar_backend",
label.Prefix + service + "." + label.BaseFrontendErrorPage + "bar." + label.SuffixErrorPageQuery: "bar_query",
}))),
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
Query: "foo_query",
Backend: "foo_backend",
},
"bar": {
Status: []string{"500", "600"},
Query: "bar_query",
Backend: "bar_backend",
},
},
},
{
desc: "only status field",
data: parseContainer(containerJSON(
labels(map[string]string{
label.Prefix + service + ".frontend.errors.foo.status": "404",
}))),
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pages := getServiceErrorPages(test.data, service)
assert.EqualValues(t, test.expected, pages)
})
}
}

View file

@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/containous/traefik/log" "github.com/containous/traefik/log"
"github.com/containous/traefik/types"
) )
const ( const (
@ -30,12 +31,20 @@ const (
DefaultBackendHealthCheckPort = 0 DefaultBackendHealthCheckPort = 0
) )
// ServicesPropertiesRegexp used to extract the name of the service and the name of the property for this service var (
// All properties are under the format traefik.<servicename>.frontend.*= except the port/portIndex/weight/protocol/backend directly after traefik.<servicename>. // ServicesPropertiesRegexp used to extract the name of the service and the name of the property for this service
var ServicesPropertiesRegexp = regexp.MustCompile(`^traefik\.(?P<service_name>.+?)\.(?P<property_name>port|portIndex|weight|protocol|backend|frontend\.(.+))$`) // All properties are under the format traefik.<servicename>.frontend.*= except the port/portIndex/weight/protocol/backend directly after traefik.<servicename>.
ServicesPropertiesRegexp = regexp.MustCompile(`^traefik\.(?P<service_name>.+?)\.(?P<property_name>port|portIndex|weight|protocol|backend|frontend\.(.+))$`)
// PortRegexp used to extract the port label of the service // PortRegexp used to extract the port label of the service
var PortRegexp = regexp.MustCompile(`^traefik\.(?P<service_name>.+?)\.port$`) PortRegexp = regexp.MustCompile(`^traefik\.(?P<service_name>.+?)\.port$`)
// RegexpBaseFrontendErrorPage used to extract error pages from service's label
RegexpBaseFrontendErrorPage = regexp.MustCompile(`^frontend\.errors\.(?P<name>[^ .]+)\.(?P<field>[^ .]+)$`)
// RegexpFrontendErrorPage used to extract error pages from label
RegexpFrontendErrorPage = regexp.MustCompile(`^traefik\.frontend\.errors\.(?P<name>[^ .]+)\.(?P<field>[^ .]+)$`)
)
// ServicePropertyValues is a map of services properties // ServicePropertyValues is a map of services properties
// an example value is: weight=42 // an example value is: weight=42
@ -200,13 +209,23 @@ func HasP(labels *map[string]string, labelName string) bool {
return Has(*labels, labelName) return Has(*labels, labelName)
} }
// HasPrefix Check if a value is associated to a less one label with a prefix
func HasPrefix(labels map[string]string, prefix string) bool {
for name, value := range labels {
if strings.HasPrefix(name, prefix) && len(value) > 0 {
return true
}
}
return false
}
// ExtractServiceProperties Extract services labels // ExtractServiceProperties Extract services labels
func ExtractServiceProperties(labels map[string]string) ServiceProperties { func ExtractServiceProperties(labels map[string]string) ServiceProperties {
v := make(ServiceProperties) v := make(ServiceProperties)
for name, value := range labels { for name, value := range labels {
matches := ServicesPropertiesRegexp.FindStringSubmatch(name) matches := ServicesPropertiesRegexp.FindStringSubmatch(name)
if matches == nil { if matches == nil || strings.HasPrefix(name, TraefikFrontend) {
continue continue
} }
@ -239,6 +258,43 @@ func ExtractServicePropertiesP(labels *map[string]string) ServiceProperties {
return ExtractServiceProperties(*labels) return ExtractServiceProperties(*labels)
} }
// ParseErrorPages parse error pages to create ErrorPage struct
func ParseErrorPages(labels map[string]string, labelPrefix string, labelRegex *regexp.Regexp) map[string]*types.ErrorPage {
errorPages := make(map[string]*types.ErrorPage)
for lblName, value := range labels {
if strings.HasPrefix(lblName, labelPrefix) {
submatch := labelRegex.FindStringSubmatch(lblName)
if len(submatch) != 3 {
log.Errorf("Invalid page error label: %s, sub-match: %v", lblName, submatch)
continue
}
pageName := submatch[1]
ep, ok := errorPages[pageName]
if !ok {
ep = &types.ErrorPage{}
errorPages[pageName] = ep
}
switch submatch[2] {
case SuffixErrorPageStatus:
ep.Status = SplitAndTrimString(value, ",")
case SuffixErrorPageQuery:
ep.Query = value
case SuffixErrorPageBackend:
ep.Backend = value
default:
log.Errorf("Invalid page error label: %s", lblName)
continue
}
}
}
return errorPages
}
// IsEnabled Check if a container is enabled in Træfik // IsEnabled Check if a container is enabled in Træfik
func IsEnabled(labels map[string]string, exposedByDefault bool) bool { func IsEnabled(labels map[string]string, exposedByDefault bool) bool {
return GetBoolValue(labels, TraefikEnable, exposedByDefault) return GetBoolValue(labels, TraefikEnable, exposedByDefault)

View file

@ -3,6 +3,7 @@ package label
import ( import (
"testing" "testing"
"github.com/containous/traefik/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -739,22 +740,24 @@ func TestExtractServiceProperties(t *testing.T) {
labels: map[string]string{ labels: map[string]string{
"traefik.foo.port": "bar", "traefik.foo.port": "bar",
"traefik.foo.frontend.bar": "1bar", "traefik.foo.frontend.bar": "1bar",
"traefik.foo.frontend.": "2bar", "traefik.foo.backend": "3bar",
}, },
expected: ServiceProperties{ expected: ServiceProperties{
"foo": ServicePropertyValues{ "foo": ServicePropertyValues{
"port": "bar", "port": "bar",
"frontend.bar": "1bar", "frontend.bar": "1bar",
"backend": "3bar",
}, },
}, },
}, },
{ {
desc: "invalid label names", desc: "invalid label names",
labels: map[string]string{ labels: map[string]string{
"foo.frontend.bar": "1bar", "foo.frontend.bar": "1bar",
"traefik.foo.frontend.": "2bar", "traefik.foo.frontend.": "2bar",
"traefik.foo.port.bar": "barbar", "traefik.foo.port.bar": "barbar",
"traefik.foo.frontend": "0bar", "traefik.foo.frontend": "0bar",
"traefik.frontend.foo.backend": "0bar",
}, },
expected: ServiceProperties{}, expected: ServiceProperties{},
}, },
@ -785,22 +788,24 @@ func TestExtractServicePropertiesP(t *testing.T) {
labels: &map[string]string{ labels: &map[string]string{
"traefik.foo.port": "bar", "traefik.foo.port": "bar",
"traefik.foo.frontend.bar": "1bar", "traefik.foo.frontend.bar": "1bar",
"traefik.foo.frontend.": "2bar", "traefik.foo.backend": "3bar",
}, },
expected: ServiceProperties{ expected: ServiceProperties{
"foo": ServicePropertyValues{ "foo": ServicePropertyValues{
"port": "bar", "port": "bar",
"frontend.bar": "1bar", "frontend.bar": "1bar",
"backend": "3bar",
}, },
}, },
}, },
{ {
desc: "invalid label names", desc: "invalid label names",
labels: &map[string]string{ labels: &map[string]string{
"foo.frontend.bar": "1bar", "foo.frontend.bar": "1bar",
"traefik.foo.frontend.": "2bar", "traefik.foo.frontend.": "2bar",
"traefik.foo.port.bar": "barbar", "traefik.foo.port.bar": "barbar",
"traefik.foo.frontend": "0bar", "traefik.foo.frontend": "0bar",
"traefik.frontend.foo.backend": "0bar",
}, },
expected: ServiceProperties{}, expected: ServiceProperties{},
}, },
@ -967,3 +972,112 @@ func TestGetServiceLabel(t *testing.T) {
}) })
} }
} }
func TestHasPrefix(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
prefix string
expected bool
}{
{
desc: "nil labels map",
prefix: "foo",
expected: false,
},
{
desc: "nonexistent prefix",
labels: map[string]string{
"foo.carotte": "bar",
},
prefix: "fii",
expected: false,
},
{
desc: "existent prefix",
labels: map[string]string{
"foo.carotte": "bar",
},
prefix: "foo",
expected: true,
},
{
desc: "existent prefix with empty value",
labels: map[string]string{
"foo.carotte": "",
},
prefix: "foo",
expected: false,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := HasPrefix(test.labels, test.prefix)
assert.Equal(t, test.expected, got)
})
}
}
func TestParseErrorPages(t *testing.T) {
testCases := []struct {
desc string
labels map[string]string
expected map[string]*types.ErrorPage
}{
{
desc: "2 errors pages",
labels: map[string]string{
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageBackend: "foo_backend",
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageQuery: "foo_query",
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageStatus: "500,600",
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageBackend: "bar_backend",
Prefix + BaseFrontendErrorPage + "bar." + SuffixErrorPageQuery: "bar_query",
},
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
Query: "foo_query",
Backend: "foo_backend",
},
"bar": {
Status: []string{"500", "600"},
Query: "bar_query",
Backend: "bar_backend",
},
},
},
{
desc: "only status field",
labels: map[string]string{
Prefix + BaseFrontendErrorPage + "foo." + SuffixErrorPageStatus: "404",
},
expected: map[string]*types.ErrorPage{
"foo": {
Status: []string{"404"},
},
},
},
{
desc: "invalid field",
labels: map[string]string{
Prefix + BaseFrontendErrorPage + "foo." + "courgette": "404",
},
expected: map[string]*types.ErrorPage{"foo": {}},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
pages := ParseErrorPages(test.labels, Prefix+BaseFrontendErrorPage, RegexpFrontendErrorPage)
assert.EqualValues(t, test.expected, pages)
})
}
}

View file

@ -23,6 +23,7 @@ const (
SuffixBackendLoadBalancerStickinessCookieName = "backend.loadbalancer.stickiness.cookieName" SuffixBackendLoadBalancerStickinessCookieName = "backend.loadbalancer.stickiness.cookieName"
SuffixBackendMaxConnAmount = "backend.maxconn.amount" SuffixBackendMaxConnAmount = "backend.maxconn.amount"
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc" SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
SuffixFrontend = "frontend"
SuffixFrontendAuthBasic = "frontend.auth.basic" SuffixFrontendAuthBasic = "frontend.auth.basic"
SuffixFrontendBackend = "frontend.backend" SuffixFrontendBackend = "frontend.backend"
SuffixFrontendEntryPoints = "frontend.entryPoints" SuffixFrontendEntryPoints = "frontend.entryPoints"
@ -76,6 +77,7 @@ const (
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
TraefikFrontend = Prefix + SuffixFrontend
TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic
TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints
TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader
@ -108,4 +110,8 @@ const (
TraefikFrontendPublicKey = Prefix + SuffixFrontendHeadersPublicKey TraefikFrontendPublicKey = Prefix + SuffixFrontendHeadersPublicKey
TraefikFrontendReferrerPolicy = Prefix + SuffixFrontendHeadersReferrerPolicy TraefikFrontendReferrerPolicy = Prefix + SuffixFrontendHeadersReferrerPolicy
TraefikFrontendIsDevelopment = Prefix + SuffixFrontendHeadersIsDevelopment TraefikFrontendIsDevelopment = Prefix + SuffixFrontendHeadersIsDevelopment
BaseFrontendErrorPage = "frontend.errors."
SuffixErrorPageBackend = "backend"
SuffixErrorPageQuery = "query"
SuffixErrorPageStatus = "status"
) )

View file

@ -83,6 +83,18 @@
replacement = "{{getServiceRedirectReplacement $container $serviceName}}" replacement = "{{getServiceRedirectReplacement $container $serviceName}}"
{{end}} {{end}}
{{ if hasServiceErrorPages $container $serviceName }}
[frontends."frontend-{{getServiceBackend $container $serviceName}}".errors]
{{ range $pageName, $page := getServiceErrorPages $container $serviceName }}
[frontends."frontend-{{getServiceBackend $container $serviceName}}".errors.{{$pageName}}]
status = [{{range $page.Status}}
"{{.}}",
{{end}}]
backend = "{{$page.Backend}}"
query = "{{$page.Query}}"
{{end}}
{{end}}
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"] [frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
rule = "{{getServiceFrontendRule $container $serviceName}}" rule = "{{getServiceFrontendRule $container $serviceName}}"
@ -131,6 +143,18 @@
replacement = "{{getRedirectReplacement $container}}" replacement = "{{getRedirectReplacement $container}}"
{{end}} {{end}}
{{ if hasErrorPages $container }}
[frontends."frontend-{{$frontend}}".errors]
{{ range $pageName, $page := getErrorPages $container }}
[frontends."frontend-{{$frontend}}".errors.{{ $pageName }}]
status = [{{range $page.Status}}
"{{.}}",
{{end}}]
backend = "{{$page.Backend}}"
query = "{{$page.Query}}"
{{end}}
{{end}}
[frontends."frontend-{{$frontend}}".headers] [frontends."frontend-{{$frontend}}".headers]
{{if hasSSLRedirectHeaders $container}} {{if hasSSLRedirectHeaders $container}}
SSLRedirect = {{getSSLRedirectHeaders $container}} SSLRedirect = {{getSSLRedirectHeaders $container}}