Support regex redirect by frontend
This commit is contained in:
parent
bddad57a7b
commit
7ecd6d20ba
22 changed files with 405 additions and 195 deletions
|
@ -172,7 +172,6 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
|||
[frontends."frontend-{{getServiceBackend $container $serviceName}}"]
|
||||
backend = "backend-{{getServiceBackend $container $serviceName}}"
|
||||
passHostHeader = {{getServicePassHostHeader $container $serviceName}}
|
||||
redirect = "{{getServiceRedirect $container $serviceName}}"
|
||||
{{if getWhitelistSourceRange $container}}
|
||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||
"{{.}}",
|
||||
|
@ -185,14 +184,21 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
|||
basicAuth = [{{range getServiceBasicAuth $container $serviceName}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
|
||||
|
||||
{{if hasServiceRedirect $container $serviceName}}
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".redirect]
|
||||
entryPoint = "{{getServiceRedirectEntryPoint $container $serviceName}}"
|
||||
regex = "{{getServiceRedirectRegex $container $serviceName}}"
|
||||
replacement = "{{getServiceRedirectReplacement $container $serviceName}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
|
||||
rule = "{{getServiceFrontendRule $container $serviceName}}"
|
||||
{{end}}
|
||||
{{else}}
|
||||
[frontends."frontend-{{$frontend}}"]
|
||||
backend = "backend-{{getBackend $container}}"
|
||||
passHostHeader = {{getPassHostHeader $container}}
|
||||
redirect = "{{getRedirect $container}}"
|
||||
{{if getWhitelistSourceRange $container}}
|
||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||
"{{.}}",
|
||||
|
@ -205,6 +211,14 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
|||
basicAuth = [{{range getBasicAuth $container}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if hasRedirect $container}}
|
||||
[frontends."frontend-{{$frontend}}".redirect]
|
||||
entryPoint = "{{getRedirectEntryPoint $container}}"
|
||||
regex = "{{getRedirectRegex $container}}"
|
||||
replacement = "{{getRedirectReplacement $container}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{$frontend}}".headers]
|
||||
{{if hasSSLRedirectHeaders $container}}
|
||||
SSLRedirect = {{getSSLRedirectHeaders $container}}
|
||||
|
@ -414,13 +428,20 @@ var _templatesKubernetesTmpl = []byte(`[backends]{{range $backendName, $backend
|
|||
backend = "{{$frontend.Backend}}"
|
||||
priority = {{$frontend.Priority}}
|
||||
passHostHeader = {{$frontend.PassHostHeader}}
|
||||
redirect = "{{$frontend.Redirect}}"
|
||||
basicAuth = [{{range $frontend.BasicAuth}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
whitelistSourceRange = [{{range $frontend.WhitelistSourceRange}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if $frontend.Redirect}}
|
||||
[frontends."{{$frontendName}}".redirect]
|
||||
entryPoint = "{{$frontend.RedirectEntryPoint}}"
|
||||
regex = "{{$frontend.RedirectRegex}}"
|
||||
replacement = "{{$frontend.RedirectReplacement}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."{{$frontendName}}".headers]
|
||||
SSLRedirect = {{$frontend.Headers.SSLRedirect}}
|
||||
SSLTemporaryRedirect = {{$frontend.Headers.SSLTemporaryRedirect}}
|
||||
|
@ -752,13 +773,20 @@ var _templatesRancherTmpl = []byte(`{{$backendServers := .Backends}}
|
|||
backend = "backend-{{getBackend $service}}"
|
||||
passHostHeader = {{getPassHostHeader $service}}
|
||||
priority = {{getPriority $service}}
|
||||
redirect = "{{getRedirect $service}}"
|
||||
entryPoints = [{{range getEntryPoints $service}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
basicAuth = [{{range getBasicAuth $service}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if hasRedirect $service}}
|
||||
[frontends."frontend-{{$frontendName}}".redirect]
|
||||
entryPoint = "{{getRedirectEntryPoint $service}}"
|
||||
regex = "{{getRedirectRegex $service}}"
|
||||
replacement = "{{getRedirectReplacement $service}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{$frontendName}}".routes."route-frontend-{{$frontendName}}"]
|
||||
rule = "{{getFrontendRule $service}}"
|
||||
{{end}}
|
||||
|
|
|
@ -57,7 +57,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
|||
Optional: false,
|
||||
},
|
||||
},
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
Replacement: "foo Replacement",
|
||||
Regex: "foo Regex",
|
||||
EntryPoint: "foo EntryPoint",
|
||||
|
@ -103,7 +103,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
|||
Optional: false,
|
||||
},
|
||||
},
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
Replacement: "fii Replacement",
|
||||
Regex: "fii Regex",
|
||||
EntryPoint: "fii EntryPoint",
|
||||
|
|
|
@ -317,9 +317,9 @@ func (ep *EntryPoints) Set(value string) error {
|
|||
Optional: optional,
|
||||
}
|
||||
}
|
||||
var redirect *Redirect
|
||||
var redirect *types.Redirect
|
||||
if len(result["redirect_entrypoint"]) > 0 || len(result["redirect_regex"]) > 0 || len(result["redirect_replacement"]) > 0 {
|
||||
redirect = &Redirect{
|
||||
redirect = &types.Redirect{
|
||||
EntryPoint: result["redirect_entrypoint"],
|
||||
Regex: result["redirect_regex"],
|
||||
Replacement: result["redirect_replacement"],
|
||||
|
@ -422,22 +422,15 @@ func (ep *EntryPoints) Type() string {
|
|||
type EntryPoint struct {
|
||||
Network string
|
||||
Address string
|
||||
TLS *tls.TLS `export:"true"`
|
||||
Redirect *Redirect `export:"true"`
|
||||
Auth *types.Auth `export:"true"`
|
||||
TLS *tls.TLS `export:"true"`
|
||||
Redirect *types.Redirect `export:"true"`
|
||||
Auth *types.Auth `export:"true"`
|
||||
WhitelistSourceRange []string
|
||||
Compress bool `export:"true"`
|
||||
ProxyProtocol *ProxyProtocol `export:"true"`
|
||||
ForwardedHeaders *ForwardedHeaders `export:"true"`
|
||||
}
|
||||
|
||||
// Redirect configures a redirection of an entry point to another, or to an URL
|
||||
type Redirect struct {
|
||||
EntryPoint string
|
||||
Regex string
|
||||
Replacement string
|
||||
}
|
||||
|
||||
// Retry contains request retry config
|
||||
type Retry struct {
|
||||
Attempts int `description:"Number of attempts" export:"true"`
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/provider/file"
|
||||
"github.com/containous/traefik/tls"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -138,7 +139,7 @@ func TestEntryPoints_Set(t *testing.T) {
|
|||
expectedEntryPointName: "foo",
|
||||
expectedEntryPoint: &EntryPoint{
|
||||
Address: ":8000",
|
||||
Redirect: &Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "RedirectEntryPoint",
|
||||
Regex: "RedirectRegex",
|
||||
Replacement: "RedirectReplacement",
|
||||
|
@ -171,7 +172,7 @@ func TestEntryPoints_Set(t *testing.T) {
|
|||
expectedEntryPointName: "foo",
|
||||
expectedEntryPoint: &EntryPoint{
|
||||
Address: ":8000",
|
||||
Redirect: &Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "RedirectEntryPoint",
|
||||
Regex: "RedirectRegex",
|
||||
Replacement: "RedirectReplacement",
|
||||
|
|
|
@ -149,29 +149,33 @@ To enable constraints see [backend-specific constraints section](/configuration/
|
|||
|
||||
Labels can be used on containers to override default behaviour.
|
||||
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
|
||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend. Must be used in conjunction with the below label to take effect. |
|
||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by. Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
||||
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
|
||||
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
|
||||
| `traefik.backend.loadbalancer.swarm=true` | Use Swarm's inbuilt load balancer (only relevant under Swarm Mode). |
|
||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `traefik.port=80` | Register this port. Useful when the container exposes multiples ports. |
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.weight=10` | Assign this weight to the container |
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||
| `traefik.frontend.whitelistSourceRange:RANGE` | List of IP-Ranges which are allowed to access. An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
|
||||
| `traefik.docker.network` | Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect <container_id>`) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name. |
|
||||
| `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||
| Label | Description |
|
||||
|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.backend=foo` | Give the name `foo` to the generated backend for this container. |
|
||||
| `traefik.backend.maxconn.amount=10` | Set a maximum number of connections to the backend. Must be used in conjunction with the below label to take effect. |
|
||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Set the function to be used against the request to determine what to limit maximum connections to the backend by. Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
||||
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
|
||||
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
|
||||
| `traefik.backend.loadbalancer.swarm=true` | Use Swarm's inbuilt load balancer (only relevant under Swarm Mode). |
|
||||
| `traefik.backend.circuitbreaker.expression=EXPR` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `traefik.port=80` | Register this port. Useful when the container exposes multiples ports. |
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.weight=10` | Assign this weight to the container |
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.frontend.rule=EXPR` | Override the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash` |
|
||||
| `traefik.frontend.whitelistSourceRange:RANGE` | List of IP-Ranges which are allowed to access. An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
|
||||
| `traefik.docker.network` | Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect <container_id>`) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name. |
|
||||
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.replacement`. |
|
||||
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.regex`. |
|
||||
|
||||
|
||||
|
||||
#### Security Headers
|
||||
|
||||
|
@ -202,18 +206,21 @@ Labels can be used on containers to override default behaviour.
|
|||
|
||||
Services labels can be used for overriding default behaviour
|
||||
|
||||
| Label | Description |
|
||||
|---------------------------------------------------|--------------------------------------------------------------------------------------------------|
|
||||
| `traefik.<service-name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the service labels could be used. |
|
||||
| `traefik.<service-name>.protocol` | Overrides `traefik.protocol`. |
|
||||
| `traefik.<service-name>.weight` | Assign this service weight. Overrides `traefik.weight`. |
|
||||
| `traefik.<service-name>.frontend.backend=BACKEND` | Assign this service frontend to `BACKEND`. Default is to assign to the service backend. |
|
||||
| `traefik.<service-name>.frontend.entryPoints` | Overrides `traefik.frontend.entrypoints` |
|
||||
| `traefik.<service-name>.frontend.auth.basic` | Sets a Basic Auth for that frontend |
|
||||
| `traefik.<service-name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
|
||||
| `traefik.<service-name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
|
||||
| `traefik.<service-name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
|
||||
| `traefik.<service-name>.frontend.redirect` | Overrides `traefik.frontend.redirect`. |
|
||||
| Label | Description |
|
||||
|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
|
||||
| `traefik.<service-name>.port=PORT` | Overrides `traefik.port`. If several ports need to be exposed, the service labels could be used. |
|
||||
| `traefik.<service-name>.protocol` | Overrides `traefik.protocol`. |
|
||||
| `traefik.<service-name>.weight` | Assign this service weight. Overrides `traefik.weight`. |
|
||||
| `traefik.<service-name>.frontend.backend=BACKEND` | Assign this service frontend to `BACKEND`. Default is to assign to the service backend. |
|
||||
| `traefik.<service-name>.frontend.entryPoints` | Overrides `traefik.frontend.entrypoints` |
|
||||
| `traefik.<service-name>.frontend.auth.basic` | Sets a Basic Auth for that frontend |
|
||||
| `traefik.<service-name>.frontend.passHostHeader` | Overrides `traefik.frontend.passHostHeader`. |
|
||||
| `traefik.<service-name>.frontend.priority` | Overrides `traefik.frontend.priority`. |
|
||||
| `traefik.<service-name>.frontend.rule` | Overrides `traefik.frontend.rule`. |
|
||||
| `traefik.<service-name>.frontend.redirect` | Overrides `traefik.frontend.redirect`. |
|
||||
| `traefik.<service-name>.frontend.redirect.entryPoint=https` | Overrides `traefik.frontend.redirect.entryPoint`. |
|
||||
| `traefik.<service-name>.frontend.redirect.regex=^http://localhost/(.*)` | Overrides `traefik.frontend.redirect.regex`. |
|
||||
| `traefik.<service-name>.frontend.redirect.replacement=http://mydomain/$1` | Overrides `traefik.frontend.redirect.replacement`. |
|
||||
|
||||
|
||||
!!! note
|
||||
|
|
|
@ -102,13 +102,21 @@ Annotations can be used on containers to override default behaviour for the whol
|
|||
Override the default frontend rule type. Default: `PathPrefix`.
|
||||
- `traefik.frontend.priority: "3"`
|
||||
Override the default frontend rule priority.
|
||||
- `traefik.frontend.redirect: https`:
|
||||
- `traefik.frontend.redirect.entryPoint: https`:
|
||||
Enables Redirect to another entryPoint for that frontend (e.g. HTTPS).
|
||||
- `traefik.frontend.redirect.regex: ^http://localhost/(.*)`:
|
||||
Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.replacement`.
|
||||
- `traefik.frontend.redirect.replacement: http://mydomain/$1`:
|
||||
Redirect to another URL for that frontend. Must be set with `traefik.frontend.redirect.regex`.
|
||||
- `traefik.frontend.entryPoints: http,https`
|
||||
Override the default frontend endpoints.
|
||||
- `traefik.frontend.passTLSCert: true`
|
||||
Override the default frontend PassTLSCert value. Default: `false`.
|
||||
|
||||
!!! note
|
||||
Please note that `traefik.frontend.redirect.regex` and `traefik.frontend.redirect.replacement` do not have to be set if `traefik.frontend.redirect.entryPoint` is defined for the redirection (they will not be used in this case).
|
||||
|
||||
|
||||
Annotations can be used on the Kubernetes service to override default behaviour:
|
||||
|
||||
- `traefik.backend.loadbalancer.method=drr`
|
||||
|
|
|
@ -120,19 +120,21 @@ secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|||
|
||||
Labels can be used on task containers to override default behaviour:
|
||||
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------------------|------------------------------------------------------------------------------------------|
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.weight=10` | Assign this weight to the container |
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.frontend.rule=Host:test.traefik.io` | Override the default frontend rule (Default: `Host:{containerName}.{domain}`). |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `traefik.frontend.redirect=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||
| `traefik.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
||||
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
|
||||
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
|
||||
| Label | Description |
|
||||
|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.protocol=https` | Override the default `http` protocol |
|
||||
| `traefik.weight=10` | Assign this weight to the container |
|
||||
| `traefik.enable=false` | Disable this container in Træfik |
|
||||
| `traefik.frontend.rule=Host:test.traefik.io` | Override the default frontend rule (Default: `Host:{containerName}.{domain}`). |
|
||||
| `traefik.frontend.passHostHeader=true` | Forward client `Host` header to the backend. |
|
||||
| `traefik.frontend.priority=10` | Override default frontend priority |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication for that frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint for that frontend (e.g. HTTPS) |
|
||||
| `traefik.frontend.redirect.regex: ^http://localhost/(.*)` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
||||
| `traefik.frontend.redirect.replacement: http://mydomain/$1` | Redirect to another URL for that frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
||||
| `traefik.backend.circuitbreaker.expression=NetworkErrorRatio() > 0.5` | Create a [circuit breaker](/basics/#backends) to be used against the backend |
|
||||
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |
|
||||
| `traefik.backend.loadbalancer.stickiness=true` | Enable backend sticky sessions |
|
||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
|
||||
| `traefik.backend.loadbalancer.sticky=true` | Enable backend sticky sessions (DEPRECATED) |
|
|
@ -42,7 +42,7 @@ const (
|
|||
defaultPassHostHeader = "true"
|
||||
defaultFrontendPriority = "0"
|
||||
defaultCircuitBreakerExpression = "NetworkErrorRatio() > 1"
|
||||
defaultFrontendRedirect = ""
|
||||
defaultFrontendRedirectEntryPoint = ""
|
||||
defaultBackendLoadBalancerMethod = "wrr"
|
||||
defaultBackendMaxconnExtractorfunc = "request.host"
|
||||
)
|
||||
|
@ -276,7 +276,6 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
|||
"getEntryPoints": getFuncSliceStringLabel(types.LabelFrontendEntryPoints),
|
||||
"getBasicAuth": getFuncSliceStringLabel(types.LabelFrontendAuthBasic),
|
||||
"getFrontendRule": p.getFrontendRule,
|
||||
"getRedirect": getFuncStringLabel(types.LabelFrontendRedirect, ""),
|
||||
"hasCircuitBreakerLabel": hasLabel(types.LabelBackendCircuitbreakerExpression),
|
||||
"getCircuitBreakerExpression": getFuncStringLabel(types.LabelBackendCircuitbreakerExpression, defaultCircuitBreakerExpression),
|
||||
"hasLoadBalancerLabel": hasLoadBalancerLabel,
|
||||
|
@ -289,7 +288,6 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
|||
"getStickinessCookieName": getFuncStringLabel(types.LabelBackendLoadbalancerStickinessCookieName, ""),
|
||||
"getIsBackendLBSwarm": getIsBackendLBSwarm,
|
||||
"getServiceBackend": getServiceBackend,
|
||||
"getServiceRedirect": getFuncServiceStringLabel(types.SuffixFrontendRedirect, defaultFrontendRedirect),
|
||||
"getWhitelistSourceRange": getFuncSliceStringLabel(types.LabelTraefikFrontendWhitelistSourceRange),
|
||||
|
||||
"hasRequestHeaders": hasLabel(types.LabelFrontendRequestHeaders),
|
||||
|
@ -343,6 +341,15 @@ func (p *Provider) loadDockerConfig(containersInspected []dockerData) *types.Con
|
|||
"getServiceFrontendRule": p.getServiceFrontendRule,
|
||||
"getServicePassHostHeader": getFuncServiceStringLabel(types.SuffixFrontendPassHostHeader, defaultPassHostHeader),
|
||||
"getServicePriority": getFuncServiceStringLabel(types.SuffixFrontendPriority, defaultFrontendPriority),
|
||||
|
||||
"hasRedirect": hasRedirect,
|
||||
"getRedirectEntryPoint": getFuncStringLabel(types.LabelFrontendRedirectEntryPoint, defaultFrontendRedirectEntryPoint),
|
||||
"getRedirectRegex": getFuncStringLabel(types.LabelFrontendRedirectRegex, ""),
|
||||
"getRedirectReplacement": getFuncStringLabel(types.LabelFrontendRedirectReplacement, ""),
|
||||
"hasServiceRedirect": hasServiceRedirect,
|
||||
"getServiceRedirectEntryPoint": getFuncServiceStringLabel(types.SuffixFrontendRedirectEntryPoint, defaultFrontendRedirectEntryPoint),
|
||||
"getServiceRedirectReplacement": getFuncServiceStringLabel(types.SuffixFrontendRedirectReplacement, ""),
|
||||
"getServiceRedirectRegex": getFuncServiceStringLabel(types.SuffixFrontendRedirectRegex, ""),
|
||||
}
|
||||
// filter containers
|
||||
filteredContainers := fun.Filter(func(container dockerData) bool {
|
||||
|
@ -865,3 +872,26 @@ func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap m
|
|||
}
|
||||
return dockerData
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func hasServiceRedirect(container dockerData, serviceName string) bool {
|
||||
serviceLabels, ok := extractServicesLabels(container.Labels)[serviceName]
|
||||
if !ok || len(serviceLabels) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
value, ok := serviceLabels[types.SuffixFrontendRedirectEntryPoint]
|
||||
frep := ok && len(value) > 0
|
||||
value, ok = serviceLabels[types.SuffixFrontendRedirectRegex]
|
||||
frrg := ok && len(value) > 0
|
||||
value, ok = serviceLabels[types.SuffixFrontendRedirectReplacement]
|
||||
frrp := ok && len(value) > 0
|
||||
|
||||
return frep || frrg && frrp
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func hasRedirect(container dockerData) bool {
|
||||
return hasLabel(types.LabelFrontendRedirectEntryPoint)(container) ||
|
||||
hasLabel(types.LabelFrontendRedirectReplacement)(container) && hasLabel(types.LabelFrontendRedirectRegex)(container)
|
||||
}
|
||||
|
|
|
@ -712,7 +712,6 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
BasicAuth: []string{},
|
||||
Redirect: "",
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test-docker-localhost-0": {
|
||||
Rule: "Host:test.docker.localhost",
|
||||
|
@ -737,10 +736,10 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
containerJSON(
|
||||
name("test1"),
|
||||
labels(map[string]string{
|
||||
types.LabelBackend: "foobar",
|
||||
types.LabelFrontendEntryPoints: "http,https",
|
||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
types.LabelFrontendRedirect: "https",
|
||||
types.LabelBackend: "foobar",
|
||||
types.LabelFrontendEntryPoints: "http,https",
|
||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
types.LabelFrontendRedirectEntryPoint: "https",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -764,7 +763,9 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
Redirect: "https",
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test1-docker-localhost-0": {
|
||||
Rule: "Host:test1.docker.localhost",
|
||||
|
@ -776,7 +777,6 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
BasicAuth: []string{},
|
||||
Redirect: "",
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test2-docker-localhost-1": {
|
||||
Rule: "Host:test2.docker.localhost",
|
||||
|
@ -824,7 +824,6 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
BasicAuth: []string{},
|
||||
Redirect: "",
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test1-docker-localhost-0": {
|
||||
Rule: "Host:test1.docker.localhost",
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/containous/traefik/types"
|
||||
docker "github.com/docker/docker/api/types"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDockerGetServicePort(t *testing.T) {
|
||||
|
@ -136,10 +137,10 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
|||
containerJSON(
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.service.port": "2503",
|
||||
"traefik.service.frontend.entryPoints": "http,https",
|
||||
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
"traefik.service.frontend.redirect": "https",
|
||||
"traefik.service.port": "2503",
|
||||
"traefik.service.frontend.entryPoints": "http,https",
|
||||
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
"traefik.service.frontend.redirect.entryPoint": "https",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -153,7 +154,9 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
Redirect: "https",
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"service-service": {
|
||||
Rule: "Host:foo.docker.localhost",
|
||||
|
@ -178,16 +181,16 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
|||
containerJSON(
|
||||
name("test1"),
|
||||
labels(map[string]string{
|
||||
"traefik.service.port": "2503",
|
||||
"traefik.service.protocol": "https",
|
||||
"traefik.service.weight": "80",
|
||||
"traefik.service.frontend.backend": "foobar",
|
||||
"traefik.service.frontend.passHostHeader": "false",
|
||||
"traefik.service.frontend.rule": "Path:/mypath",
|
||||
"traefik.service.frontend.priority": "5000",
|
||||
"traefik.service.frontend.entryPoints": "http,https,ws",
|
||||
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
"traefik.service.frontend.redirect": "https",
|
||||
"traefik.service.port": "2503",
|
||||
"traefik.service.protocol": "https",
|
||||
"traefik.service.weight": "80",
|
||||
"traefik.service.frontend.backend": "foobar",
|
||||
"traefik.service.frontend.passHostHeader": "false",
|
||||
"traefik.service.frontend.rule": "Path:/mypath",
|
||||
"traefik.service.frontend.priority": "5000",
|
||||
"traefik.service.frontend.entryPoints": "http,https,ws",
|
||||
"traefik.service.frontend.auth.basic": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
"traefik.service.frontend.redirect.entryPoint": "https",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -214,7 +217,9 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
|||
Priority: 5000,
|
||||
EntryPoints: []string{"http", "https", "ws"},
|
||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
Redirect: "https",
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"service-service": {
|
||||
Rule: "Path:/mypath",
|
||||
|
@ -226,7 +231,6 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
BasicAuth: []string{},
|
||||
Redirect: "",
|
||||
Routes: map[string]types.Route{
|
||||
"service-anotherservice": {
|
||||
Rule: "Path:/anotherpath",
|
||||
|
@ -274,9 +278,11 @@ func TestDockerLoadDockerServiceConfig(t *testing.T) {
|
|||
|
||||
actualConfig := provider.loadDockerConfig(dockerDataList)
|
||||
// Compare backends
|
||||
assert.EqualValues(t, test.expectedBackends, actualConfig.Backends)
|
||||
if !reflect.DeepEqual(actualConfig.Backends, test.expectedBackends) {
|
||||
t.Fatalf("expected %#v, got %#v", test.expectedBackends, actualConfig.Backends)
|
||||
}
|
||||
assert.EqualValues(t, test.expectedFrontends, actualConfig.Frontends)
|
||||
if !reflect.DeepEqual(actualConfig.Frontends, test.expectedFrontends) {
|
||||
t.Fatalf("expected %#v, got %#v", test.expectedFrontends, actualConfig.Frontends)
|
||||
}
|
||||
|
|
|
@ -516,7 +516,6 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
BasicAuth: []string{},
|
||||
Redirect: "",
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test-docker-localhost-0": {
|
||||
Rule: "Host:test.docker.localhost",
|
||||
|
@ -547,11 +546,11 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
swarmService(
|
||||
serviceName("test1"),
|
||||
serviceLabels(map[string]string{
|
||||
types.LabelPort: "80",
|
||||
types.LabelBackend: "foobar",
|
||||
types.LabelFrontendEntryPoints: "http,https",
|
||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
types.LabelFrontendRedirect: "https",
|
||||
types.LabelPort: "80",
|
||||
types.LabelBackend: "foobar",
|
||||
types.LabelFrontendEntryPoints: "http,https",
|
||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
types.LabelFrontendRedirectEntryPoint: "https",
|
||||
}),
|
||||
withEndpointSpec(modeVIP),
|
||||
withEndpoint(virtualIP("1", "127.0.0.1/24")),
|
||||
|
@ -572,7 +571,9 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{"http", "https"},
|
||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
Redirect: "https",
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test1-docker-localhost-0": {
|
||||
Rule: "Host:test1.docker.localhost",
|
||||
|
@ -584,7 +585,6 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
|||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
BasicAuth: []string{},
|
||||
Redirect: "",
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test2-docker-localhost-1": {
|
||||
Rule: "Host:test2.docker.localhost",
|
||||
|
|
|
@ -199,8 +199,6 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
|
||||
whitelistSourceRange := getSliceAnnotation(i, annotationKubernetesWhitelistSourceRange)
|
||||
|
||||
entryPointRedirect, _ := i.Annotations[types.LabelFrontendRedirect]
|
||||
|
||||
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
||||
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
||||
if err != nil {
|
||||
|
@ -241,7 +239,7 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
Priority: priority,
|
||||
BasicAuth: basicAuthCreds,
|
||||
WhitelistSourceRange: whitelistSourceRange,
|
||||
Redirect: entryPointRedirect,
|
||||
Redirect: getFrontendRedirect(i),
|
||||
EntryPoints: entryPoints,
|
||||
Headers: headers,
|
||||
}
|
||||
|
@ -492,3 +490,22 @@ func shouldProcessIngress(ingressClass string) bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func getFrontendRedirect(i *v1beta1.Ingress) *types.Redirect {
|
||||
frontendRedirectEntryPoint, ok := i.Annotations[types.LabelFrontendRedirectEntryPoint]
|
||||
frep := ok && len(frontendRedirectEntryPoint) > 0
|
||||
frontendRedirectRegex, ok := i.Annotations[types.LabelFrontendRedirectRegex]
|
||||
frrg := ok && len(frontendRedirectRegex) > 0
|
||||
frontendRedirectReplacement, ok := i.Annotations[types.LabelFrontendRedirectReplacement]
|
||||
frrp := ok && len(frontendRedirectReplacement) > 0
|
||||
|
||||
if frep || frrg && frrp {
|
||||
return &types.Redirect{
|
||||
EntryPoint: frontendRedirectEntryPoint,
|
||||
Regex: frontendRedirectRegex,
|
||||
Replacement: frontendRedirectReplacement,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/client-go/pkg/util/intstr"
|
||||
|
@ -1266,8 +1267,8 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: "testing",
|
||||
Annotations: map[string]string{
|
||||
"kubernetes.io/ingress.class": "traefik",
|
||||
types.LabelFrontendRedirect: "https",
|
||||
"kubernetes.io/ingress.class": "traefik",
|
||||
types.LabelFrontendRedirectEntryPoint: "https",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.IngressSpec{
|
||||
|
@ -1452,7 +1453,6 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
Rule: "Host:foo",
|
||||
},
|
||||
},
|
||||
Redirect: "",
|
||||
},
|
||||
"other/stuff": {
|
||||
Backend: "other/stuff",
|
||||
|
@ -1465,7 +1465,6 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
Rule: "Host:other",
|
||||
},
|
||||
},
|
||||
Redirect: "",
|
||||
},
|
||||
"other/": {
|
||||
Backend: "other/",
|
||||
|
@ -1505,7 +1504,6 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
},
|
||||
},
|
||||
BasicAuth: []string{"myUser:myEncodedPW"},
|
||||
Redirect: "",
|
||||
},
|
||||
"redirect/https": {
|
||||
Backend: "redirect/https",
|
||||
|
@ -1518,7 +1516,9 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
Rule: "Host:redirect",
|
||||
},
|
||||
},
|
||||
Redirect: "https",
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
},
|
||||
|
||||
"test/whitelist-source-range": {
|
||||
|
@ -1536,7 +1536,6 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
Rule: "Host:test",
|
||||
},
|
||||
},
|
||||
Redirect: "",
|
||||
},
|
||||
"rewrite/api": {
|
||||
Backend: "rewrite/api",
|
||||
|
@ -1549,7 +1548,6 @@ func TestIngressAnnotations(t *testing.T) {
|
|||
Rule: "Host:rewrite",
|
||||
},
|
||||
},
|
||||
Redirect: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -2256,6 +2254,7 @@ func TestBasicAuthInTemplate(t *testing.T) {
|
|||
}
|
||||
|
||||
actual = provider.loadConfig(*actual)
|
||||
require.NotNil(t, actual)
|
||||
got := actual.Frontends["basic/auth"].BasicAuth
|
||||
if !reflect.DeepEqual(got, []string{"myUser:myEncodedPW"}) {
|
||||
t.Fatalf("unexpected credentials: %+v", got)
|
||||
|
|
|
@ -76,13 +76,6 @@ func (p *Provider) getBasicAuth(service rancherData) []string {
|
|||
return []string{}
|
||||
}
|
||||
|
||||
func (p *Provider) getRedirect(service rancherData) string {
|
||||
if redirect, err := getServiceLabel(service, types.LabelFrontendRedirect); err == nil {
|
||||
return redirect
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Provider) getFrontendName(service rancherData) string {
|
||||
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
|
||||
return provider.Normalize(p.getFrontendRule(service))
|
||||
|
@ -246,7 +239,10 @@ func (p *Provider) loadRancherConfig(services []rancherData) *types.Configuratio
|
|||
"getSticky": p.getSticky,
|
||||
"hasStickinessLabel": p.hasStickinessLabel,
|
||||
"getStickinessCookieName": p.getStickinessCookieName,
|
||||
"getRedirect": p.getRedirect,
|
||||
"hasRedirect": hasRedirect,
|
||||
"getRedirectEntryPoint": getRedirectEntryPoint,
|
||||
"getRedirectRegex": getRedirectRegex,
|
||||
"getRedirectReplacement": getRedirectReplacement,
|
||||
}
|
||||
|
||||
// filter services
|
||||
|
@ -340,3 +336,42 @@ func isServiceEnabled(service rancherData, exposedByDefault bool) bool {
|
|||
}
|
||||
return exposedByDefault
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func hasRedirect(service rancherData) bool {
|
||||
value, err := getServiceLabel(service, types.LabelFrontendRedirectEntryPoint)
|
||||
frep := err == nil && len(value) > 0
|
||||
value, err = getServiceLabel(service, types.LabelFrontendRedirectRegex)
|
||||
frrg := err == nil && len(value) > 0
|
||||
value, err = getServiceLabel(service, types.LabelFrontendRedirectReplacement)
|
||||
frrp := err == nil && len(value) > 0
|
||||
|
||||
return frep || frrg && frrp
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func getRedirectEntryPoint(service rancherData) string {
|
||||
value, err := getServiceLabel(service, types.LabelFrontendRedirectEntryPoint)
|
||||
if err != nil || len(value) == 0 {
|
||||
return ""
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func getRedirectRegex(service rancherData) string {
|
||||
value, err := getServiceLabel(service, types.LabelFrontendRedirectRegex)
|
||||
if err != nil || len(value) == 0 {
|
||||
return ""
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// TODO will be rewrite when merge on master
|
||||
func getRedirectReplacement(service rancherData) string {
|
||||
value, err := getServiceLabel(service, types.LabelFrontendRedirectReplacement)
|
||||
if err != nil || len(value) == 0 {
|
||||
return ""
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestProviderServiceFilter(t *testing.T) {
|
||||
|
@ -529,44 +530,6 @@ func TestProviderGetPassHostHeader(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProviderGetRedirect(t *testing.T) {
|
||||
provider := &Provider{Domain: "rancher.localhost"}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
service rancherData
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "without label",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
},
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
desc: "with label",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
Labels: map[string]string{
|
||||
types.LabelFrontendRedirect: "https",
|
||||
},
|
||||
},
|
||||
expected: "https",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := provider.getRedirect(test.service)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderGetLabel(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -634,9 +597,9 @@ func TestProviderLoadRancherConfig(t *testing.T) {
|
|||
{
|
||||
Name: "test/service",
|
||||
Labels: map[string]string{
|
||||
types.LabelPort: "80",
|
||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
types.LabelFrontendRedirect: "https",
|
||||
types.LabelPort: "80",
|
||||
types.LabelFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
types.LabelFrontendRedirectEntryPoint: "https",
|
||||
},
|
||||
Health: "healthy",
|
||||
Containers: []string{"127.0.0.1"},
|
||||
|
@ -649,7 +612,9 @@ func TestProviderLoadRancherConfig(t *testing.T) {
|
|||
EntryPoints: []string{},
|
||||
BasicAuth: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
Priority: 0,
|
||||
Redirect: "https",
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
Routes: map[string]types.Route{
|
||||
"route-frontend-Host-test-service-rancher-localhost": {
|
||||
Rule: "Host:test.service.rancher.localhost",
|
||||
|
@ -679,6 +644,7 @@ func TestProviderLoadRancherConfig(t *testing.T) {
|
|||
|
||||
actualConfig := provider.loadRancherConfig(test.services)
|
||||
|
||||
require.NotNil(t, actualConfig)
|
||||
assert.EqualValues(t, test.expectedBackends, actualConfig.Backends)
|
||||
assert.EqualValues(t, test.expectedFrontends, actualConfig.Frontends)
|
||||
})
|
||||
|
@ -732,3 +698,70 @@ func TestProviderHasStickinessLabel(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasRedirect(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
service rancherData
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "without redirect labels",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "with Redirect EntryPoint label",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
Labels: map[string]string{
|
||||
types.LabelFrontendRedirectEntryPoint: "https",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "with Redirect regex label",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
Labels: map[string]string{
|
||||
types.LabelFrontendRedirectRegex: `(.+)`,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "with Redirect replacement label",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
Labels: map[string]string{
|
||||
types.LabelFrontendRedirectReplacement: "$1",
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "with Redirect regex & replacement labels",
|
||||
service: rancherData{
|
||||
Name: "test-service",
|
||||
Labels: map[string]string{
|
||||
types.LabelFrontendRedirectRegex: `(.+)`,
|
||||
types.LabelFrontendRedirectReplacement: "$1",
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual := hasRedirect(test.service)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -944,7 +944,7 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
if entryPoint.Redirect != nil {
|
||||
if redirectHandlers[entryPointName] != nil {
|
||||
n.Use(redirectHandlers[entryPointName])
|
||||
} else if handler, err := s.buildEntryPointRedirect(entryPointName, entryPoint); err != nil {
|
||||
} else if handler, err := s.buildRedirectHandler(entryPointName, entryPoint.Redirect); err != nil {
|
||||
log.Errorf("Error loading entrypoint configuration for frontend %s: %v", frontendName, err)
|
||||
log.Errorf("Skipping frontend %s...", frontendName)
|
||||
continue frontend
|
||||
|
@ -1131,8 +1131,8 @@ func (s *Server) loadConfig(configurations types.Configurations, globalConfigura
|
|||
log.Infof("Configured IP Whitelists: %s", frontend.WhitelistSourceRange)
|
||||
}
|
||||
|
||||
if len(frontend.Redirect) > 0 {
|
||||
rewrite, err := s.buildRedirectRewrite(entryPointName, frontend.Redirect)
|
||||
if frontend.Redirect != nil {
|
||||
rewrite, err := s.buildRedirectHandler(entryPointName, frontend.Redirect)
|
||||
if err != nil {
|
||||
log.Errorf("Error creating Frontend Redirect: %v", err)
|
||||
}
|
||||
|
@ -1287,23 +1287,23 @@ func (s *Server) wireFrontendBackend(serverRoute *serverRoute, handler http.Hand
|
|||
serverRoute.route.Handler(handler)
|
||||
}
|
||||
|
||||
func (s *Server) buildEntryPointRedirect(srcEntryPointName string, entryPoint *configuration.EntryPoint) (*middlewares.Rewrite, error) {
|
||||
if len(entryPoint.Redirect.EntryPoint) > 0 {
|
||||
return s.buildRedirectRewrite(srcEntryPointName, entryPoint.Redirect.EntryPoint)
|
||||
func (s *Server) buildRedirectHandler(srcEntryPointName string, redirect *types.Redirect) (*middlewares.Rewrite, error) {
|
||||
// entry point redirect
|
||||
if len(redirect.EntryPoint) > 0 {
|
||||
return s.buildEntryPointRedirect(srcEntryPointName, redirect.EntryPoint)
|
||||
}
|
||||
|
||||
regex := entryPoint.Redirect.Regex
|
||||
replacement := entryPoint.Redirect.Replacement
|
||||
rewrite, err := middlewares.NewRewrite(regex, replacement, true)
|
||||
// regex redirect
|
||||
rewrite, err := middlewares.NewRewrite(redirect.Regex, redirect.Replacement, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("Creating entryPoint redirect %s -> %s : %s -> %s", srcEntryPointName, entryPoint.Redirect.EntryPoint, regex, replacement)
|
||||
log.Debugf("Creating entryPoint redirect %s -> %s -> %s", srcEntryPointName, redirect.Regex, redirect.Replacement)
|
||||
|
||||
return rewrite, nil
|
||||
}
|
||||
|
||||
func (s *Server) buildRedirectRewrite(srcEntryPointName string, redirectEntryPoint string) (*middlewares.Rewrite, error) {
|
||||
func (s *Server) buildEntryPointRedirect(srcEntryPointName string, redirectEntryPoint string) (*middlewares.Rewrite, error) {
|
||||
regex, replacement, err := s.buildRedirect(redirectEntryPoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -918,15 +918,20 @@ func TestBuildEntryPointRedirect(t *testing.T) {
|
|||
srcEntryPointName string
|
||||
url string
|
||||
entryPoint *configuration.EntryPoint
|
||||
redirect *types.Redirect
|
||||
expectedURL string
|
||||
}{
|
||||
{
|
||||
desc: "redirect regex",
|
||||
srcEntryPointName: "http",
|
||||
url: "http://foo.com",
|
||||
redirect: &types.Redirect{
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)$`,
|
||||
Replacement: "https://$1{{\"bar\"}}$2",
|
||||
},
|
||||
entryPoint: &configuration.EntryPoint{
|
||||
Address: ":80",
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)$`,
|
||||
Replacement: "https://$1{{\"bar\"}}$2",
|
||||
},
|
||||
|
@ -937,9 +942,12 @@ func TestBuildEntryPointRedirect(t *testing.T) {
|
|||
desc: "redirect entry point",
|
||||
srcEntryPointName: "http",
|
||||
url: "http://foo:80",
|
||||
redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
entryPoint: &configuration.EntryPoint{
|
||||
Address: ":80",
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
},
|
||||
},
|
||||
|
@ -949,9 +957,14 @@ func TestBuildEntryPointRedirect(t *testing.T) {
|
|||
desc: "redirect entry point with regex (ignored)",
|
||||
srcEntryPointName: "http",
|
||||
url: "http://foo.com:80",
|
||||
redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)$`,
|
||||
Replacement: "https://$1{{\"bar\"}}$2",
|
||||
},
|
||||
entryPoint: &configuration.EntryPoint{
|
||||
Address: ":80",
|
||||
Redirect: &configuration.Redirect{
|
||||
Redirect: &types.Redirect{
|
||||
EntryPoint: "https",
|
||||
Regex: `^(?:http?:\/\/)(foo)(\.com)$`,
|
||||
Replacement: "https://$1{{\"bar\"}}$2",
|
||||
|
@ -966,7 +979,7 @@ func TestBuildEntryPointRedirect(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rewrite, err := srv.buildEntryPointRedirect(test.srcEntryPointName, test.entryPoint)
|
||||
rewrite, err := srv.buildRedirectHandler(test.srcEntryPointName, test.redirect)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, test.url, nil)
|
||||
|
@ -983,7 +996,7 @@ func TestBuildEntryPointRedirect(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServerBuildRedirectRewrite(t *testing.T) {
|
||||
func TestServerBuildEntryPointRedirect(t *testing.T) {
|
||||
srv := Server{
|
||||
globalConfiguration: configuration.GlobalConfiguration{
|
||||
EntryPoints: configuration.EntryPoints{
|
||||
|
@ -1022,7 +1035,7 @@ func TestServerBuildRedirectRewrite(t *testing.T) {
|
|||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rewrite, err := srv.buildRedirectRewrite(test.srcEntryPointName, test.redirectEntryPoint)
|
||||
rewrite, err := srv.buildEntryPointRedirect(test.srcEntryPointName, test.redirectEntryPoint)
|
||||
if test.errorExpected {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
[frontends."frontend-{{getServiceBackend $container $serviceName}}"]
|
||||
backend = "backend-{{getServiceBackend $container $serviceName}}"
|
||||
passHostHeader = {{getServicePassHostHeader $container $serviceName}}
|
||||
redirect = "{{getServiceRedirect $container $serviceName}}"
|
||||
{{if getWhitelistSourceRange $container}}
|
||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||
"{{.}}",
|
||||
|
@ -60,14 +59,21 @@
|
|||
basicAuth = [{{range getServiceBasicAuth $container $serviceName}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
|
||||
|
||||
{{if hasServiceRedirect $container $serviceName}}
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".redirect]
|
||||
entryPoint = "{{getServiceRedirectEntryPoint $container $serviceName}}"
|
||||
regex = "{{getServiceRedirectRegex $container $serviceName}}"
|
||||
replacement = "{{getServiceRedirectReplacement $container $serviceName}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{getServiceBackend $container $serviceName}}".routes."service-{{$serviceName | replace "/" "" | replace "." "-"}}"]
|
||||
rule = "{{getServiceFrontendRule $container $serviceName}}"
|
||||
{{end}}
|
||||
{{else}}
|
||||
[frontends."frontend-{{$frontend}}"]
|
||||
backend = "backend-{{getBackend $container}}"
|
||||
passHostHeader = {{getPassHostHeader $container}}
|
||||
redirect = "{{getRedirect $container}}"
|
||||
{{if getWhitelistSourceRange $container}}
|
||||
whitelistSourceRange = [{{range getWhitelistSourceRange $container}}
|
||||
"{{.}}",
|
||||
|
@ -80,6 +86,14 @@
|
|||
basicAuth = [{{range getBasicAuth $container}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if hasRedirect $container}}
|
||||
[frontends."frontend-{{$frontend}}".redirect]
|
||||
entryPoint = "{{getRedirectEntryPoint $container}}"
|
||||
regex = "{{getRedirectRegex $container}}"
|
||||
replacement = "{{getRedirectReplacement $container}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{$frontend}}".headers]
|
||||
{{if hasSSLRedirectHeaders $container}}
|
||||
SSLRedirect = {{getSSLRedirectHeaders $container}}
|
||||
|
|
|
@ -25,13 +25,20 @@
|
|||
backend = "{{$frontend.Backend}}"
|
||||
priority = {{$frontend.Priority}}
|
||||
passHostHeader = {{$frontend.PassHostHeader}}
|
||||
redirect = "{{$frontend.Redirect}}"
|
||||
basicAuth = [{{range $frontend.BasicAuth}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
whitelistSourceRange = [{{range $frontend.WhitelistSourceRange}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if $frontend.Redirect}}
|
||||
[frontends."{{$frontendName}}".redirect]
|
||||
entryPoint = "{{$frontend.RedirectEntryPoint}}"
|
||||
regex = "{{$frontend.RedirectRegex}}"
|
||||
replacement = "{{$frontend.RedirectReplacement}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."{{$frontendName}}".headers]
|
||||
SSLRedirect = {{$frontend.Headers.SSLRedirect}}
|
||||
SSLTemporaryRedirect = {{$frontend.Headers.SSLTemporaryRedirect}}
|
||||
|
|
|
@ -34,13 +34,20 @@
|
|||
backend = "backend-{{getBackend $service}}"
|
||||
passHostHeader = {{getPassHostHeader $service}}
|
||||
priority = {{getPriority $service}}
|
||||
redirect = "{{getRedirect $service}}"
|
||||
entryPoints = [{{range getEntryPoints $service}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
basicAuth = [{{range getBasicAuth $service}}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
||||
{{if hasRedirect $service}}
|
||||
[frontends."frontend-{{$frontendName}}".redirect]
|
||||
entryPoint = "{{getRedirectEntryPoint $service}}"
|
||||
regex = "{{getRedirectRegex $service}}"
|
||||
replacement = "{{getRedirectReplacement $service}}"
|
||||
{{end}}
|
||||
|
||||
[frontends."frontend-{{$frontendName}}".routes."route-frontend-{{$frontendName}}"]
|
||||
rule = "{{getFrontendRule $service}}"
|
||||
{{end}}
|
||||
|
|
|
@ -13,7 +13,9 @@ const (
|
|||
SuffixFrontendEntryPoints = "frontend.entryPoints"
|
||||
SuffixFrontendPassHostHeader = "frontend.passHostHeader"
|
||||
SuffixFrontendPriority = "frontend.priority"
|
||||
SuffixFrontendRedirect = "frontend.redirect"
|
||||
SuffixFrontendRedirectEntryPoint = "frontend.redirect.entryPoint"
|
||||
SuffixFrontendRedirectRegex = "frontend.redirect.regex"
|
||||
SuffixFrontendRedirectReplacement = "frontend.redirect.replacement"
|
||||
SuffixFrontendRule = "frontend.rule"
|
||||
LabelDomain = LabelPrefix + "domain"
|
||||
LabelEnable = LabelPrefix + "enable"
|
||||
|
@ -29,7 +31,9 @@ const (
|
|||
LabelFrontendPriority = LabelPrefix + SuffixFrontendPriority
|
||||
LabelFrontendRule = LabelPrefix + SuffixFrontendRule
|
||||
LabelFrontendRuleType = LabelPrefix + "frontend.rule.type"
|
||||
LabelFrontendRedirect = LabelPrefix + SuffixFrontendRedirect
|
||||
LabelFrontendRedirectEntryPoint = LabelPrefix + SuffixFrontendRedirectEntryPoint
|
||||
LabelFrontendRedirectRegex = LabelPrefix + SuffixFrontendRedirectRegex
|
||||
LabelFrontendRedirectReplacement = LabelPrefix + SuffixFrontendRedirectReplacement
|
||||
LabelTraefikFrontendValue = LabelPrefix + "frontend.value"
|
||||
LabelTraefikFrontendWhitelistSourceRange = LabelPrefix + "frontend.whitelistSourceRange"
|
||||
LabelFrontendRequestHeaders = LabelPrefix + "frontend.headers.customRequestHeaders"
|
||||
|
|
|
@ -153,7 +153,14 @@ type Frontend struct {
|
|||
Headers Headers `json:"headers,omitempty"`
|
||||
Errors map[string]ErrorPage `json:"errors,omitempty"`
|
||||
RateLimit *RateLimit `json:"ratelimit,omitempty"`
|
||||
Redirect string `json:"redirect,omitempty"`
|
||||
Redirect *Redirect `json:"redirect,omitempty"`
|
||||
}
|
||||
|
||||
// Redirect configures a redirection of an entry point to another, or to an URL
|
||||
type Redirect struct {
|
||||
EntryPoint string `json:"entryPoint,omitempty"`
|
||||
Regex string `json:"regex,omitempty"`
|
||||
Replacement string `json:"replacement,omitempty"`
|
||||
}
|
||||
|
||||
// LoadBalancerMethod holds the method of load balancing to use.
|
||||
|
|
Loading…
Reference in a new issue