Entry point redirection and default routers configuration
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com> Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
This commit is contained in:
parent
93a7af270f
commit
a6040c623b
46 changed files with 1016 additions and 126 deletions
|
@ -191,7 +191,25 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
|
||||||
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry)
|
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry)
|
||||||
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder)
|
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder)
|
||||||
|
|
||||||
watcher := server.NewConfigurationWatcher(routinesPool, providerAggregator, time.Duration(staticConfiguration.Providers.ProvidersThrottleDuration))
|
var eps []string
|
||||||
|
for name, cfg := range staticConfiguration.EntryPoints {
|
||||||
|
protocol, err := cfg.GetProtocol()
|
||||||
|
if err != nil {
|
||||||
|
// Should never happen because Traefik should not start if protocol is invalid.
|
||||||
|
log.WithoutContext().Errorf("Invalid protocol: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if protocol != "udp" {
|
||||||
|
eps = append(eps, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher := server.NewConfigurationWatcher(
|
||||||
|
routinesPool,
|
||||||
|
providerAggregator,
|
||||||
|
time.Duration(staticConfiguration.Providers.ProvidersThrottleDuration),
|
||||||
|
eps,
|
||||||
|
)
|
||||||
|
|
||||||
watcher.AddListener(func(conf dynamic.Configuration) {
|
watcher.AddListener(func(conf dynamic.Configuration) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
|
@ -387,10 +387,8 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||||
- match: HostRegexp(`{any:.+}`)
|
- match: HostRegexp(`{any:.+}`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
# any service in the namespace
|
# the noop service will be never called
|
||||||
# the service will be never called
|
- name: noop@internal
|
||||||
- name: noop
|
|
||||||
port: 80
|
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: https_redirect
|
- name: https_redirect
|
||||||
# if the Middleware has distinct namespace
|
# if the Middleware has distinct namespace
|
||||||
|
@ -431,13 +429,8 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||||
entryPoints = ["web"]
|
entryPoints = ["web"]
|
||||||
middlewares = ["https_redirect"]
|
middlewares = ["https_redirect"]
|
||||||
rule = "HostRegexp(`{any:.+}`)"
|
rule = "HostRegexp(`{any:.+}`)"
|
||||||
service = "noop"
|
# the noop service will be never called
|
||||||
|
service = "noop@internal"
|
||||||
[http.services]
|
|
||||||
# noop service, the URL will be never called
|
|
||||||
[http.services.noop.loadBalancer]
|
|
||||||
[[http.services.noop.loadBalancer.servers]]
|
|
||||||
url = "http://192.168.0.1:1337"
|
|
||||||
|
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.https_redirect.redirectScheme]
|
[http.middlewares.https_redirect.redirectScheme]
|
||||||
|
@ -472,14 +465,8 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
|
||||||
middlewares:
|
middlewares:
|
||||||
- https_redirect
|
- https_redirect
|
||||||
rule: "HostRegexp(`{any:.+}`)"
|
rule: "HostRegexp(`{any:.+}`)"
|
||||||
service: noop
|
# the noop service will be never called
|
||||||
|
service: noop@internal
|
||||||
services:
|
|
||||||
# noop service, the URL will be never called
|
|
||||||
noop:
|
|
||||||
loadBalancer:
|
|
||||||
servers:
|
|
||||||
- url: http://192.168.0.1:1337
|
|
||||||
|
|
||||||
middlewares:
|
middlewares:
|
||||||
https_redirect:
|
https_redirect:
|
||||||
|
|
|
@ -99,6 +99,36 @@ Trust all forwarded headers. (Default: ```false```)
|
||||||
`--entrypoints.<name>.forwardedheaders.trustedips`:
|
`--entrypoints.<name>.forwardedheaders.trustedips`:
|
||||||
Trust only forwarded headers from selected IPs.
|
Trust only forwarded headers from selected IPs.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http`:
|
||||||
|
HTTP configuration.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.middlewares`:
|
||||||
|
Default middlewares for the routers linked to the entry point.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.redirections.entrypoint.scheme`:
|
||||||
|
Scheme used for the redirection. Defaults to https. (Default: ```https```)
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.redirections.entrypoint.to`:
|
||||||
|
Targeted entry point of the redirection.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.tls`:
|
||||||
|
Default TLS configuration for the routers linked to the entry point. (Default: ```false```)
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.tls.certresolver`:
|
||||||
|
Default certificate resolver for the routers linked to the entry point.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.tls.domains`:
|
||||||
|
Default TLS domains for the routers linked to the entry point.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.tls.domains[n].main`:
|
||||||
|
Default subject name.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.tls.domains[n].sans`:
|
||||||
|
Subject alternative names.
|
||||||
|
|
||||||
|
`--entrypoints.<name>.http.tls.options`:
|
||||||
|
Default TLS options for the routers linked to the entry point.
|
||||||
|
|
||||||
`--entrypoints.<name>.proxyprotocol`:
|
`--entrypoints.<name>.proxyprotocol`:
|
||||||
Proxy-Protocol configuration. (Default: ```false```)
|
Proxy-Protocol configuration. (Default: ```false```)
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,36 @@ Trust all forwarded headers. (Default: ```false```)
|
||||||
`TRAEFIK_ENTRYPOINTS_<NAME>_FORWARDEDHEADERS_TRUSTEDIPS`:
|
`TRAEFIK_ENTRYPOINTS_<NAME>_FORWARDEDHEADERS_TRUSTEDIPS`:
|
||||||
Trust only forwarded headers from selected IPs.
|
Trust only forwarded headers from selected IPs.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP`:
|
||||||
|
HTTP configuration.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_MIDDLEWARES`:
|
||||||
|
Default middlewares for the routers linked to the entry point.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_REDIRECTIONS_ENTRYPOINT_SCHEME`:
|
||||||
|
Scheme used for the redirection. Defaults to https. (Default: ```https```)
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_REDIRECTIONS_ENTRYPOINT_TO`:
|
||||||
|
Targeted entry point of the redirection.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS`:
|
||||||
|
Default TLS configuration for the routers linked to the entry point. (Default: ```false```)
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_CERTRESOLVER`:
|
||||||
|
Default certificate resolver for the routers linked to the entry point.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS`:
|
||||||
|
Default TLS domains for the routers linked to the entry point.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS[n]_MAIN`:
|
||||||
|
Default subject name.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_DOMAINS[n]_SANS`:
|
||||||
|
Subject alternative names.
|
||||||
|
|
||||||
|
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_TLS_OPTIONS`:
|
||||||
|
Default TLS options for the routers linked to the entry point.
|
||||||
|
|
||||||
`TRAEFIK_ENTRYPOINTS_<NAME>_PROXYPROTOCOL`:
|
`TRAEFIK_ENTRYPOINTS_<NAME>_PROXYPROTOCOL`:
|
||||||
Proxy-Protocol configuration. (Default: ```false```)
|
Proxy-Protocol configuration. (Default: ```false```)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,23 @@
|
||||||
[entryPoints.EntryPoint0.forwardedHeaders]
|
[entryPoints.EntryPoint0.forwardedHeaders]
|
||||||
insecure = true
|
insecure = true
|
||||||
trustedIPs = ["foobar", "foobar"]
|
trustedIPs = ["foobar", "foobar"]
|
||||||
|
[entryPoints.EntryPoint0.http]
|
||||||
|
middlewares = ["foobar", "foobar"]
|
||||||
|
[entryPoints.EntryPoint0.http.redirections]
|
||||||
|
[entryPoints.EntryPoint0.http.redirections.entryPoint]
|
||||||
|
to = "foobar"
|
||||||
|
scheme = "foobar"
|
||||||
|
[entryPoints.EntryPoint0.http.tls]
|
||||||
|
options = "foobar"
|
||||||
|
certResolver = "foobar"
|
||||||
|
|
||||||
|
[[entryPoints.EntryPoint0.http.tls.domains]]
|
||||||
|
main = "foobar"
|
||||||
|
sans = ["foobar", "foobar"]
|
||||||
|
|
||||||
|
[[entryPoints.EntryPoint0.http.tls.domains]]
|
||||||
|
main = "foobar"
|
||||||
|
sans = ["foobar", "foobar"]
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
providersThrottleDuration = 42
|
providersThrottleDuration = 42
|
||||||
|
@ -133,10 +150,10 @@
|
||||||
username = "foobar"
|
username = "foobar"
|
||||||
password = "foobar"
|
password = "foobar"
|
||||||
[providers.consul]
|
[providers.consul]
|
||||||
rootKey = "traefik"
|
rootKey = "traefik"
|
||||||
endpoints = ["foobar", "foobar"]
|
endpoints = ["foobar", "foobar"]
|
||||||
username = "foobar"
|
username = "foobar"
|
||||||
password = "foobar"
|
password = "foobar"
|
||||||
[providers.consul.tls]
|
[providers.consul.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
caOptional = true
|
caOptional = true
|
||||||
|
@ -144,10 +161,10 @@
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
[providers.etcd]
|
[providers.etcd]
|
||||||
rootKey = "traefik"
|
rootKey = "traefik"
|
||||||
endpoints = ["foobar", "foobar"]
|
endpoints = ["foobar", "foobar"]
|
||||||
username = "foobar"
|
username = "foobar"
|
||||||
password = "foobar"
|
password = "foobar"
|
||||||
[providers.etcd.tls]
|
[providers.etcd.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
caOptional = true
|
caOptional = true
|
||||||
|
@ -155,10 +172,10 @@
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
[providers.zooKeeper]
|
[providers.zooKeeper]
|
||||||
rootKey = "traefik"
|
rootKey = "traefik"
|
||||||
endpoints = ["foobar", "foobar"]
|
endpoints = ["foobar", "foobar"]
|
||||||
username = "foobar"
|
username = "foobar"
|
||||||
password = "foobar"
|
password = "foobar"
|
||||||
[providers.zooKeeper.tls]
|
[providers.zooKeeper.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
caOptional = true
|
caOptional = true
|
||||||
|
@ -166,10 +183,10 @@
|
||||||
key = "foobar"
|
key = "foobar"
|
||||||
insecureSkipVerify = true
|
insecureSkipVerify = true
|
||||||
[providers.redis]
|
[providers.redis]
|
||||||
rootKey = "traefik"
|
rootKey = "traefik"
|
||||||
endpoints = ["foobar", "foobar"]
|
endpoints = ["foobar", "foobar"]
|
||||||
username = "foobar"
|
username = "foobar"
|
||||||
password = "foobar"
|
password = "foobar"
|
||||||
[providers.redis.tls]
|
[providers.redis.tls]
|
||||||
ca = "foobar"
|
ca = "foobar"
|
||||||
caOptional = true
|
caOptional = true
|
||||||
|
|
|
@ -32,6 +32,26 @@ entryPoints:
|
||||||
trustedIPs:
|
trustedIPs:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
to: foobar
|
||||||
|
scheme: foobar
|
||||||
|
middlewares:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
tls:
|
||||||
|
options: foobar
|
||||||
|
certResolver: foobar
|
||||||
|
domains:
|
||||||
|
- main: foobar
|
||||||
|
sans:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
|
- main: foobar
|
||||||
|
sans:
|
||||||
|
- foobar
|
||||||
|
- foobar
|
||||||
providers:
|
providers:
|
||||||
providersThrottleDuration: 42
|
providersThrottleDuration: 42
|
||||||
docker:
|
docker:
|
||||||
|
@ -142,8 +162,8 @@ providers:
|
||||||
consul:
|
consul:
|
||||||
rootKey: traefik
|
rootKey: traefik
|
||||||
endpoints:
|
endpoints:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
username: foobar
|
username: foobar
|
||||||
password: foobar
|
password: foobar
|
||||||
tls:
|
tls:
|
||||||
|
@ -155,8 +175,8 @@ providers:
|
||||||
etcd:
|
etcd:
|
||||||
rootKey: traefik
|
rootKey: traefik
|
||||||
endpoints:
|
endpoints:
|
||||||
- foobar
|
- foobar
|
||||||
- foobar
|
- foobar
|
||||||
username: foobar
|
username: foobar
|
||||||
password: foobar
|
password: foobar
|
||||||
tls:
|
tls:
|
||||||
|
|
|
@ -529,3 +529,211 @@ If the Proxy Protocol header is passed, then the version is determined automatic
|
||||||
|
|
||||||
When queuing Traefik behind another load-balancer, make sure to configure Proxy Protocol on both sides.
|
When queuing Traefik behind another load-balancer, make sure to configure Proxy Protocol on both sides.
|
||||||
Not doing so could introduce a security risk in your system (enabling request forgery).
|
Not doing so could introduce a security risk in your system (enabling request forgery).
|
||||||
|
|
||||||
|
## HTTP Options
|
||||||
|
|
||||||
|
This whole section is dedicated to options, keyed by entry point, that will apply only to HTTP routing.
|
||||||
|
|
||||||
|
### Redirection
|
||||||
|
|
||||||
|
??? example "HTTPS redirection (80 to 443)"
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[entryPoints.web]
|
||||||
|
address = ":80"
|
||||||
|
|
||||||
|
[entryPoints.web.http]
|
||||||
|
[entryPoints.web.http.redirections]
|
||||||
|
[entryPoints.web.http.redirections.entryPoint]
|
||||||
|
to = "websecure"
|
||||||
|
scheme = "https"
|
||||||
|
|
||||||
|
[entryPoints.websecure]
|
||||||
|
address = ":443"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
entryPoints:
|
||||||
|
web:
|
||||||
|
address: :80
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
to: websecure
|
||||||
|
https: true
|
||||||
|
|
||||||
|
websecure:
|
||||||
|
address: :443
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--entrypoints.web.address=:80
|
||||||
|
--entrypoints.web.http.redirections.entryPoint.to=websecure
|
||||||
|
--entrypoints.web.http.redirections.entryPoint.https=true
|
||||||
|
--entrypoints.websecure.address=:443
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `entryPoint`
|
||||||
|
|
||||||
|
This section is a convenience to enable (permanent) redirecting of all incoming requests on an entry point (e.g. port `80`) to another entry point (e.g. port `443`).
|
||||||
|
|
||||||
|
??? info "`entryPoint.to`"
|
||||||
|
|
||||||
|
_Required_
|
||||||
|
|
||||||
|
The target entry point.
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[entryPoints.foo]
|
||||||
|
# ...
|
||||||
|
[entryPoints.foo.http.redirections]
|
||||||
|
[entryPoints.foo.http.redirections.entryPoint]
|
||||||
|
to = "bar"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
entryPoints:
|
||||||
|
foo:
|
||||||
|
# ...
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
to: bar
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--entrypoints.foo.http.redirections.entryPoint.to=websecure
|
||||||
|
```
|
||||||
|
|
||||||
|
??? info "`entryPoint.scheme`"
|
||||||
|
|
||||||
|
_Optional, Default="http"_
|
||||||
|
|
||||||
|
The redirection target scheme.
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[entryPoints.foo]
|
||||||
|
# ...
|
||||||
|
[entryPoints.foo.http.redirections]
|
||||||
|
[entryPoints.foo.http.redirections.entryPoint]
|
||||||
|
# ...
|
||||||
|
scheme = "https"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
entryPoints:
|
||||||
|
foo:
|
||||||
|
# ...
|
||||||
|
http:
|
||||||
|
redirections:
|
||||||
|
entryPoint:
|
||||||
|
# ...
|
||||||
|
scheme: https
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
--entrypoints.foo.http.redirections.entryPoint.scheme=https
|
||||||
|
```
|
||||||
|
|
||||||
|
### Middlewares
|
||||||
|
|
||||||
|
The list of middlewares that are prepended by default to the list of middlewares of each router associated to the named entry point.
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[entryPoints.websecure]
|
||||||
|
address = ":443"
|
||||||
|
|
||||||
|
[entryPoints.websecure.http]
|
||||||
|
middlewares = ["auth@file", "strip@file"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
entryPoints:
|
||||||
|
websecure:
|
||||||
|
address: ':443'
|
||||||
|
http:
|
||||||
|
middlewares:
|
||||||
|
- auth@file
|
||||||
|
- strip@file
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
entrypoints.websecure.address=:443
|
||||||
|
entrypoints.websecure.http.middlewares=auth@file,strip@file
|
||||||
|
```
|
||||||
|
|
||||||
|
### TLS
|
||||||
|
|
||||||
|
This section is about the default TLS configuration applied to all routers associated with the named entry point.
|
||||||
|
|
||||||
|
If a TLS section (i.e. any of its fields) is user-defined, then the default configuration does not apply at all.
|
||||||
|
|
||||||
|
The TLS section is the same as the [TLS section on HTTP routers](./routers/index.md#tls).
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[entryPoints.websecure]
|
||||||
|
address = ":443"
|
||||||
|
|
||||||
|
[entryPoints.websecure.http.tls]
|
||||||
|
options = "foobar"
|
||||||
|
certResolver = "leresolver"
|
||||||
|
[[entryPoints.websecure.http.tls.domains]]
|
||||||
|
main = "example.com"
|
||||||
|
sans = ["foo.example.com", "bar.example.com"]
|
||||||
|
[[entryPoints.websecure.http.tls.domains]]
|
||||||
|
main = "test.com"
|
||||||
|
sans = ["foo.test.com", "bar.test.com"]
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
entryPoints:
|
||||||
|
websecure:
|
||||||
|
address: ':443'
|
||||||
|
http:
|
||||||
|
tls:
|
||||||
|
options: foobar
|
||||||
|
certResolver: leresolver
|
||||||
|
domains:
|
||||||
|
- main: example.com
|
||||||
|
sans:
|
||||||
|
- foo.example.com
|
||||||
|
- bar.example.com
|
||||||
|
- main: test.com
|
||||||
|
sans:
|
||||||
|
- foo.test.com
|
||||||
|
- bar.test.com
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
entrypoints.websecure.address=:443
|
||||||
|
entrypoints.websecure.http.tls.options=foobar
|
||||||
|
entrypoints.websecure.http.tls.certResolver=leresolver
|
||||||
|
entrypoints.websecure.http.tls.domains[0].main=example.com
|
||||||
|
entrypoints.websecure.http.tls.domains[0].sans=foo.example.com,bar.example.com
|
||||||
|
entrypoints.websecure.http.tls.domains[1].main=test.com
|
||||||
|
entrypoints.websecure.http.tls.domains[1].sans=foo.test.com,bar.test.com
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Let's Encrypt"
|
||||||
|
|
||||||
|
```toml tab="File (TOML)"
|
||||||
|
[entryPoints.websecure]
|
||||||
|
address = ":443"
|
||||||
|
|
||||||
|
[entryPoints.websecure.http.tls]
|
||||||
|
certResolver = "leresolver"
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="File (YAML)"
|
||||||
|
entryPoints:
|
||||||
|
websecure:
|
||||||
|
address: ':443'
|
||||||
|
http:
|
||||||
|
tls:
|
||||||
|
certResolver: leresolver
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash tab="CLI"
|
||||||
|
entrypoints.websecure.address=:443
|
||||||
|
entrypoints.websecure.http.tls.certResolver=leresolver
|
||||||
|
```
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (s *DockerComposeSuite) TestComposeScale(c *check.C) {
|
||||||
|
|
||||||
// check that we have only one service (not counting the internal ones) with n servers
|
// check that we have only one service (not counting the internal ones) with n servers
|
||||||
services := rtconf.Services
|
services := rtconf.Services
|
||||||
c.Assert(services, checker.HasLen, 3)
|
c.Assert(services, checker.HasLen, 4)
|
||||||
for name, service := range services {
|
for name, service := range services {
|
||||||
if strings.HasSuffix(name, "@internal") {
|
if strings.HasSuffix(name, "@internal") {
|
||||||
continue
|
continue
|
||||||
|
|
3
integration/testdata/rawdata-consul.json
vendored
3
integration/testdata/rawdata-consul.json
vendored
|
@ -165,6 +165,9 @@
|
||||||
},
|
},
|
||||||
"status": "enabled"
|
"status": "enabled"
|
||||||
},
|
},
|
||||||
|
"noop@internal": {
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
"simplesvc@consul": {
|
"simplesvc@consul": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
|
|
33
integration/testdata/rawdata-crd.json
vendored
33
integration/testdata/rawdata-crd.json
vendored
|
@ -98,10 +98,10 @@
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.3:80"
|
"url": "http://10.42.0.2:80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.5:80"
|
"url": "http://10.42.0.3:80"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"passHostHeader": true
|
"passHostHeader": true
|
||||||
|
@ -111,18 +111,18 @@
|
||||||
"default-test-route-6b204d94623b3df4370c@kubernetescrd"
|
"default-test-route-6b204d94623b3df4370c@kubernetescrd"
|
||||||
],
|
],
|
||||||
"serverStatus": {
|
"serverStatus": {
|
||||||
"http://10.42.0.3:80": "UP",
|
"http://10.42.0.2:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.3:80": "UP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default-test2-route-23c7f4c450289ee29016@kubernetescrd": {
|
"default-test2-route-23c7f4c450289ee29016@kubernetescrd": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.3:80"
|
"url": "http://10.42.0.2:80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.5:80"
|
"url": "http://10.42.0.3:80"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"passHostHeader": true
|
"passHostHeader": true
|
||||||
|
@ -132,26 +132,26 @@
|
||||||
"default-test2-route-23c7f4c450289ee29016@kubernetescrd"
|
"default-test2-route-23c7f4c450289ee29016@kubernetescrd"
|
||||||
],
|
],
|
||||||
"serverStatus": {
|
"serverStatus": {
|
||||||
"http://10.42.0.3:80": "UP",
|
"http://10.42.0.2:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.3:80": "UP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default-whoami-80@kubernetescrd": {
|
"default-whoami-80@kubernetescrd": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.3:80"
|
"url": "http://10.42.0.2:80"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "http://10.42.0.5:80"
|
"url": "http://10.42.0.3:80"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"passHostHeader": true
|
"passHostHeader": true
|
||||||
},
|
},
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
"serverStatus": {
|
"serverStatus": {
|
||||||
"http://10.42.0.3:80": "UP",
|
"http://10.42.0.2:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.3:80": "UP"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"default-wrr1@kubernetescrd": {
|
"default-wrr1@kubernetescrd": {
|
||||||
|
@ -171,6 +171,9 @@
|
||||||
"usedBy": [
|
"usedBy": [
|
||||||
"default-test3-route-7d0ac22d3d8db4b82618@kubernetescrd"
|
"default-test3-route-7d0ac22d3d8db4b82618@kubernetescrd"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"noop@internal": {
|
||||||
|
"status": "enabled"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcpRouters": {
|
"tcpRouters": {
|
||||||
|
@ -199,7 +202,7 @@
|
||||||
"address": "10.42.0.4:8080"
|
"address": "10.42.0.4:8080"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "10.42.0.6:8080"
|
"address": "10.42.0.8:8080"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -226,10 +229,10 @@
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"address": "10.42.0.4:8090"
|
"address": "10.42.0.10:8090"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "10.42.0.6:8090"
|
"address": "10.42.0.9:8090"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
3
integration/testdata/rawdata-etcd.json
vendored
3
integration/testdata/rawdata-etcd.json
vendored
|
@ -165,6 +165,9 @@
|
||||||
},
|
},
|
||||||
"status": "enabled"
|
"status": "enabled"
|
||||||
},
|
},
|
||||||
|
"noop@internal": {
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
"simplesvc@etcd": {
|
"simplesvc@etcd": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
|
|
11
integration/testdata/rawdata-ingress.json
vendored
11
integration/testdata/rawdata-ingress.json
vendored
|
@ -29,6 +29,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"test-ingress-default-whoami-test-whoami@kubernetes": {
|
"test-ingress-default-whoami-test-whoami@kubernetes": {
|
||||||
|
"entryPoints": [
|
||||||
|
"web",
|
||||||
|
"traefik"
|
||||||
|
],
|
||||||
"service": "default-whoami-http",
|
"service": "default-whoami-http",
|
||||||
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"status": "enabled",
|
"status": "enabled",
|
||||||
|
@ -38,6 +42,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"test-ingress-https-default-whoami-test-https-whoami@kubernetes": {
|
"test-ingress-https-default-whoami-test-https-whoami@kubernetes": {
|
||||||
|
"entryPoints": [
|
||||||
|
"web",
|
||||||
|
"traefik"
|
||||||
|
],
|
||||||
"service": "default-whoami-http",
|
"service": "default-whoami-http",
|
||||||
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",
|
||||||
"tls": {},
|
"tls": {},
|
||||||
|
@ -107,6 +115,9 @@
|
||||||
"http://10.42.0.3:80": "UP",
|
"http://10.42.0.3:80": "UP",
|
||||||
"http://10.42.0.5:80": "UP"
|
"http://10.42.0.5:80": "UP"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"noop@internal": {
|
||||||
|
"status": "enabled"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
3
integration/testdata/rawdata-redis.json
vendored
3
integration/testdata/rawdata-redis.json
vendored
|
@ -165,6 +165,9 @@
|
||||||
},
|
},
|
||||||
"status": "enabled"
|
"status": "enabled"
|
||||||
},
|
},
|
||||||
|
"noop@internal": {
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
"simplesvc@redis": {
|
"simplesvc@redis": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
|
|
3
integration/testdata/rawdata-zk.json
vendored
3
integration/testdata/rawdata-zk.json
vendored
|
@ -165,6 +165,9 @@
|
||||||
},
|
},
|
||||||
"status": "enabled"
|
"status": "enabled"
|
||||||
},
|
},
|
||||||
|
"noop@internal": {
|
||||||
|
"status": "enabled"
|
||||||
|
},
|
||||||
"simplesvc@zookeeper": {
|
"simplesvc@zookeeper": {
|
||||||
"loadBalancer": {
|
"loadBalancer": {
|
||||||
"servers": [
|
"servers": [
|
||||||
|
|
1
pkg/api/testdata/entrypoint-bar.json
vendored
1
pkg/api/testdata/entrypoint-bar.json
vendored
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
"address": ":81",
|
"address": ":81",
|
||||||
|
"http": {},
|
||||||
"name": "bar"
|
"name": "bar"
|
||||||
}
|
}
|
|
@ -1,22 +1,27 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"address": ":14",
|
"address": ":14",
|
||||||
|
"http": {},
|
||||||
"name": "ep14"
|
"name": "ep14"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": ":15",
|
"address": ":15",
|
||||||
|
"http": {},
|
||||||
"name": "ep15"
|
"name": "ep15"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": ":16",
|
"address": ":16",
|
||||||
|
"http": {},
|
||||||
"name": "ep16"
|
"name": "ep16"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": ":17",
|
"address": ":17",
|
||||||
|
"http": {},
|
||||||
"name": "ep17"
|
"name": "ep17"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": ":18",
|
"address": ":18",
|
||||||
|
"http": {},
|
||||||
"name": "ep18"
|
"name": "ep18"
|
||||||
}
|
}
|
||||||
]
|
]
|
1
pkg/api/testdata/entrypoints-page2.json
vendored
1
pkg/api/testdata/entrypoints-page2.json
vendored
|
@ -1,6 +1,7 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"address": ":82",
|
"address": ":82",
|
||||||
|
"http": {},
|
||||||
"name": "web2"
|
"name": "web2"
|
||||||
}
|
}
|
||||||
]
|
]
|
2
pkg/api/testdata/entrypoints.json
vendored
2
pkg/api/testdata/entrypoints.json
vendored
|
@ -8,6 +8,7 @@
|
||||||
"192.168.1.4"
|
"192.168.1.4"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"http": {},
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"proxyProtocol": {
|
"proxyProtocol": {
|
||||||
"insecure": true,
|
"insecure": true,
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
"192.168.1.40"
|
"192.168.1.40"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"http": {},
|
||||||
"name": "websecure",
|
"name": "websecure",
|
||||||
"proxyProtocol": {
|
"proxyProtocol": {
|
||||||
"insecure": true,
|
"insecure": true,
|
||||||
|
|
|
@ -11,8 +11,17 @@ import (
|
||||||
// HTTPConfiguration contains all the HTTP configuration parameters.
|
// HTTPConfiguration contains all the HTTP configuration parameters.
|
||||||
type HTTPConfiguration struct {
|
type HTTPConfiguration struct {
|
||||||
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
|
Routers map[string]*Router `json:"routers,omitempty" toml:"routers,omitempty" yaml:"routers,omitempty"`
|
||||||
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
|
||||||
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
Services map[string]*Service `json:"services,omitempty" toml:"services,omitempty" yaml:"services,omitempty"`
|
||||||
|
Middlewares map[string]*Middleware `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
||||||
|
Models map[string]*Model `json:"models,omitempty" toml:"models,omitempty" yaml:"models,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// Model is a set of default router's values.
|
||||||
|
type Model struct {
|
||||||
|
Middlewares []string `json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
||||||
|
TLS *RouterTLSConfig `json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
|
@ -375,6 +375,21 @@ func (in *HTTPConfiguration) DeepCopyInto(out *HTTPConfiguration) {
|
||||||
(*out)[key] = outVal
|
(*out)[key] = outVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if in.Services != nil {
|
||||||
|
in, out := &in.Services, &out.Services
|
||||||
|
*out = make(map[string]*Service, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
var outVal *Service
|
||||||
|
if val == nil {
|
||||||
|
(*out)[key] = nil
|
||||||
|
} else {
|
||||||
|
in, out := &val, &outVal
|
||||||
|
*out = new(Service)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
(*out)[key] = outVal
|
||||||
|
}
|
||||||
|
}
|
||||||
if in.Middlewares != nil {
|
if in.Middlewares != nil {
|
||||||
in, out := &in.Middlewares, &out.Middlewares
|
in, out := &in.Middlewares, &out.Middlewares
|
||||||
*out = make(map[string]*Middleware, len(*in))
|
*out = make(map[string]*Middleware, len(*in))
|
||||||
|
@ -390,16 +405,16 @@ func (in *HTTPConfiguration) DeepCopyInto(out *HTTPConfiguration) {
|
||||||
(*out)[key] = outVal
|
(*out)[key] = outVal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if in.Services != nil {
|
if in.Models != nil {
|
||||||
in, out := &in.Services, &out.Services
|
in, out := &in.Models, &out.Models
|
||||||
*out = make(map[string]*Service, len(*in))
|
*out = make(map[string]*Model, len(*in))
|
||||||
for key, val := range *in {
|
for key, val := range *in {
|
||||||
var outVal *Service
|
var outVal *Model
|
||||||
if val == nil {
|
if val == nil {
|
||||||
(*out)[key] = nil
|
(*out)[key] = nil
|
||||||
} else {
|
} else {
|
||||||
in, out := &val, &outVal
|
in, out := &val, &outVal
|
||||||
*out = new(Service)
|
*out = new(Model)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
(*out)[key] = outVal
|
(*out)[key] = outVal
|
||||||
|
@ -760,6 +775,32 @@ func (in *Mirroring) DeepCopy() *Mirroring {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Model) DeepCopyInto(out *Model) {
|
||||||
|
*out = *in
|
||||||
|
if in.Middlewares != nil {
|
||||||
|
in, out := &in.Middlewares, &out.Middlewares
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.TLS != nil {
|
||||||
|
in, out := &in.TLS, &out.TLS
|
||||||
|
*out = new(RouterTLSConfig)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Model.
|
||||||
|
func (in *Model) DeepCopy() *Model {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Model)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *PassTLSClientCert) DeepCopyInto(out *PassTLSClientCert) {
|
func (in *PassTLSClientCert) DeepCopyInto(out *PassTLSClientCert) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|
|
@ -21,14 +21,8 @@ func (c *Configuration) GetRoutersByEntryPoints(ctx context.Context, entryPoints
|
||||||
|
|
||||||
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
logger := log.FromContext(log.With(ctx, log.Str(log.RouterName, rtName)))
|
||||||
|
|
||||||
eps := rt.EntryPoints
|
|
||||||
if len(eps) == 0 {
|
|
||||||
logger.Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
|
||||||
eps = entryPoints
|
|
||||||
}
|
|
||||||
|
|
||||||
entryPointsCount := 0
|
entryPointsCount := 0
|
||||||
for _, entryPointName := range eps {
|
for _, entryPointName := range rt.EntryPoints {
|
||||||
if !contains(entryPoints, entryPointName) {
|
if !contains(entryPoints, entryPointName) {
|
||||||
rt.AddError(fmt.Errorf("entryPoint %q doesn't exist", entryPointName), false)
|
rt.AddError(fmt.Errorf("entryPoint %q doesn't exist", entryPointName), false)
|
||||||
logger.WithField(log.EntryPointName, entryPointName).
|
logger.WithField(log.EntryPointName, entryPointName).
|
||||||
|
|
|
@ -3,6 +3,8 @@ package static
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/v2/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EntryPoint holds the entry point configuration.
|
// EntryPoint holds the entry point configuration.
|
||||||
|
@ -11,6 +13,7 @@ type EntryPoint struct {
|
||||||
Transport *EntryPointsTransport `description:"Configures communication between clients and Traefik." json:"transport,omitempty" toml:"transport,omitempty" yaml:"transport,omitempty"`
|
Transport *EntryPointsTransport `description:"Configures communication between clients and Traefik." json:"transport,omitempty" toml:"transport,omitempty" yaml:"transport,omitempty"`
|
||||||
ProxyProtocol *ProxyProtocol `description:"Proxy-Protocol configuration." json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty"`
|
ProxyProtocol *ProxyProtocol `description:"Proxy-Protocol configuration." json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty"`
|
||||||
ForwardedHeaders *ForwardedHeaders `description:"Trust client forwarding headers." json:"forwardedHeaders,omitempty" toml:"forwardedHeaders,omitempty" yaml:"forwardedHeaders,omitempty"`
|
ForwardedHeaders *ForwardedHeaders `description:"Trust client forwarding headers." json:"forwardedHeaders,omitempty" toml:"forwardedHeaders,omitempty" yaml:"forwardedHeaders,omitempty"`
|
||||||
|
HTTP HTTPConfig `description:"HTTP configuration." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAddress strips any potential protocol part of the address field of the
|
// GetAddress strips any potential protocol part of the address field of the
|
||||||
|
@ -43,6 +46,36 @@ func (ep *EntryPoint) SetDefaults() {
|
||||||
ep.ForwardedHeaders = &ForwardedHeaders{}
|
ep.ForwardedHeaders = &ForwardedHeaders{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTPConfig is the HTTP configuration of an entry point.
|
||||||
|
type HTTPConfig struct {
|
||||||
|
Redirections *Redirections `description:"Set of redirection" json:"redirections,omitempty" toml:"redirections,omitempty" yaml:"redirections,omitempty"`
|
||||||
|
Middlewares []string `description:"Default middlewares for the routers linked to the entry point." json:"middlewares,omitempty" toml:"middlewares,omitempty" yaml:"middlewares,omitempty"`
|
||||||
|
TLS *TLSConfig `description:"Default TLS configuration for the routers linked to the entry point." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" label:"allowEmpty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirections is a set of redirection for an entry point.
|
||||||
|
type Redirections struct {
|
||||||
|
EntryPoint *RedirectEntryPoint `description:"Set of redirection for an entry point." json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RedirectEntryPoint is the definition of an entry point redirection.
|
||||||
|
type RedirectEntryPoint struct {
|
||||||
|
To string `description:"Targeted entry point of the redirection." json:"to,omitempty" toml:"to,omitempty" yaml:"to,omitempty"`
|
||||||
|
Scheme string `description:"Scheme used for the redirection. Defaults to https." json:"https,omitempty" toml:"https,omitempty" yaml:"https,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults sets the default values.
|
||||||
|
func (r *RedirectEntryPoint) SetDefaults() {
|
||||||
|
r.Scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSConfig is the default TLS configuration for all the routers associated to the concerned entry point.
|
||||||
|
type TLSConfig struct {
|
||||||
|
Options string `description:"Default TLS options for the routers linked to the entry point." json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty"`
|
||||||
|
CertResolver string `description:"Default certificate resolver for the routers linked to the entry point." json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty"`
|
||||||
|
Domains []types.Domain `description:"Default TLS domains for the routers linked to the entry point." json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// ForwardedHeaders Trust client forwarding headers.
|
// ForwardedHeaders Trust client forwarding headers.
|
||||||
type ForwardedHeaders struct {
|
type ForwardedHeaders struct {
|
||||||
Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
|
Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
|
||||||
|
|
|
@ -41,7 +41,8 @@
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"api": {},
|
"api": {},
|
||||||
"dashboard": {}
|
"dashboard": {},
|
||||||
|
"noop": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"api": {}
|
"api": {},
|
||||||
|
"noop": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
"http": {
|
"http": {
|
||||||
"services": {
|
"services": {
|
||||||
"api": {},
|
"api": {},
|
||||||
"dashboard": {}
|
"dashboard": {},
|
||||||
|
"noop": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"services": {
|
"services": {
|
||||||
"api": {}
|
"api": {},
|
||||||
|
"noop": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tcp": {},
|
"tcp": {},
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
"services": {
|
"services": {
|
||||||
"api": {},
|
"api": {},
|
||||||
"dashboard": {},
|
"dashboard": {},
|
||||||
|
"noop": {},
|
||||||
"ping": {},
|
"ping": {},
|
||||||
"prometheus": {},
|
"prometheus": {},
|
||||||
"rest": {}
|
"rest": {}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"services": {
|
"services": {
|
||||||
"api": {},
|
"api": {},
|
||||||
"dashboard": {},
|
"dashboard": {},
|
||||||
|
"noop": {},
|
||||||
"ping": {},
|
"ping": {},
|
||||||
"prometheus": {},
|
"prometheus": {},
|
||||||
"rest": {}
|
"rest": {}
|
||||||
|
|
36
pkg/provider/traefik/fixtures/models.json
Normal file
36
pkg/provider/traefik/fixtures/models.json
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"http": {
|
||||||
|
"services": {
|
||||||
|
"noop": {}
|
||||||
|
},
|
||||||
|
"models": {
|
||||||
|
"websecure": {
|
||||||
|
"middlewares": [
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"tls": {
|
||||||
|
"options": "opt",
|
||||||
|
"certResolver": "le",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"main": "mainA",
|
||||||
|
"sans": [
|
||||||
|
"sanA1",
|
||||||
|
"sanA2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"main": "mainB",
|
||||||
|
"sans": [
|
||||||
|
"sanB1",
|
||||||
|
"sanB2"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tcp": {},
|
||||||
|
"tls": {}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"services": {
|
"services": {
|
||||||
|
"noop": {},
|
||||||
"ping": {}
|
"ping": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"noop": {},
|
||||||
"ping": {}
|
"ping": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"services": {
|
"services": {
|
||||||
|
"noop": {},
|
||||||
"prometheus": {}
|
"prometheus": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"noop": {},
|
||||||
"prometheus": {}
|
"prometheus": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
30
pkg/provider/traefik/fixtures/redirection.json
Normal file
30
pkg/provider/traefik/fixtures/redirection.json
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"http": {
|
||||||
|
"routers": {
|
||||||
|
"web-to-websecure": {
|
||||||
|
"entryPoints": [
|
||||||
|
"web"
|
||||||
|
],
|
||||||
|
"middlewares": [
|
||||||
|
"redirect-web-to-websecure"
|
||||||
|
],
|
||||||
|
"service": "noop@internal",
|
||||||
|
"rule": "HostRegexp(`{host:.+}`)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"middlewares": {
|
||||||
|
"redirect-web-to-websecure": {
|
||||||
|
"redirectScheme": {
|
||||||
|
"scheme": "https",
|
||||||
|
"port": "443",
|
||||||
|
"permanent": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"services": {
|
||||||
|
"noop": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tcp": {},
|
||||||
|
"tls": {}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
"noop": {},
|
||||||
"rest": {}
|
"rest": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"services": {
|
"services": {
|
||||||
|
"noop": {},
|
||||||
"rest": {}
|
"rest": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package traefik
|
package traefik
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
"github.com/containous/traefik/v2/pkg/config/dynamic"
|
||||||
"github.com/containous/traefik/v2/pkg/config/static"
|
"github.com/containous/traefik/v2/pkg/config/static"
|
||||||
|
"github.com/containous/traefik/v2/pkg/log"
|
||||||
"github.com/containous/traefik/v2/pkg/provider"
|
"github.com/containous/traefik/v2/pkg/provider"
|
||||||
"github.com/containous/traefik/v2/pkg/safe"
|
"github.com/containous/traefik/v2/pkg/safe"
|
||||||
"github.com/containous/traefik/v2/pkg/tls"
|
"github.com/containous/traefik/v2/pkg/tls"
|
||||||
|
@ -43,6 +47,7 @@ func (i *Provider) createConfiguration() *dynamic.Configuration {
|
||||||
Routers: make(map[string]*dynamic.Router),
|
Routers: make(map[string]*dynamic.Router),
|
||||||
Middlewares: make(map[string]*dynamic.Middleware),
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
Services: make(map[string]*dynamic.Service),
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
},
|
},
|
||||||
TCP: &dynamic.TCPConfiguration{
|
TCP: &dynamic.TCPConfiguration{
|
||||||
Routers: make(map[string]*dynamic.TCPRouter),
|
Routers: make(map[string]*dynamic.TCPRouter),
|
||||||
|
@ -58,10 +63,73 @@ func (i *Provider) createConfiguration() *dynamic.Configuration {
|
||||||
i.pingConfiguration(cfg)
|
i.pingConfiguration(cfg)
|
||||||
i.restConfiguration(cfg)
|
i.restConfiguration(cfg)
|
||||||
i.prometheusConfiguration(cfg)
|
i.prometheusConfiguration(cfg)
|
||||||
|
i.entryPointModels(cfg)
|
||||||
|
i.redirection(cfg)
|
||||||
|
|
||||||
|
cfg.HTTP.Services["noop"] = &dynamic.Service{}
|
||||||
|
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Provider) redirection(cfg *dynamic.Configuration) {
|
||||||
|
for name, ep := range i.staticCfg.EntryPoints {
|
||||||
|
if ep.HTTP.Redirections == nil || ep.HTTP.Redirections.EntryPoint == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
def := ep.HTTP.Redirections
|
||||||
|
rtName := provider.Normalize(name + "-to-" + def.EntryPoint.To)
|
||||||
|
mdName := "redirect-" + rtName
|
||||||
|
|
||||||
|
rt := &dynamic.Router{
|
||||||
|
Rule: "HostRegexp(`{host:.+}`)",
|
||||||
|
EntryPoints: []string{name},
|
||||||
|
Middlewares: []string{mdName},
|
||||||
|
Service: "noop@internal",
|
||||||
|
}
|
||||||
|
|
||||||
|
port, err := i.getEntryPointPort(name, def)
|
||||||
|
if err != nil {
|
||||||
|
log.FromContext(context.Background()).WithField(log.EntryPointName, name).Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.HTTP.Routers[rtName] = rt
|
||||||
|
|
||||||
|
rs := &dynamic.Middleware{
|
||||||
|
RedirectScheme: &dynamic.RedirectScheme{
|
||||||
|
Scheme: def.EntryPoint.Scheme,
|
||||||
|
Port: port,
|
||||||
|
Permanent: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.HTTP.Middlewares[mdName] = rs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Provider) entryPointModels(cfg *dynamic.Configuration) {
|
||||||
|
for name, ep := range i.staticCfg.EntryPoints {
|
||||||
|
if len(ep.HTTP.Middlewares) == 0 && ep.HTTP.TLS == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &dynamic.Model{
|
||||||
|
Middlewares: ep.HTTP.Middlewares,
|
||||||
|
}
|
||||||
|
|
||||||
|
if ep.HTTP.TLS != nil {
|
||||||
|
m.TLS = &dynamic.RouterTLSConfig{
|
||||||
|
Options: ep.HTTP.TLS.Options,
|
||||||
|
CertResolver: ep.HTTP.TLS.CertResolver,
|
||||||
|
Domains: ep.HTTP.TLS.Domains,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.HTTP.Models[name] = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Provider) apiConfiguration(cfg *dynamic.Configuration) {
|
func (i *Provider) apiConfiguration(cfg *dynamic.Configuration) {
|
||||||
if i.staticCfg.API == nil {
|
if i.staticCfg.API == nil {
|
||||||
return
|
return
|
||||||
|
@ -163,3 +231,18 @@ func (i *Provider) prometheusConfiguration(cfg *dynamic.Configuration) {
|
||||||
|
|
||||||
cfg.HTTP.Services["prometheus"] = &dynamic.Service{}
|
cfg.HTTP.Services["prometheus"] = &dynamic.Service{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Provider) getEntryPointPort(name string, def *static.Redirections) (string, error) {
|
||||||
|
dst, ok := i.staticCfg.EntryPoints[def.EntryPoint.To]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("'to' entry point field references a non-existing entry point: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, port, err := net.SplitHostPort(dst.Address)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("invalid entry point %q address %q: %v",
|
||||||
|
name, i.staticCfg.EntryPoints[def.EntryPoint.To].Address, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
|
|
@ -167,6 +167,47 @@ func Test_createConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "models.json",
|
||||||
|
staticCfg: static.Configuration{
|
||||||
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
|
"websecure": {
|
||||||
|
HTTP: static.HTTPConfig{
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &static.TLSConfig{
|
||||||
|
Options: "opt",
|
||||||
|
CertResolver: "le",
|
||||||
|
Domains: []types.Domain{
|
||||||
|
{Main: "mainA", SANs: []string{"sanA1", "sanA2"}},
|
||||||
|
{Main: "mainB", SANs: []string{"sanB1", "sanB2"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "redirection.json",
|
||||||
|
staticCfg: static.Configuration{
|
||||||
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
|
"web": {
|
||||||
|
Address: ":80",
|
||||||
|
HTTP: static.HTTPConfig{
|
||||||
|
Redirections: &static.Redirections{
|
||||||
|
EntryPoint: &static.RedirectEntryPoint{
|
||||||
|
To: "websecure",
|
||||||
|
Scheme: "https",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"websecure": {
|
||||||
|
Address: ":443",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
|
|
@ -7,12 +7,13 @@ import (
|
||||||
"github.com/containous/traefik/v2/pkg/tls"
|
"github.com/containous/traefik/v2/pkg/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mergeConfiguration(configurations dynamic.Configurations) dynamic.Configuration {
|
func mergeConfiguration(configurations dynamic.Configurations, entryPoints []string) dynamic.Configuration {
|
||||||
conf := dynamic.Configuration{
|
conf := dynamic.Configuration{
|
||||||
HTTP: &dynamic.HTTPConfiguration{
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
Routers: make(map[string]*dynamic.Router),
|
Routers: make(map[string]*dynamic.Router),
|
||||||
Middlewares: make(map[string]*dynamic.Middleware),
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
Services: make(map[string]*dynamic.Service),
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
},
|
},
|
||||||
TCP: &dynamic.TCPConfiguration{
|
TCP: &dynamic.TCPConfiguration{
|
||||||
Routers: make(map[string]*dynamic.TCPRouter),
|
Routers: make(map[string]*dynamic.TCPRouter),
|
||||||
|
@ -33,6 +34,13 @@ func mergeConfiguration(configurations dynamic.Configurations) dynamic.Configura
|
||||||
for pvd, configuration := range configurations {
|
for pvd, configuration := range configurations {
|
||||||
if configuration.HTTP != nil {
|
if configuration.HTTP != nil {
|
||||||
for routerName, router := range configuration.HTTP.Routers {
|
for routerName, router := range configuration.HTTP.Routers {
|
||||||
|
if len(router.EntryPoints) == 0 {
|
||||||
|
log.WithoutContext().
|
||||||
|
WithField(log.RouterName, routerName).
|
||||||
|
Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
|
||||||
|
router.EntryPoints = entryPoints
|
||||||
|
}
|
||||||
|
|
||||||
conf.HTTP.Routers[provider.MakeQualifiedName(pvd, routerName)] = router
|
conf.HTTP.Routers[provider.MakeQualifiedName(pvd, routerName)] = router
|
||||||
}
|
}
|
||||||
for middlewareName, middleware := range configuration.HTTP.Middlewares {
|
for middlewareName, middleware := range configuration.HTTP.Middlewares {
|
||||||
|
@ -41,6 +49,9 @@ func mergeConfiguration(configurations dynamic.Configurations) dynamic.Configura
|
||||||
for serviceName, service := range configuration.HTTP.Services {
|
for serviceName, service := range configuration.HTTP.Services {
|
||||||
conf.HTTP.Services[provider.MakeQualifiedName(pvd, serviceName)] = service
|
conf.HTTP.Services[provider.MakeQualifiedName(pvd, serviceName)] = service
|
||||||
}
|
}
|
||||||
|
for modelName, model := range configuration.HTTP.Models {
|
||||||
|
conf.HTTP.Models[provider.MakeQualifiedName(pvd, modelName)] = model
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if configuration.TCP != nil {
|
if configuration.TCP != nil {
|
||||||
|
@ -101,3 +112,45 @@ func mergeConfiguration(configurations dynamic.Configurations) dynamic.Configura
|
||||||
|
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
|
||||||
|
if cfg.HTTP == nil || len(cfg.HTTP.Models) == 0 {
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
rts := make(map[string]*dynamic.Router)
|
||||||
|
|
||||||
|
for name, router := range cfg.HTTP.Routers {
|
||||||
|
eps := router.EntryPoints
|
||||||
|
router.EntryPoints = nil
|
||||||
|
|
||||||
|
for _, epName := range eps {
|
||||||
|
m, ok := cfg.HTTP.Models[epName+"@internal"]
|
||||||
|
if ok {
|
||||||
|
cp := router.DeepCopy()
|
||||||
|
|
||||||
|
cp.EntryPoints = []string{epName}
|
||||||
|
|
||||||
|
if cp.TLS == nil {
|
||||||
|
cp.TLS = m.TLS
|
||||||
|
}
|
||||||
|
|
||||||
|
cp.Middlewares = append(m.Middlewares, cp.Middlewares...)
|
||||||
|
|
||||||
|
rtName := name
|
||||||
|
if len(eps) > 1 {
|
||||||
|
rtName = epName + "-" + name
|
||||||
|
}
|
||||||
|
rts[rtName] = cp
|
||||||
|
} else {
|
||||||
|
router.EntryPoints = append(router.EntryPoints, epName)
|
||||||
|
|
||||||
|
rts[name] = router
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.HTTP.Routers = rts
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAggregator(t *testing.T) {
|
func Test_mergeConfiguration(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
given dynamic.Configurations
|
given dynamic.Configurations
|
||||||
|
@ -21,6 +21,7 @@ func TestAggregator(t *testing.T) {
|
||||||
Routers: make(map[string]*dynamic.Router),
|
Routers: make(map[string]*dynamic.Router),
|
||||||
Middlewares: make(map[string]*dynamic.Middleware),
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
Services: make(map[string]*dynamic.Service),
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -42,7 +43,9 @@ func TestAggregator(t *testing.T) {
|
||||||
},
|
},
|
||||||
expected: &dynamic.HTTPConfiguration{
|
expected: &dynamic.HTTPConfiguration{
|
||||||
Routers: map[string]*dynamic.Router{
|
Routers: map[string]*dynamic.Router{
|
||||||
"router-1@provider-1": {},
|
"router-1@provider-1": {
|
||||||
|
EntryPoints: []string{"defaultEP"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{
|
Middlewares: map[string]*dynamic.Middleware{
|
||||||
"middleware-1@provider-1": {},
|
"middleware-1@provider-1": {},
|
||||||
|
@ -50,6 +53,7 @@ func TestAggregator(t *testing.T) {
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
"service-1@provider-1": {},
|
"service-1@provider-1": {},
|
||||||
},
|
},
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -84,8 +88,12 @@ func TestAggregator(t *testing.T) {
|
||||||
},
|
},
|
||||||
expected: &dynamic.HTTPConfiguration{
|
expected: &dynamic.HTTPConfiguration{
|
||||||
Routers: map[string]*dynamic.Router{
|
Routers: map[string]*dynamic.Router{
|
||||||
"router-1@provider-1": {},
|
"router-1@provider-1": {
|
||||||
"router-1@provider-2": {},
|
EntryPoints: []string{"defaultEP"},
|
||||||
|
},
|
||||||
|
"router-1@provider-2": {
|
||||||
|
EntryPoints: []string{"defaultEP"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Middlewares: map[string]*dynamic.Middleware{
|
Middlewares: map[string]*dynamic.Middleware{
|
||||||
"middleware-1@provider-1": {},
|
"middleware-1@provider-1": {},
|
||||||
|
@ -95,6 +103,7 @@ func TestAggregator(t *testing.T) {
|
||||||
"service-1@provider-1": {},
|
"service-1@provider-1": {},
|
||||||
"service-1@provider-2": {},
|
"service-1@provider-2": {},
|
||||||
},
|
},
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -104,13 +113,13 @@ func TestAggregator(t *testing.T) {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
actual := mergeConfiguration(test.given)
|
actual := mergeConfiguration(test.given, []string{"defaultEP"})
|
||||||
assert.Equal(t, test.expected, actual.HTTP)
|
assert.Equal(t, test.expected, actual.HTTP)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAggregator_tlsoptions(t *testing.T) {
|
func Test_mergeConfiguration_tlsOptions(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
given dynamic.Configurations
|
given dynamic.Configurations
|
||||||
|
@ -289,13 +298,13 @@ func TestAggregator_tlsoptions(t *testing.T) {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
actual := mergeConfiguration(test.given)
|
actual := mergeConfiguration(test.given, []string{"defaultEP"})
|
||||||
assert.Equal(t, test.expected, actual.TLS.Options)
|
assert.Equal(t, test.expected, actual.TLS.Options)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAggregator_tlsStore(t *testing.T) {
|
func Test_mergeConfiguration_tlsStore(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
given dynamic.Configurations
|
given dynamic.Configurations
|
||||||
|
@ -381,8 +390,202 @@ func TestAggregator_tlsStore(t *testing.T) {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
actual := mergeConfiguration(test.given)
|
actual := mergeConfiguration(test.given, []string{"defaultEP"})
|
||||||
assert.Equal(t, test.expected, actual.TLS.Stores)
|
assert.Equal(t, test.expected, actual.TLS.Stores)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_applyModel(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
input dynamic.Configuration
|
||||||
|
expected dynamic.Configuration
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "empty configuration",
|
||||||
|
input: dynamic.Configuration{},
|
||||||
|
expected: dynamic.Configuration{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "without model",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: make(map[string]*dynamic.Router),
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: make(map[string]*dynamic.Router),
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: make(map[string]*dynamic.Model),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "with model, not used",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: make(map[string]*dynamic.Router),
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"ep@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: make(map[string]*dynamic.Router),
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"ep@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "with model, one entry point",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "with model, one entry point, and router with tls",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{CertResolver: "router"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{CertResolver: "ep"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{CertResolver: "router"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{CertResolver: "ep"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "with model, two entry points",
|
||||||
|
input: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
EntryPoints: []string{"websecure", "web"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: dynamic.Configuration{
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"test": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
},
|
||||||
|
"websecure-test": {
|
||||||
|
EntryPoints: []string{"websecure"},
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: make(map[string]*dynamic.Middleware),
|
||||||
|
Services: make(map[string]*dynamic.Service),
|
||||||
|
Models: map[string]*dynamic.Model{
|
||||||
|
"websecure@internal": {
|
||||||
|
Middlewares: []string{"test"},
|
||||||
|
TLS: &dynamic.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
actual := applyModel(test.input)
|
||||||
|
|
||||||
|
assert.Equal(t, test.expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ import (
|
||||||
type ConfigurationWatcher struct {
|
type ConfigurationWatcher struct {
|
||||||
provider provider.Provider
|
provider provider.Provider
|
||||||
|
|
||||||
|
entryPoints []string
|
||||||
|
|
||||||
providersThrottleDuration time.Duration
|
providersThrottleDuration time.Duration
|
||||||
|
|
||||||
currentConfigurations safe.Safe
|
currentConfigurations safe.Safe
|
||||||
|
@ -32,7 +34,12 @@ type ConfigurationWatcher struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfigurationWatcher creates a new ConfigurationWatcher.
|
// NewConfigurationWatcher creates a new ConfigurationWatcher.
|
||||||
func NewConfigurationWatcher(routinesPool *safe.Pool, pvd provider.Provider, providersThrottleDuration time.Duration) *ConfigurationWatcher {
|
func NewConfigurationWatcher(
|
||||||
|
routinesPool *safe.Pool,
|
||||||
|
pvd provider.Provider,
|
||||||
|
providersThrottleDuration time.Duration,
|
||||||
|
entryPoints []string,
|
||||||
|
) *ConfigurationWatcher {
|
||||||
watcher := &ConfigurationWatcher{
|
watcher := &ConfigurationWatcher{
|
||||||
provider: pvd,
|
provider: pvd,
|
||||||
configurationChan: make(chan dynamic.Message, 100),
|
configurationChan: make(chan dynamic.Message, 100),
|
||||||
|
@ -40,6 +47,7 @@ func NewConfigurationWatcher(routinesPool *safe.Pool, pvd provider.Provider, pro
|
||||||
providerConfigUpdateMap: make(map[string]chan dynamic.Message),
|
providerConfigUpdateMap: make(map[string]chan dynamic.Message),
|
||||||
providersThrottleDuration: providersThrottleDuration,
|
providersThrottleDuration: providersThrottleDuration,
|
||||||
routinesPool: routinesPool,
|
routinesPool: routinesPool,
|
||||||
|
entryPoints: entryPoints,
|
||||||
}
|
}
|
||||||
|
|
||||||
currentConfigurations := make(dynamic.Configurations)
|
currentConfigurations := make(dynamic.Configurations)
|
||||||
|
@ -135,7 +143,8 @@ func (c *ConfigurationWatcher) loadMessage(configMsg dynamic.Message) {
|
||||||
|
|
||||||
c.currentConfigurations.Set(newConfigurations)
|
c.currentConfigurations.Set(newConfigurations)
|
||||||
|
|
||||||
conf := mergeConfiguration(newConfigurations)
|
conf := mergeConfiguration(newConfigurations, c.entryPoints)
|
||||||
|
conf = applyModel(conf)
|
||||||
|
|
||||||
for _, listener := range c.configurationListeners {
|
for _, listener := range c.configurationListeners {
|
||||||
listener(conf)
|
listener(conf)
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestNewConfigurationWatcher(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher := NewConfigurationWatcher(routinesPool, pvd, time.Second)
|
watcher := NewConfigurationWatcher(routinesPool, pvd, time.Second, []string{})
|
||||||
|
|
||||||
run := make(chan struct{})
|
run := make(chan struct{})
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ func TestListenProvidersThrottleProviderConfigReload(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher := NewConfigurationWatcher(routinesPool, pvd, 30*time.Millisecond)
|
watcher := NewConfigurationWatcher(routinesPool, pvd, 30*time.Millisecond, []string{})
|
||||||
|
|
||||||
publishedConfigCount := 0
|
publishedConfigCount := 0
|
||||||
watcher.AddListener(func(_ dynamic.Configuration) {
|
watcher.AddListener(func(_ dynamic.Configuration) {
|
||||||
|
@ -136,7 +136,7 @@ func TestListenProvidersSkipsEmptyConfigs(t *testing.T) {
|
||||||
messages: []dynamic.Message{{ProviderName: "mock"}},
|
messages: []dynamic.Message{{ProviderName: "mock"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher := NewConfigurationWatcher(routinesPool, pvd, time.Second)
|
watcher := NewConfigurationWatcher(routinesPool, pvd, time.Second, []string{})
|
||||||
watcher.AddListener(func(_ dynamic.Configuration) {
|
watcher.AddListener(func(_ dynamic.Configuration) {
|
||||||
t.Error("An empty configuration was published but it should not")
|
t.Error("An empty configuration was published but it should not")
|
||||||
})
|
})
|
||||||
|
@ -162,7 +162,7 @@ func TestListenProvidersSkipsSameConfigurationForProvider(t *testing.T) {
|
||||||
messages: []dynamic.Message{message, message},
|
messages: []dynamic.Message{message, message},
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher := NewConfigurationWatcher(routinesPool, pvd, 0)
|
watcher := NewConfigurationWatcher(routinesPool, pvd, 0, []string{})
|
||||||
|
|
||||||
alreadyCalled := false
|
alreadyCalled := false
|
||||||
watcher.AddListener(func(_ dynamic.Configuration) {
|
watcher.AddListener(func(_ dynamic.Configuration) {
|
||||||
|
@ -205,7 +205,7 @@ func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher := NewConfigurationWatcher(routinesPool, pvd, 15*time.Millisecond)
|
watcher := NewConfigurationWatcher(routinesPool, pvd, 15*time.Millisecond, []string{"defaultEP"})
|
||||||
|
|
||||||
var lastConfig dynamic.Configuration
|
var lastConfig dynamic.Configuration
|
||||||
watcher.AddListener(func(conf dynamic.Configuration) {
|
watcher.AddListener(func(conf dynamic.Configuration) {
|
||||||
|
@ -220,7 +220,7 @@ func TestListenProvidersDoesNotSkipFlappingConfiguration(t *testing.T) {
|
||||||
|
|
||||||
expected := dynamic.Configuration{
|
expected := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo@mock")),
|
th.WithRouters(th.WithRouter("foo@mock", th.WithEntryPoints("defaultEP"))),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
th.WithLoadBalancerServices(th.WithService("bar@mock")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
@ -260,7 +260,7 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher := NewConfigurationWatcher(routinesPool, pvd, 0)
|
watcher := NewConfigurationWatcher(routinesPool, pvd, 0, []string{"defaultEP"})
|
||||||
|
|
||||||
var publishedProviderConfig dynamic.Configuration
|
var publishedProviderConfig dynamic.Configuration
|
||||||
|
|
||||||
|
@ -276,7 +276,10 @@ func TestListenProvidersPublishesConfigForEachProvider(t *testing.T) {
|
||||||
|
|
||||||
expected := dynamic.Configuration{
|
expected := dynamic.Configuration{
|
||||||
HTTP: th.BuildConfiguration(
|
HTTP: th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo@mock"), th.WithRouter("foo@mock2")),
|
th.WithRouters(
|
||||||
|
th.WithRouter("foo@mock", th.WithEntryPoints("defaultEP")),
|
||||||
|
th.WithRouter("foo@mock2", th.WithEntryPoints("defaultEP")),
|
||||||
|
),
|
||||||
th.WithLoadBalancerServices(th.WithService("bar@mock"), th.WithService("bar@mock2")),
|
th.WithLoadBalancerServices(th.WithService("bar@mock"), th.WithService("bar@mock2")),
|
||||||
th.WithMiddlewares(),
|
th.WithMiddlewares(),
|
||||||
),
|
),
|
||||||
|
|
|
@ -76,28 +76,6 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
entryPoints: []string{"web"},
|
entryPoints: []string{"web"},
|
||||||
expected: expectedResult{StatusCode: http.StatusNotFound},
|
expected: expectedResult{StatusCode: http.StatusNotFound},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
desc: "no middleware, default entry point",
|
|
||||||
routersConfig: map[string]*dynamic.Router{
|
|
||||||
"foo": {
|
|
||||||
Service: "foo-service",
|
|
||||||
Rule: "Host(`foo.bar`)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
serviceConfig: map[string]*dynamic.Service{
|
|
||||||
"foo-service": {
|
|
||||||
LoadBalancer: &dynamic.ServersLoadBalancer{
|
|
||||||
Servers: []dynamic.Server{
|
|
||||||
{
|
|
||||||
URL: server.URL,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
entryPoints: []string{"web"},
|
|
||||||
expected: expectedResult{StatusCode: http.StatusOK},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
desc: "no middleware, no matching",
|
desc: "no middleware, no matching",
|
||||||
routersConfig: map[string]*dynamic.Router{
|
routersConfig: map[string]*dynamic.Router{
|
||||||
|
@ -735,6 +713,14 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
func TestProviderOnMiddlewares(t *testing.T) {
|
func TestProviderOnMiddlewares(t *testing.T) {
|
||||||
entryPoints := []string{"web"}
|
entryPoints := []string{"web"}
|
||||||
|
|
||||||
|
staticCfg := static.Configuration{
|
||||||
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
|
"web": {
|
||||||
|
Address: ":80",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
rtConf := runtime.NewConfig(dynamic.Configuration{
|
rtConf := runtime.NewConfig(dynamic.Configuration{
|
||||||
HTTP: &dynamic.HTTPConfiguration{
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
Services: map[string]*dynamic.Service{
|
Services: map[string]*dynamic.Service{
|
||||||
|
@ -746,11 +732,13 @@ func TestProviderOnMiddlewares(t *testing.T) {
|
||||||
},
|
},
|
||||||
Routers: map[string]*dynamic.Router{
|
Routers: map[string]*dynamic.Router{
|
||||||
"router@file": {
|
"router@file": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
Rule: "Host(`test`)",
|
Rule: "Host(`test`)",
|
||||||
Service: "test@file",
|
Service: "test@file",
|
||||||
Middlewares: []string{"chain@file", "m1"},
|
Middlewares: []string{"chain@file", "m1"},
|
||||||
},
|
},
|
||||||
"router@docker": {
|
"router@docker": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
Rule: "Host(`test`)",
|
Rule: "Host(`test`)",
|
||||||
Service: "test@file",
|
Service: "test@file",
|
||||||
Middlewares: []string{"chain", "m1@file"},
|
Middlewares: []string{"chain", "m1@file"},
|
||||||
|
@ -774,7 +762,7 @@ func TestProviderOnMiddlewares(t *testing.T) {
|
||||||
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
|
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
||||||
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{})
|
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{})
|
||||||
chainBuilder := middleware.NewChainBuilder(static.Configuration{}, nil, nil)
|
chainBuilder := middleware.NewChainBuilder(staticCfg, nil, nil)
|
||||||
|
|
||||||
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
|
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory, chainBuilder)
|
||||||
|
|
||||||
|
|
|
@ -23,17 +23,18 @@ func TestReuseService(t *testing.T) {
|
||||||
|
|
||||||
staticConfig := static.Configuration{
|
staticConfig := static.Configuration{
|
||||||
EntryPoints: map[string]*static.EntryPoint{
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
"http": {},
|
"web": {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamicConfigs := th.BuildConfiguration(
|
dynamicConfigs := th.BuildConfiguration(
|
||||||
th.WithRouters(
|
th.WithRouters(
|
||||||
th.WithRouter("foo",
|
th.WithRouter("foo",
|
||||||
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRule("Path(`/ok`)")),
|
th.WithRule("Path(`/ok`)")),
|
||||||
th.WithRouter("foo2",
|
th.WithRouter("foo2",
|
||||||
th.WithEntryPoints("http"),
|
th.WithEntryPoints("web"),
|
||||||
th.WithRule("Path(`/unauthorized`)"),
|
th.WithRule("Path(`/unauthorized`)"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRouterMiddlewares("basicauth")),
|
th.WithRouterMiddlewares("basicauth")),
|
||||||
|
@ -56,7 +57,7 @@ func TestReuseService(t *testing.T) {
|
||||||
// Test that the /ok path returns a status 200.
|
// Test that the /ok path returns a status 200.
|
||||||
responseRecorderOk := &httptest.ResponseRecorder{}
|
responseRecorderOk := &httptest.ResponseRecorder{}
|
||||||
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/ok", nil)
|
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/ok", nil)
|
||||||
entryPointsHandlers["http"].GetHTTPHandler().ServeHTTP(responseRecorderOk, requestOk)
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorderOk, requestOk)
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ func TestReuseService(t *testing.T) {
|
||||||
// the basic authentication defined on the frontend.
|
// the basic authentication defined on the frontend.
|
||||||
responseRecorderUnauthorized := &httptest.ResponseRecorder{}
|
responseRecorderUnauthorized := &httptest.ResponseRecorder{}
|
||||||
requestUnauthorized := httptest.NewRequest(http.MethodGet, testServer.URL+"/unauthorized", nil)
|
requestUnauthorized := httptest.NewRequest(http.MethodGet, testServer.URL+"/unauthorized", nil)
|
||||||
entryPointsHandlers["http"].GetHTTPHandler().ServeHTTP(responseRecorderUnauthorized, requestUnauthorized)
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorderUnauthorized, requestUnauthorized)
|
||||||
|
|
||||||
assert.Equal(t, http.StatusUnauthorized, responseRecorderUnauthorized.Result().StatusCode, "status code")
|
assert.Equal(t, http.StatusUnauthorized, responseRecorderUnauthorized.Result().StatusCode, "status code")
|
||||||
}
|
}
|
||||||
|
@ -83,7 +84,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
||||||
return th.BuildConfiguration(
|
return th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo",
|
th.WithRouters(th.WithRouter("foo",
|
||||||
th.WithEntryPoints("http"),
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
|
@ -106,7 +107,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
||||||
return th.BuildConfiguration(
|
return th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo",
|
th.WithRouters(th.WithRouter("foo",
|
||||||
th.WithEntryPoints("http"),
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
|
@ -120,7 +121,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
||||||
return th.BuildConfiguration(
|
return th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo",
|
th.WithRouters(th.WithRouter("foo",
|
||||||
th.WithEntryPoints("http"),
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
|
@ -136,7 +137,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
||||||
return th.BuildConfiguration(
|
return th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo",
|
th.WithRouters(th.WithRouter("foo",
|
||||||
th.WithEntryPoints("http"),
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
|
@ -150,7 +151,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
config: func(testServerURL string) *dynamic.HTTPConfiguration {
|
||||||
return th.BuildConfiguration(
|
return th.BuildConfiguration(
|
||||||
th.WithRouters(th.WithRouter("foo",
|
th.WithRouters(th.WithRouter("foo",
|
||||||
th.WithEntryPoints("http"),
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("bar"),
|
th.WithServiceName("bar"),
|
||||||
th.WithRule(routeRule)),
|
th.WithRule(routeRule)),
|
||||||
),
|
),
|
||||||
|
@ -176,7 +177,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
|
|
||||||
staticConfig := static.Configuration{
|
staticConfig := static.Configuration{
|
||||||
EntryPoints: map[string]*static.EntryPoint{
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
"http": {},
|
"web": {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +191,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
|
||||||
responseRecorder := &httptest.ResponseRecorder{}
|
responseRecorder := &httptest.ResponseRecorder{}
|
||||||
request := httptest.NewRequest(http.MethodGet, testServer.URL+requestPath, nil)
|
request := httptest.NewRequest(http.MethodGet, testServer.URL+requestPath, nil)
|
||||||
|
|
||||||
entryPointsHandlers["http"].GetHTTPHandler().ServeHTTP(responseRecorder, request)
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorder, request)
|
||||||
|
|
||||||
assert.Equal(t, test.expectedStatusCode, responseRecorder.Result().StatusCode, "status code")
|
assert.Equal(t, test.expectedStatusCode, responseRecorder.Result().StatusCode, "status code")
|
||||||
})
|
})
|
||||||
|
@ -206,13 +207,14 @@ func TestInternalServices(t *testing.T) {
|
||||||
staticConfig := static.Configuration{
|
staticConfig := static.Configuration{
|
||||||
API: &static.API{},
|
API: &static.API{},
|
||||||
EntryPoints: map[string]*static.EntryPoint{
|
EntryPoints: map[string]*static.EntryPoint{
|
||||||
"http": {},
|
"web": {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamicConfigs := th.BuildConfiguration(
|
dynamicConfigs := th.BuildConfiguration(
|
||||||
th.WithRouters(
|
th.WithRouters(
|
||||||
th.WithRouter("foo",
|
th.WithRouter("foo",
|
||||||
|
th.WithEntryPoints("web"),
|
||||||
th.WithServiceName("api@internal"),
|
th.WithServiceName("api@internal"),
|
||||||
th.WithRule("PathPrefix(`/api`)")),
|
th.WithRule("PathPrefix(`/api`)")),
|
||||||
),
|
),
|
||||||
|
@ -228,7 +230,7 @@ func TestInternalServices(t *testing.T) {
|
||||||
// Test that the /ok path returns a status 200.
|
// Test that the /ok path returns a status 200.
|
||||||
responseRecorderOk := &httptest.ResponseRecorder{}
|
responseRecorderOk := &httptest.ResponseRecorder{}
|
||||||
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/api/rawdata", nil)
|
requestOk := httptest.NewRequest(http.MethodGet, testServer.URL+"/api/rawdata", nil)
|
||||||
entryPointsHandlers["http"].GetHTTPHandler().ServeHTTP(responseRecorderOk, requestOk)
|
entryPointsHandlers["web"].GetHTTPHandler().ServeHTTP(responseRecorderOk, requestOk)
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
assert.Equal(t, http.StatusOK, responseRecorderOk.Result().StatusCode, "status code")
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,11 @@ func (m *InternalHandlers) BuildHTTP(rootCtx context.Context, serviceName string
|
||||||
|
|
||||||
func (m *InternalHandlers) get(serviceName string) (http.Handler, error) {
|
func (m *InternalHandlers) get(serviceName string) (http.Handler, error) {
|
||||||
switch serviceName {
|
switch serviceName {
|
||||||
|
case "noop@internal":
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
|
||||||
|
rw.WriteHeader(http.StatusTeapot)
|
||||||
|
}), nil
|
||||||
|
|
||||||
case "api@internal":
|
case "api@internal":
|
||||||
if m.api == nil {
|
if m.api == nil {
|
||||||
return nil, errors.New("api is not enabled")
|
return nil, errors.New("api is not enabled")
|
||||||
|
|
|
@ -6,7 +6,10 @@ import (
|
||||||
|
|
||||||
// BuildConfiguration is a helper to create a configuration.
|
// BuildConfiguration is a helper to create a configuration.
|
||||||
func BuildConfiguration(dynamicConfigBuilders ...func(*dynamic.HTTPConfiguration)) *dynamic.HTTPConfiguration {
|
func BuildConfiguration(dynamicConfigBuilders ...func(*dynamic.HTTPConfiguration)) *dynamic.HTTPConfiguration {
|
||||||
conf := &dynamic.HTTPConfiguration{}
|
conf := &dynamic.HTTPConfiguration{
|
||||||
|
Models: map[string]*dynamic.Model{},
|
||||||
|
}
|
||||||
|
|
||||||
for _, build := range dynamicConfigBuilders {
|
for _, build := range dynamicConfigBuilders {
|
||||||
build(conf)
|
build(conf)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue